mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-31 20:09:01 +00:00
Auto merge of #142567 - lnicola:sync-from-ra, r=lnicola
Subtree update of `rust-analyzer` r? `@ghost`
This commit is contained in:
commit
01ccbcf4a8
131 changed files with 4777 additions and 3492 deletions
|
|
@ -18,6 +18,7 @@ extend-ignore-re = [
|
|||
"INOUT",
|
||||
"optin",
|
||||
"=Pn",
|
||||
"\\[[0-9A-F]{4},", # AstId hex hashes
|
||||
# ignore `// spellchecker:off` until `// spellchecker:on`
|
||||
"(?s)(#|//)\\s*spellchecker:off.*?\\n\\s*(#|//)\\s*spellchecker:on",
|
||||
]
|
||||
|
|
|
|||
567
Cargo.lock
generated
567
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
44
Cargo.toml
44
Cargo.toml
|
|
@ -87,11 +87,11 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
|
|||
vfs = { path = "./crates/vfs", version = "0.0.0" }
|
||||
edition = { path = "./crates/edition", version = "0.0.0" }
|
||||
|
||||
ra-ap-rustc_lexer = { version = "0.113", default-features = false }
|
||||
ra-ap-rustc_parse_format = { version = "0.113", default-features = false }
|
||||
ra-ap-rustc_index = { version = "0.113", default-features = false }
|
||||
ra-ap-rustc_abi = { version = "0.113", default-features = false }
|
||||
ra-ap-rustc_pattern_analysis = { version = "0.113", default-features = false }
|
||||
ra-ap-rustc_lexer = { version = "0.116", default-features = false }
|
||||
ra-ap-rustc_parse_format = { version = "0.116", default-features = false }
|
||||
ra-ap-rustc_index = { version = "0.116", default-features = false }
|
||||
ra-ap-rustc_abi = { version = "0.116", default-features = false }
|
||||
ra-ap-rustc_pattern_analysis = { version = "0.116", default-features = false }
|
||||
|
||||
# local crates that aren't published to crates.io. These should not have versions.
|
||||
|
||||
|
|
@ -101,24 +101,24 @@ la-arena = { version = "0.3.1" }
|
|||
lsp-server = { version = "0.7.8" }
|
||||
|
||||
# non-local crates
|
||||
anyhow = "1.0.97"
|
||||
anyhow = "1.0.98"
|
||||
arrayvec = "0.7.6"
|
||||
bitflags = "2.9.0"
|
||||
cargo_metadata = "0.19.2"
|
||||
camino = "1.1.9"
|
||||
chalk-solve = { version = "0.102.0", default-features = false }
|
||||
chalk-ir = "0.102.0"
|
||||
chalk-recursive = { version = "0.102.0", default-features = false }
|
||||
chalk-derive = "0.102.0"
|
||||
bitflags = "2.9.1"
|
||||
cargo_metadata = "0.20.0"
|
||||
camino = "1.1.10"
|
||||
chalk-solve = { version = "0.103.0", default-features = false }
|
||||
chalk-ir = "0.103.0"
|
||||
chalk-recursive = { version = "0.103.0", default-features = false }
|
||||
chalk-derive = "0.103.0"
|
||||
crossbeam-channel = "0.5.15"
|
||||
dissimilar = "1.0.10"
|
||||
dot = "0.1.4"
|
||||
either = "1.15.0"
|
||||
expect-test = "1.5.1"
|
||||
indexmap = { version = "2.8.0", features = ["serde"] }
|
||||
indexmap = { version = "2.9.0", features = ["serde"] }
|
||||
itertools = "0.14.0"
|
||||
libc = "0.2.171"
|
||||
libloading = "0.8.6"
|
||||
libc = "0.2.172"
|
||||
libloading = "0.8.8"
|
||||
memmap2 = "0.9.5"
|
||||
nohash-hasher = "0.2.0"
|
||||
oorandom = "11.1.5"
|
||||
|
|
@ -129,20 +129,22 @@ object = { version = "0.36.7", default-features = false, features = [
|
|||
"macho",
|
||||
"pe",
|
||||
] }
|
||||
process-wrap = { version = "8.2.0", features = ["std"] }
|
||||
process-wrap = { version = "8.2.1", features = ["std"] }
|
||||
pulldown-cmark-to-cmark = "10.0.4"
|
||||
pulldown-cmark = { version = "0.9.6", default-features = false }
|
||||
rayon = "1.10.0"
|
||||
rowan = "=0.15.15"
|
||||
salsa = { version = "0.22.0", default-features = false, features = ["rayon","salsa_unstable"] }
|
||||
# Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work
|
||||
# on impls without it
|
||||
salsa = { version = "0.22.0", default-features = true, features = ["rayon","salsa_unstable", "macros"] }
|
||||
salsa-macros = "0.22.0"
|
||||
semver = "1.0.26"
|
||||
serde = { version = "1.0.219" }
|
||||
serde_derive = { version = "1.0.219" }
|
||||
serde_json = "1.0.140"
|
||||
rustc-hash = "2.1.1"
|
||||
rustc-literal-escaper = "0.0.2"
|
||||
smallvec = { version = "1.14.0", features = [
|
||||
rustc-literal-escaper = "0.0.3"
|
||||
smallvec = { version = "1.15.1", features = [
|
||||
"const_new",
|
||||
"union",
|
||||
"const_generics",
|
||||
|
|
@ -166,7 +168,7 @@ xshell = "0.2.7"
|
|||
# We need to freeze the version of the crate, as the raw-api feature is considered unstable
|
||||
dashmap = { version = "=6.1.0", features = ["raw-api", "inline"] }
|
||||
# We need to freeze the version of the crate, as it needs to match with dashmap
|
||||
hashbrown = { version = "0.14.0", features = [
|
||||
hashbrown = { version = "0.14.*", features = [
|
||||
"inline-more",
|
||||
], default-features = false }
|
||||
|
||||
|
|
|
|||
|
|
@ -20,12 +20,10 @@ use span::Edition;
|
|||
use triomphe::Arc;
|
||||
use vfs::{AbsPathBuf, AnchoredPath, FileId, VfsPath, file_set::FileSet};
|
||||
|
||||
use crate::{CrateWorkspaceData, EditionedFileId, RootQueryDb};
|
||||
use crate::{CrateWorkspaceData, EditionedFileId, FxIndexSet, RootQueryDb};
|
||||
|
||||
pub type ProcMacroPaths = FxHashMap<CrateBuilderId, Result<(String, AbsPathBuf), String>>;
|
||||
|
||||
type FxIndexSet<T> = indexmap::IndexSet<T, FxBuildHasher>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct SourceRootId(pub u32);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ use syntax::{Parse, SyntaxError, ast};
|
|||
use triomphe::Arc;
|
||||
pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet};
|
||||
|
||||
pub type FxIndexSet<T> = indexmap::IndexSet<T, rustc_hash::FxBuildHasher>;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_intern_key {
|
||||
($id:ident, $loc:ident) => {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ rustc-hash.workspace = true
|
|||
tracing.workspace = true
|
||||
smallvec.workspace = true
|
||||
triomphe.workspace = true
|
||||
rustc_apfloat = "0.2.2"
|
||||
rustc_apfloat = "0.2.3"
|
||||
text-size.workspace = true
|
||||
salsa.workspace = true
|
||||
salsa-macros.workspace = true
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use intern::{Symbol, sym};
|
|||
use la_arena::{ArenaMap, Idx, RawIdx};
|
||||
use mbe::DelimiterKind;
|
||||
use rustc_abi::ReprOptions;
|
||||
use span::AstIdNode;
|
||||
use syntax::{
|
||||
AstPtr,
|
||||
ast::{self, HasAttrs},
|
||||
|
|
@ -22,10 +23,10 @@ use triomphe::Arc;
|
|||
use tt::iter::{TtElement, TtIter};
|
||||
|
||||
use crate::{
|
||||
AdtId, AttrDefId, GenericParamId, HasModule, ItemTreeLoc, LocalFieldId, Lookup, MacroId,
|
||||
AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId,
|
||||
VariantId,
|
||||
db::DefDatabase,
|
||||
item_tree::{AttrOwner, FieldParent, ItemTreeNode},
|
||||
item_tree::block_item_tree_query,
|
||||
lang_item::LangItem,
|
||||
nameres::{ModuleOrigin, ModuleSource},
|
||||
src::{HasChildSource, HasSource},
|
||||
|
|
@ -42,6 +43,15 @@ pub struct AttrsWithOwner {
|
|||
}
|
||||
|
||||
impl Attrs {
|
||||
pub fn new(
|
||||
db: &dyn DefDatabase,
|
||||
owner: &dyn ast::HasAttrs,
|
||||
span_map: SpanMapRef<'_>,
|
||||
cfg_options: &CfgOptions,
|
||||
) -> Self {
|
||||
Attrs(RawAttrs::new_expanded(db, owner, span_map, cfg_options))
|
||||
}
|
||||
|
||||
pub fn get(&self, id: AttrId) -> Option<&Attr> {
|
||||
(**self).iter().find(|attr| attr.id == id)
|
||||
}
|
||||
|
|
@ -94,44 +104,64 @@ impl Attrs {
|
|||
v: VariantId,
|
||||
) -> Arc<ArenaMap<LocalFieldId, Attrs>> {
|
||||
let _p = tracing::info_span!("fields_attrs_query").entered();
|
||||
// FIXME: There should be some proper form of mapping between item tree field ids and hir field ids
|
||||
let mut res = ArenaMap::default();
|
||||
let item_tree;
|
||||
let (parent, fields, krate) = match v {
|
||||
let (fields, file_id, krate) = match v {
|
||||
VariantId::EnumVariantId(it) => {
|
||||
let loc = it.lookup(db);
|
||||
let krate = loc.parent.lookup(db).container.krate;
|
||||
item_tree = loc.id.item_tree(db);
|
||||
let variant = &item_tree[loc.id.value];
|
||||
(FieldParent::EnumVariant(loc.id.value), &variant.fields, krate)
|
||||
let source = loc.source(db);
|
||||
(source.value.field_list(), source.file_id, krate)
|
||||
}
|
||||
VariantId::StructId(it) => {
|
||||
let loc = it.lookup(db);
|
||||
let krate = loc.container.krate;
|
||||
item_tree = loc.id.item_tree(db);
|
||||
let struct_ = &item_tree[loc.id.value];
|
||||
(FieldParent::Struct(loc.id.value), &struct_.fields, krate)
|
||||
let source = loc.source(db);
|
||||
(source.value.field_list(), source.file_id, krate)
|
||||
}
|
||||
VariantId::UnionId(it) => {
|
||||
let loc = it.lookup(db);
|
||||
let krate = loc.container.krate;
|
||||
item_tree = loc.id.item_tree(db);
|
||||
let union_ = &item_tree[loc.id.value];
|
||||
(FieldParent::Union(loc.id.value), &union_.fields, krate)
|
||||
let source = loc.source(db);
|
||||
(
|
||||
source.value.record_field_list().map(ast::FieldList::RecordFieldList),
|
||||
source.file_id,
|
||||
krate,
|
||||
)
|
||||
}
|
||||
};
|
||||
let Some(fields) = fields else {
|
||||
return Arc::new(res);
|
||||
};
|
||||
|
||||
let cfg_options = krate.cfg_options(db);
|
||||
let span_map = db.span_map(file_id);
|
||||
|
||||
let mut idx = 0;
|
||||
for (id, _field) in fields.iter().enumerate() {
|
||||
let attrs = item_tree.attrs(db, krate, AttrOwner::make_field_indexed(parent, id));
|
||||
if attrs.is_cfg_enabled(cfg_options) {
|
||||
res.insert(Idx::from_raw(RawIdx::from(idx)), attrs);
|
||||
idx += 1;
|
||||
match fields {
|
||||
ast::FieldList::RecordFieldList(fields) => {
|
||||
let mut idx = 0;
|
||||
for field in fields.fields() {
|
||||
let attrs =
|
||||
Attrs(RawAttrs::new_expanded(db, &field, span_map.as_ref(), cfg_options));
|
||||
if attrs.is_cfg_enabled(cfg_options).is_ok() {
|
||||
res.insert(Idx::from_raw(RawIdx::from(idx)), attrs);
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::FieldList::TupleFieldList(fields) => {
|
||||
let mut idx = 0;
|
||||
for field in fields.fields() {
|
||||
let attrs =
|
||||
Attrs(RawAttrs::new_expanded(db, &field, span_map.as_ref(), cfg_options));
|
||||
if attrs.is_cfg_enabled(cfg_options).is_ok() {
|
||||
res.insert(Idx::from_raw(RawIdx::from(idx)), attrs);
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.shrink_to_fit();
|
||||
Arc::new(res)
|
||||
}
|
||||
}
|
||||
|
|
@ -167,11 +197,10 @@ impl Attrs {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
|
||||
match self.cfg() {
|
||||
None => true,
|
||||
Some(cfg) => cfg_options.check(&cfg) != Some(false),
|
||||
}
|
||||
pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Result<(), CfgExpr> {
|
||||
self.cfgs().try_for_each(|cfg| {
|
||||
if cfg_options.check(&cfg) != Some(false) { Ok(()) } else { Err(cfg) }
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -488,61 +517,59 @@ impl AttrsWithOwner {
|
|||
pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
|
||||
let _p = tracing::info_span!("attrs_query").entered();
|
||||
// FIXME: this should use `Trace` to avoid duplication in `source_map` below
|
||||
let raw_attrs = match def {
|
||||
match def {
|
||||
AttrDefId::ModuleId(module) => {
|
||||
let def_map = module.def_map(db);
|
||||
let mod_data = &def_map[module.local_id];
|
||||
|
||||
match mod_data.origin {
|
||||
ModuleOrigin::File { definition, declaration_tree_id, .. } => {
|
||||
let raw_attrs = match mod_data.origin {
|
||||
ModuleOrigin::File { definition, declaration_tree_id, declaration, .. } => {
|
||||
let decl_attrs = declaration_tree_id
|
||||
.item_tree(db)
|
||||
.raw_attrs(AttrOwner::ModItem(declaration_tree_id.value.into()))
|
||||
.raw_attrs(declaration.upcast())
|
||||
.clone();
|
||||
let tree = db.file_item_tree(definition.into());
|
||||
let def_attrs = tree.raw_attrs(AttrOwner::TopLevel).clone();
|
||||
let def_attrs = tree.top_level_raw_attrs().clone();
|
||||
decl_attrs.merge(def_attrs)
|
||||
}
|
||||
ModuleOrigin::CrateRoot { definition } => {
|
||||
let tree = db.file_item_tree(definition.into());
|
||||
tree.raw_attrs(AttrOwner::TopLevel).clone()
|
||||
tree.top_level_raw_attrs().clone()
|
||||
}
|
||||
ModuleOrigin::Inline { definition_tree_id, definition } => {
|
||||
definition_tree_id.item_tree(db).raw_attrs(definition.upcast()).clone()
|
||||
}
|
||||
ModuleOrigin::Inline { definition_tree_id, .. } => definition_tree_id
|
||||
.item_tree(db)
|
||||
.raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into()))
|
||||
.clone(),
|
||||
ModuleOrigin::BlockExpr { id, .. } => {
|
||||
let tree = db.block_item_tree(id);
|
||||
tree.raw_attrs(AttrOwner::TopLevel).clone()
|
||||
let tree = block_item_tree_query(db, id);
|
||||
tree.top_level_raw_attrs().clone()
|
||||
}
|
||||
}
|
||||
};
|
||||
Attrs::expand_cfg_attr(db, module.krate, raw_attrs)
|
||||
}
|
||||
AttrDefId::FieldId(it) => {
|
||||
return db.fields_attrs(it.parent)[it.local_id].clone();
|
||||
}
|
||||
AttrDefId::EnumVariantId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AttrDefId::FieldId(it) => db.fields_attrs(it.parent)[it.local_id].clone(),
|
||||
AttrDefId::EnumVariantId(it) => attrs_from_ast_id_loc(db, it),
|
||||
AttrDefId::AdtId(it) => match it {
|
||||
AdtId::StructId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AdtId::EnumId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AdtId::UnionId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AdtId::StructId(it) => attrs_from_ast_id_loc(db, it),
|
||||
AdtId::EnumId(it) => attrs_from_ast_id_loc(db, it),
|
||||
AdtId::UnionId(it) => attrs_from_ast_id_loc(db, it),
|
||||
},
|
||||
AttrDefId::TraitId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AttrDefId::TraitAliasId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AttrDefId::TraitId(it) => attrs_from_ast_id_loc(db, it),
|
||||
AttrDefId::TraitAliasId(it) => attrs_from_ast_id_loc(db, it),
|
||||
AttrDefId::MacroId(it) => match it {
|
||||
MacroId::Macro2Id(it) => attrs_from_item_tree_loc(db, it),
|
||||
MacroId::MacroRulesId(it) => attrs_from_item_tree_loc(db, it),
|
||||
MacroId::ProcMacroId(it) => attrs_from_item_tree_loc(db, it),
|
||||
MacroId::Macro2Id(it) => attrs_from_ast_id_loc(db, it),
|
||||
MacroId::MacroRulesId(it) => attrs_from_ast_id_loc(db, it),
|
||||
MacroId::ProcMacroId(it) => attrs_from_ast_id_loc(db, it),
|
||||
},
|
||||
AttrDefId::ImplId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AttrDefId::ConstId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AttrDefId::StaticId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AttrDefId::FunctionId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AttrDefId::TypeAliasId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AttrDefId::ImplId(it) => attrs_from_ast_id_loc(db, it),
|
||||
AttrDefId::ConstId(it) => attrs_from_ast_id_loc(db, it),
|
||||
AttrDefId::StaticId(it) => attrs_from_ast_id_loc(db, it),
|
||||
AttrDefId::FunctionId(it) => attrs_from_ast_id_loc(db, it),
|
||||
AttrDefId::TypeAliasId(it) => attrs_from_ast_id_loc(db, it),
|
||||
AttrDefId::GenericParamId(it) => match it {
|
||||
GenericParamId::ConstParamId(it) => {
|
||||
let src = it.parent().child_source(db);
|
||||
// FIXME: We should be never getting `None` here.
|
||||
return Attrs(match src.value.get(it.local_id()) {
|
||||
Attrs(match src.value.get(it.local_id()) {
|
||||
Some(val) => RawAttrs::new_expanded(
|
||||
db,
|
||||
val,
|
||||
|
|
@ -550,12 +577,12 @@ impl AttrsWithOwner {
|
|||
def.krate(db).cfg_options(db),
|
||||
),
|
||||
None => RawAttrs::EMPTY,
|
||||
});
|
||||
})
|
||||
}
|
||||
GenericParamId::TypeParamId(it) => {
|
||||
let src = it.parent().child_source(db);
|
||||
// FIXME: We should be never getting `None` here.
|
||||
return Attrs(match src.value.get(it.local_id()) {
|
||||
Attrs(match src.value.get(it.local_id()) {
|
||||
Some(val) => RawAttrs::new_expanded(
|
||||
db,
|
||||
val,
|
||||
|
|
@ -563,12 +590,12 @@ impl AttrsWithOwner {
|
|||
def.krate(db).cfg_options(db),
|
||||
),
|
||||
None => RawAttrs::EMPTY,
|
||||
});
|
||||
})
|
||||
}
|
||||
GenericParamId::LifetimeParamId(it) => {
|
||||
let src = it.parent.child_source(db);
|
||||
// FIXME: We should be never getting `None` here.
|
||||
return Attrs(match src.value.get(it.local_id) {
|
||||
Attrs(match src.value.get(it.local_id) {
|
||||
Some(val) => RawAttrs::new_expanded(
|
||||
db,
|
||||
val,
|
||||
|
|
@ -576,16 +603,13 @@ impl AttrsWithOwner {
|
|||
def.krate(db).cfg_options(db),
|
||||
),
|
||||
None => RawAttrs::EMPTY,
|
||||
});
|
||||
})
|
||||
}
|
||||
},
|
||||
AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AttrDefId::ExternCrateId(it) => attrs_from_item_tree_loc(db, it),
|
||||
AttrDefId::UseId(it) => attrs_from_item_tree_loc(db, it),
|
||||
};
|
||||
|
||||
let attrs = raw_attrs.expand_cfg_attr(db, def.krate(db));
|
||||
Attrs(attrs)
|
||||
AttrDefId::ExternBlockId(it) => attrs_from_ast_id_loc(db, it),
|
||||
AttrDefId::ExternCrateId(it) => attrs_from_ast_id_loc(db, it),
|
||||
AttrDefId::UseId(it) => attrs_from_ast_id_loc(db, it),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap {
|
||||
|
|
@ -787,14 +811,15 @@ fn any_has_attrs<'db>(
|
|||
id.lookup(db).source(db).map(ast::AnyHasAttrs::new)
|
||||
}
|
||||
|
||||
fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>(
|
||||
fn attrs_from_ast_id_loc<'db, N: AstIdNode + HasAttrs>(
|
||||
db: &(dyn DefDatabase + 'db),
|
||||
lookup: impl Lookup<Database = dyn DefDatabase, Data = impl ItemTreeLoc<Id = N>>,
|
||||
) -> RawAttrs {
|
||||
let id = lookup.lookup(db).item_tree_id();
|
||||
let tree = id.item_tree(db);
|
||||
let attr_owner = N::attr_owner(id.value);
|
||||
tree.raw_attrs(attr_owner).clone()
|
||||
lookup: impl Lookup<Database = dyn DefDatabase, Data = impl AstIdLoc<Ast = N> + HasModule>,
|
||||
) -> Attrs {
|
||||
let loc = lookup.lookup(db);
|
||||
let source = loc.source(db);
|
||||
let span_map = db.span_map(source.file_id);
|
||||
let cfg_options = loc.krate(db).cfg_options(db);
|
||||
Attrs(RawAttrs::new_expanded(db, &source.value, span_map.as_ref(), cfg_options))
|
||||
}
|
||||
|
||||
pub(crate) fn fields_attrs_source_map(
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
//! Defines database & queries for name resolution.
|
||||
use base_db::{Crate, RootQueryDb, SourceDatabase};
|
||||
use either::Either;
|
||||
use hir_expand::{EditionedFileId, HirFileId, MacroCallId, MacroDefId, db::ExpandDatabase};
|
||||
use hir_expand::{
|
||||
EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind,
|
||||
db::ExpandDatabase,
|
||||
};
|
||||
use intern::sym;
|
||||
use la_arena::ArenaMap;
|
||||
use syntax::{AstPtr, ast};
|
||||
use thin_vec::ThinVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId,
|
||||
AssocItemId, AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId,
|
||||
EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId,
|
||||
FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId,
|
||||
MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId,
|
||||
FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander,
|
||||
MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId,
|
||||
StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId,
|
||||
TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
|
||||
attr::{Attrs, AttrsWithOwner},
|
||||
|
|
@ -21,17 +23,13 @@ use crate::{
|
|||
},
|
||||
hir::generics::GenericParams,
|
||||
import_map::ImportMap,
|
||||
item_tree::{AttrOwner, ItemTree},
|
||||
item_tree::{ItemTree, file_item_tree_query},
|
||||
lang_item::{self, LangItem},
|
||||
nameres::{
|
||||
assoc::{ImplItems, TraitItems},
|
||||
crate_def_map,
|
||||
diagnostics::DefDiagnostics,
|
||||
},
|
||||
nameres::{assoc::TraitItems, crate_def_map, diagnostics::DefDiagnostics},
|
||||
signatures::{
|
||||
ConstSignature, EnumSignature, EnumVariants, FunctionSignature, ImplSignature,
|
||||
InactiveEnumVariantCode, StaticSignature, StructSignature, TraitAliasSignature,
|
||||
TraitSignature, TypeAliasSignature, UnionSignature, VariantFields,
|
||||
ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature,
|
||||
StructSignature, TraitAliasSignature, TraitSignature, TypeAliasSignature, UnionSignature,
|
||||
VariantFields,
|
||||
},
|
||||
tt,
|
||||
visibility::{self, Visibility},
|
||||
|
|
@ -93,9 +91,6 @@ pub trait InternDatabase: RootQueryDb {
|
|||
#[salsa::interned]
|
||||
fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId;
|
||||
// // endregion: items
|
||||
|
||||
#[salsa::interned]
|
||||
fn intern_block(&self, loc: BlockLoc) -> BlockId;
|
||||
}
|
||||
|
||||
#[query_group::query_group]
|
||||
|
|
@ -105,11 +100,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
|
|||
fn expand_proc_attr_macros(&self) -> bool;
|
||||
|
||||
/// Computes an [`ItemTree`] for the given file or macro expansion.
|
||||
#[salsa::invoke(ItemTree::file_item_tree_query)]
|
||||
fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
|
||||
|
||||
#[salsa::invoke(ItemTree::block_item_tree_query)]
|
||||
fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
|
||||
#[salsa::invoke(file_item_tree_query)]
|
||||
#[salsa::transparent]
|
||||
fn file_item_tree(&self, file_id: HirFileId) -> &ItemTree;
|
||||
|
||||
/// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
|
||||
#[salsa::invoke(macro_def)]
|
||||
|
|
@ -123,24 +116,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
|
|||
id: VariantId,
|
||||
) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
#[salsa::tracked]
|
||||
fn enum_variants(&self, id: EnumId) -> Arc<EnumVariants> {
|
||||
self.enum_variants_with_diagnostics(id).0
|
||||
}
|
||||
|
||||
#[salsa::invoke(EnumVariants::enum_variants_query)]
|
||||
fn enum_variants_with_diagnostics(
|
||||
&self,
|
||||
id: EnumId,
|
||||
) -> (Arc<EnumVariants>, Option<Arc<ThinVec<InactiveEnumVariantCode>>>);
|
||||
|
||||
#[salsa::transparent]
|
||||
#[salsa::invoke(ImplItems::impl_items_query)]
|
||||
fn impl_items(&self, e: ImplId) -> Arc<ImplItems>;
|
||||
|
||||
#[salsa::invoke(ImplItems::impl_items_with_diagnostics_query)]
|
||||
fn impl_items_with_diagnostics(&self, e: ImplId) -> (Arc<ImplItems>, DefDiagnostics);
|
||||
|
||||
#[salsa::transparent]
|
||||
#[salsa::invoke(TraitItems::trait_items_query)]
|
||||
fn trait_items(&self, e: TraitId) -> Arc<TraitItems>;
|
||||
|
|
@ -323,16 +298,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
|
|||
#[salsa::invoke(visibility::field_visibilities_query)]
|
||||
fn field_visibilities(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Visibility>>;
|
||||
|
||||
// FIXME: unify function_visibility and const_visibility?
|
||||
|
||||
#[salsa::invoke(visibility::function_visibility_query)]
|
||||
fn function_visibility(&self, def: FunctionId) -> Visibility;
|
||||
|
||||
#[salsa::invoke(visibility::const_visibility_query)]
|
||||
fn const_visibility(&self, def: ConstId) -> Visibility;
|
||||
|
||||
#[salsa::invoke(visibility::type_alias_visibility_query)]
|
||||
fn type_alias_visibility(&self, def: TypeAliasId) -> Visibility;
|
||||
#[salsa::invoke(visibility::assoc_visibility_query)]
|
||||
fn assoc_visibility(&self, def: AssocItemId) -> Visibility;
|
||||
|
||||
// endregion:visibilities
|
||||
|
||||
|
|
@ -368,7 +335,7 @@ fn include_macro_invoc(
|
|||
fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool {
|
||||
let file = crate_id.data(db).root_file_id(db);
|
||||
let item_tree = db.file_item_tree(file.into());
|
||||
let attrs = item_tree.raw_attrs(AttrOwner::TopLevel);
|
||||
let attrs = item_tree.top_level_raw_attrs();
|
||||
for attr in &**attrs {
|
||||
match attr.path().as_ident() {
|
||||
Some(ident) if *ident == sym::no_std => return true,
|
||||
|
|
@ -399,10 +366,6 @@ fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool {
|
|||
}
|
||||
|
||||
fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
|
||||
use hir_expand::InFile;
|
||||
|
||||
use crate::{Lookup, MacroDefKind, MacroExpander};
|
||||
|
||||
let kind = |expander, file_id, m| {
|
||||
let in_file = InFile::new(file_id, m);
|
||||
match expander {
|
||||
|
|
@ -418,11 +381,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
|
|||
MacroId::Macro2Id(it) => {
|
||||
let loc: Macro2Loc = it.lookup(db);
|
||||
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let makro = &item_tree[loc.id.value];
|
||||
MacroDefId {
|
||||
krate: loc.container.krate,
|
||||
kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()),
|
||||
kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()),
|
||||
local_inner: false,
|
||||
allow_internal_unsafe: loc.allow_internal_unsafe,
|
||||
edition: loc.edition,
|
||||
|
|
@ -431,11 +392,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
|
|||
MacroId::MacroRulesId(it) => {
|
||||
let loc: MacroRulesLoc = it.lookup(db);
|
||||
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let makro = &item_tree[loc.id.value];
|
||||
MacroDefId {
|
||||
krate: loc.container.krate,
|
||||
kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()),
|
||||
kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()),
|
||||
local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER),
|
||||
allow_internal_unsafe: loc
|
||||
.flags
|
||||
|
|
@ -446,15 +405,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
|
|||
MacroId::ProcMacroId(it) => {
|
||||
let loc = it.lookup(db);
|
||||
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let makro = &item_tree[loc.id.value];
|
||||
MacroDefId {
|
||||
krate: loc.container.krate,
|
||||
kind: MacroDefKind::ProcMacro(
|
||||
InFile::new(loc.id.file_id(), makro.ast_id),
|
||||
loc.expander,
|
||||
loc.kind,
|
||||
),
|
||||
kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind),
|
||||
local_inner: false,
|
||||
allow_internal_unsafe: false,
|
||||
edition: loc.edition,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use base_db::Crate;
|
|||
use cfg::CfgOptions;
|
||||
use drop_bomb::DropBomb;
|
||||
use hir_expand::AstId;
|
||||
use hir_expand::span_map::SpanMapRef;
|
||||
use hir_expand::{
|
||||
ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId,
|
||||
eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap,
|
||||
|
|
@ -223,9 +224,15 @@ impl Expander {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn ast_id_map(&self) -> &AstIdMap {
|
||||
&self.ast_id_map
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn span_map(&self) -> SpanMapRef<'_> {
|
||||
self.span_map.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ mod path;
|
|||
|
||||
use std::mem;
|
||||
|
||||
use base_db::FxIndexSet;
|
||||
use cfg::CfgOptions;
|
||||
use either::Either;
|
||||
use hir_expand::{
|
||||
HirFileId, InFile, Lookup, MacroDefId,
|
||||
HirFileId, InFile, Intern, MacroDefId,
|
||||
mod_path::tool_path,
|
||||
name::{AsName, Name},
|
||||
span_map::SpanMapRef,
|
||||
};
|
||||
use intern::{Symbol, sym};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
|
@ -30,8 +32,8 @@ use triomphe::Arc;
|
|||
use tt::TextRange;
|
||||
|
||||
use crate::{
|
||||
AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, ItemTreeLoc,
|
||||
MacroId, ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro,
|
||||
AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId,
|
||||
ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro,
|
||||
builtin_type::BuiltinUint,
|
||||
db::DefDatabase,
|
||||
expr_store::{
|
||||
|
|
@ -65,8 +67,6 @@ use crate::{
|
|||
|
||||
pub use self::path::hir_segment_to_ast_segment;
|
||||
|
||||
type FxIndexSet<K> = indexmap::IndexSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
|
||||
|
||||
pub(super) fn lower_body(
|
||||
db: &dyn DefDatabase,
|
||||
owner: DefWithBodyId,
|
||||
|
|
@ -564,6 +564,11 @@ impl ExprCollector<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn span_map(&self) -> SpanMapRef<'_> {
|
||||
self.expander.span_map()
|
||||
}
|
||||
|
||||
pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId {
|
||||
// FIXME: Keyword check?
|
||||
let lifetime_ref = match &*lifetime.text() {
|
||||
|
|
@ -2141,26 +2146,10 @@ impl ExprCollector<'_> {
|
|||
block: ast::BlockExpr,
|
||||
mk_block: impl FnOnce(Option<BlockId>, Box<[Statement]>, Option<ExprId>) -> Expr,
|
||||
) -> ExprId {
|
||||
let block_has_items = {
|
||||
let statement_has_item = block.statements().any(|stmt| match stmt {
|
||||
ast::Stmt::Item(_) => true,
|
||||
// Macro calls can be both items and expressions. The syntax library always treats
|
||||
// them as expressions here, so we undo that.
|
||||
ast::Stmt::ExprStmt(es) => matches!(es.expr(), Some(ast::Expr::MacroExpr(_))),
|
||||
_ => false,
|
||||
});
|
||||
statement_has_item
|
||||
|| matches!(block.tail_expr(), Some(ast::Expr::MacroExpr(_)))
|
||||
|| (block.may_carry_attributes() && block.attrs().next().is_some())
|
||||
};
|
||||
|
||||
let block_id = if block_has_items {
|
||||
let file_local_id = self.expander.ast_id_map().ast_id(&block);
|
||||
let block_id = self.expander.ast_id_map().ast_id_for_block(&block).map(|file_local_id| {
|
||||
let ast_id = self.expander.in_file(file_local_id);
|
||||
Some(self.db.intern_block(BlockLoc { ast_id, module: self.module }))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
BlockLoc { ast_id, module: self.module }.intern(self.db)
|
||||
});
|
||||
|
||||
let (module, def_map) =
|
||||
match block_id.map(|block_id| (block_def_map(self.db, block_id), block_id)) {
|
||||
|
|
@ -2260,11 +2249,8 @@ impl ExprCollector<'_> {
|
|||
match resolved.take_values() {
|
||||
Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
|
||||
Some(ModuleDefId::EnumVariantId(variant))
|
||||
if {
|
||||
let loc = variant.lookup(self.db);
|
||||
let tree = loc.item_tree_id().item_tree(self.db);
|
||||
tree[loc.id.value].shape != FieldsShape::Record
|
||||
} =>
|
||||
// FIXME: This can cause a cycle if the user is writing invalid code
|
||||
if self.db.variant_fields(variant.into()).shape != FieldsShape::Record =>
|
||||
{
|
||||
(None, Pat::Path(name.into()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,10 @@ use std::{
|
|||
use hir_expand::{Lookup, mod_path::PathKind};
|
||||
use itertools::Itertools;
|
||||
use span::Edition;
|
||||
use syntax::ast::HasName;
|
||||
|
||||
use crate::{
|
||||
AdtId, DefWithBodyId, GenericDefId, ItemTreeLoc, TypeParamId, VariantId,
|
||||
AdtId, DefWithBodyId, GenericDefId, TypeParamId, VariantId,
|
||||
expr_store::path::{GenericArg, GenericArgs},
|
||||
hir::{
|
||||
Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement,
|
||||
|
|
@ -19,6 +20,7 @@ use crate::{
|
|||
},
|
||||
lang_item::LangItemTarget,
|
||||
signatures::{FnFlags, FunctionSignature, StructSignature},
|
||||
src::HasSource,
|
||||
type_ref::{ConstRef, LifetimeRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef},
|
||||
};
|
||||
use crate::{LifetimeParamId, signatures::StructFlags};
|
||||
|
|
@ -48,6 +50,17 @@ pub enum LineFormat {
|
|||
Indentation,
|
||||
}
|
||||
|
||||
fn item_name<Id, Loc>(db: &dyn DefDatabase, id: Id, default: &str) -> String
|
||||
where
|
||||
Id: Lookup<Database = dyn DefDatabase, Data = Loc>,
|
||||
Loc: HasSource,
|
||||
Loc::Value: ast::HasName,
|
||||
{
|
||||
let loc = id.lookup(db);
|
||||
let source = loc.source(db);
|
||||
source.value.name().map_or_else(|| default.to_owned(), |name| name.to_string())
|
||||
}
|
||||
|
||||
pub fn print_body_hir(
|
||||
db: &dyn DefDatabase,
|
||||
body: &Body,
|
||||
|
|
@ -55,31 +68,14 @@ pub fn print_body_hir(
|
|||
edition: Edition,
|
||||
) -> String {
|
||||
let header = match owner {
|
||||
DefWithBodyId::FunctionId(it) => {
|
||||
it.lookup(db).id.resolved(db, |it| format!("fn {}", it.name.display(db, edition)))
|
||||
}
|
||||
DefWithBodyId::StaticId(it) => it
|
||||
.lookup(db)
|
||||
.id
|
||||
.resolved(db, |it| format!("static {} = ", it.name.display(db, edition))),
|
||||
DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| {
|
||||
format!(
|
||||
"const {} = ",
|
||||
match &it.name {
|
||||
Some(name) => name.display(db, edition).to_string(),
|
||||
None => "_".to_owned(),
|
||||
}
|
||||
)
|
||||
}),
|
||||
DefWithBodyId::VariantId(it) => {
|
||||
let loc = it.lookup(db);
|
||||
let enum_loc = loc.parent.lookup(db);
|
||||
format!(
|
||||
"enum {}::{}",
|
||||
enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition),
|
||||
loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
|
||||
)
|
||||
}
|
||||
DefWithBodyId::FunctionId(it) => format!("fn {}", item_name(db, it, "<missing>")),
|
||||
DefWithBodyId::StaticId(it) => format!("static {} = ", item_name(db, it, "<missing>")),
|
||||
DefWithBodyId::ConstId(it) => format!("const {} = ", item_name(db, it, "_")),
|
||||
DefWithBodyId::VariantId(it) => format!(
|
||||
"enum {}::{}",
|
||||
item_name(db, it.lookup(db).parent, "<missing>"),
|
||||
item_name(db, it, "<missing>")
|
||||
),
|
||||
};
|
||||
|
||||
let mut p = Printer {
|
||||
|
|
@ -116,22 +112,13 @@ pub fn print_body_hir(
|
|||
|
||||
pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: Edition) -> String {
|
||||
let header = match owner {
|
||||
VariantId::StructId(it) => {
|
||||
it.lookup(db).id.resolved(db, |it| format!("struct {}", it.name.display(db, edition)))
|
||||
}
|
||||
VariantId::EnumVariantId(enum_variant_id) => {
|
||||
let loc = enum_variant_id.lookup(db);
|
||||
let enum_loc = loc.parent.lookup(db);
|
||||
format!(
|
||||
"enum {}::{}",
|
||||
enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition),
|
||||
loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
|
||||
)
|
||||
}
|
||||
VariantId::UnionId(union_id) => union_id
|
||||
.lookup(db)
|
||||
.id
|
||||
.resolved(db, |it| format!("union {}", it.name.display(db, edition))),
|
||||
VariantId::StructId(it) => format!("struct {}", item_name(db, it, "<missing>")),
|
||||
VariantId::EnumVariantId(it) => format!(
|
||||
"enum {}::{}",
|
||||
item_name(db, it.lookup(db).parent, "<missing>"),
|
||||
item_name(db, it, "<missing>")
|
||||
),
|
||||
VariantId::UnionId(it) => format!("union {}", item_name(db, it, "<missing>")),
|
||||
};
|
||||
|
||||
let fields = db.variant_fields(owner);
|
||||
|
|
@ -154,9 +141,11 @@ pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: E
|
|||
let FieldData { name, type_ref, visibility, is_unsafe } = data;
|
||||
match visibility {
|
||||
crate::item_tree::RawVisibility::Module(interned, _visibility_explicitness) => {
|
||||
w!(p, "{}", interned.display(db, p.edition))
|
||||
w!(p, "pub(in {})", interned.display(db, p.edition))
|
||||
}
|
||||
crate::item_tree::RawVisibility::Public => w!(p, "pub "),
|
||||
crate::item_tree::RawVisibility::PubCrate => w!(p, "pub(crate) "),
|
||||
crate::item_tree::RawVisibility::PubSelf(_) => w!(p, "pub(self) "),
|
||||
}
|
||||
if *is_unsafe {
|
||||
w!(p, "unsafe ");
|
||||
|
|
@ -1089,10 +1078,7 @@ impl Printer<'_> {
|
|||
w!(self, "builtin#lang(");
|
||||
macro_rules! write_name {
|
||||
($it:ident) => {{
|
||||
let loc = $it.lookup(self.db);
|
||||
let tree = loc.item_tree_id().item_tree(self.db);
|
||||
let name = &tree[loc.id.value].name;
|
||||
w!(self, "{}", name.display(self.db, self.edition));
|
||||
w!(self, "{}", item_name(self.db, $it, "<missing>"));
|
||||
}};
|
||||
}
|
||||
match *it {
|
||||
|
|
|
|||
|
|
@ -189,8 +189,8 @@ fn f() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
BlockId(3c01) in BlockRelativeModuleId { block: Some(BlockId(3c00)), local_id: Idx::<ModuleData>(1) }
|
||||
BlockId(3c00) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
|
||||
BlockIdLt { [salsa id]: Id(3c01) } in BlockRelativeModuleId { block: Some(BlockIdLt { [salsa id]: Id(3c00) }), local_id: Idx::<ModuleData>(1) }
|
||||
BlockIdLt { [salsa id]: Id(3c00) } in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
|
||||
crate scope
|
||||
"#]],
|
||||
);
|
||||
|
|
@ -397,7 +397,6 @@ fn main() {
|
|||
fn underscore_import() {
|
||||
// This used to panic, because the default (private) visibility inside block expressions would
|
||||
// point into the containing `DefMap`, which visibilities should never be able to do.
|
||||
cov_mark::check!(adjust_vis_in_block_def_map);
|
||||
check_at(
|
||||
r#"
|
||||
mod m {
|
||||
|
|
@ -457,7 +456,6 @@ fn foo() {
|
|||
#[test]
|
||||
fn is_visible_from_same_def_map() {
|
||||
// Regression test for https://github.com/rust-lang/rust-analyzer/issues/9481
|
||||
cov_mark::check!(is_visible_from_same_block_def_map);
|
||||
check_at(
|
||||
r#"
|
||||
fn outer() {
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt
|
|||
let loc = variant.lookup(ctx.db);
|
||||
if let Some(mut path) = find_path_inner(ctx, ItemInNs::Types(loc.parent.into()), max_len) {
|
||||
path.push_segment(
|
||||
ctx.db.enum_variants(loc.parent).variants[loc.index as usize].1.clone(),
|
||||
loc.parent.enum_variants(ctx.db).variants[loc.index as usize].1.clone(),
|
||||
);
|
||||
return Some(path);
|
||||
}
|
||||
|
|
@ -615,6 +615,7 @@ fn find_local_import_locations(
|
|||
cov_mark::hit!(discount_private_imports);
|
||||
false
|
||||
}
|
||||
Visibility::PubCrate(_) => true,
|
||||
Visibility::Public => true,
|
||||
};
|
||||
|
||||
|
|
@ -1286,7 +1287,6 @@ $0
|
|||
|
||||
#[test]
|
||||
fn explicit_private_imports_crate() {
|
||||
cov_mark::check!(explicit_private_imports);
|
||||
check_found_path(
|
||||
r#"
|
||||
//- /main.rs
|
||||
|
|
|
|||
|
|
@ -13,13 +13,14 @@ use smallvec::{SmallVec, smallvec};
|
|||
use span::Edition;
|
||||
use stdx::format_to;
|
||||
use syntax::ast;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::{
|
||||
AdtId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap, HasModule, ImplId,
|
||||
LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
|
||||
db::DefDatabase,
|
||||
per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem},
|
||||
visibility::{Visibility, VisibilityExplicitness},
|
||||
visibility::Visibility,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
|
@ -155,22 +156,21 @@ pub struct ItemScope {
|
|||
|
||||
/// The defs declared in this scope. Each def has a single scope where it is
|
||||
/// declared.
|
||||
declarations: Vec<ModuleDefId>,
|
||||
declarations: ThinVec<ModuleDefId>,
|
||||
|
||||
impls: Vec<ImplId>,
|
||||
#[allow(clippy::box_collection)]
|
||||
extern_blocks: Option<Box<Vec<ExternBlockId>>>,
|
||||
unnamed_consts: Vec<ConstId>,
|
||||
impls: ThinVec<ImplId>,
|
||||
extern_blocks: ThinVec<ExternBlockId>,
|
||||
unnamed_consts: ThinVec<ConstId>,
|
||||
/// Traits imported via `use Trait as _;`.
|
||||
unnamed_trait_imports: FxHashMap<TraitId, Item<()>>,
|
||||
unnamed_trait_imports: ThinVec<(TraitId, Item<()>)>,
|
||||
|
||||
// the resolutions of the imports of this scope
|
||||
use_imports_types: FxHashMap<ImportOrExternCrate, ImportOrDef>,
|
||||
use_imports_values: FxHashMap<ImportOrGlob, ImportOrDef>,
|
||||
use_imports_macros: FxHashMap<ImportOrExternCrate, ImportOrDef>,
|
||||
|
||||
use_decls: Vec<UseId>,
|
||||
extern_crate_decls: Vec<ExternCrateId>,
|
||||
use_decls: ThinVec<UseId>,
|
||||
extern_crate_decls: ThinVec<ExternCrateId>,
|
||||
/// Macros visible in current module in legacy textual scope
|
||||
///
|
||||
/// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
|
||||
|
|
@ -183,7 +183,7 @@ pub struct ItemScope {
|
|||
/// Module scoped macros will be inserted into `items` instead of here.
|
||||
// FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
|
||||
// be all resolved to the last one defined if shadowing happens.
|
||||
legacy_macros: FxHashMap<Name, SmallVec<[MacroId; 1]>>,
|
||||
legacy_macros: FxHashMap<Name, SmallVec<[MacroId; 2]>>,
|
||||
/// The attribute macro invocations in this scope.
|
||||
attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
|
||||
/// The macro invocations in this scope.
|
||||
|
|
@ -198,7 +198,7 @@ struct DeriveMacroInvocation {
|
|||
attr_id: AttrId,
|
||||
/// The `#[derive]` call
|
||||
attr_call_id: MacroCallId,
|
||||
derive_call_ids: SmallVec<[Option<MacroCallId>; 1]>,
|
||||
derive_call_ids: SmallVec<[Option<MacroCallId>; 4]>,
|
||||
}
|
||||
|
||||
pub(crate) static BUILTIN_SCOPE: LazyLock<FxIndexMap<Name, PerNs>> = LazyLock::new(|| {
|
||||
|
|
@ -322,7 +322,7 @@ impl ItemScope {
|
|||
}
|
||||
|
||||
pub fn extern_blocks(&self) -> impl Iterator<Item = ExternBlockId> + '_ {
|
||||
self.extern_blocks.iter().flat_map(|it| it.iter()).copied()
|
||||
self.extern_blocks.iter().copied()
|
||||
}
|
||||
|
||||
pub fn use_decls(&self) -> impl ExactSizeIterator<Item = UseId> + '_ {
|
||||
|
|
@ -435,7 +435,7 @@ impl ItemScope {
|
|||
ModuleDefId::TraitId(t) => Some(t),
|
||||
_ => None,
|
||||
})
|
||||
.chain(self.unnamed_trait_imports.keys().copied())
|
||||
.chain(self.unnamed_trait_imports.iter().map(|&(t, _)| t))
|
||||
}
|
||||
|
||||
pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
|
||||
|
|
@ -476,7 +476,7 @@ impl ItemScope {
|
|||
}
|
||||
|
||||
pub(crate) fn define_extern_block(&mut self, extern_block: ExternBlockId) {
|
||||
self.extern_blocks.get_or_insert_default().push(extern_block);
|
||||
self.extern_blocks.push(extern_block);
|
||||
}
|
||||
|
||||
pub(crate) fn define_extern_crate_decl(&mut self, extern_crate: ExternCrateId) {
|
||||
|
|
@ -564,7 +564,7 @@ impl ItemScope {
|
|||
|
||||
// FIXME: This is only used in collection, we should move the relevant parts of it out of ItemScope
|
||||
pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
|
||||
self.unnamed_trait_imports.get(&tr).map(|trait_| trait_.vis)
|
||||
self.unnamed_trait_imports.iter().find(|&&(t, _)| t == tr).map(|(_, trait_)| trait_.vis)
|
||||
}
|
||||
|
||||
pub(crate) fn push_unnamed_trait(
|
||||
|
|
@ -573,7 +573,7 @@ impl ItemScope {
|
|||
vis: Visibility,
|
||||
import: Option<ImportId>,
|
||||
) {
|
||||
self.unnamed_trait_imports.insert(tr, Item { def: (), vis, import });
|
||||
self.unnamed_trait_imports.push((tr, Item { def: (), vis, import }));
|
||||
}
|
||||
|
||||
pub(crate) fn push_res_with_import(
|
||||
|
|
@ -720,33 +720,19 @@ impl ItemScope {
|
|||
}
|
||||
|
||||
/// Marks everything that is not a procedural macro as private to `this_module`.
|
||||
pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
|
||||
pub(crate) fn censor_non_proc_macros(&mut self, krate: Crate) {
|
||||
self.types
|
||||
.values_mut()
|
||||
.map(|def| &mut def.vis)
|
||||
.chain(self.values.values_mut().map(|def| &mut def.vis))
|
||||
.chain(self.unnamed_trait_imports.values_mut().map(|def| &mut def.vis))
|
||||
.for_each(|vis| match vis {
|
||||
&mut Visibility::Module(_, visibility_explicitness) => {
|
||||
*vis = Visibility::Module(this_module, visibility_explicitness)
|
||||
}
|
||||
Visibility::Public => {
|
||||
*vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
|
||||
}
|
||||
});
|
||||
.chain(self.unnamed_trait_imports.iter_mut().map(|(_, def)| &mut def.vis))
|
||||
.for_each(|vis| *vis = Visibility::PubCrate(krate));
|
||||
|
||||
for mac in self.macros.values_mut() {
|
||||
if matches!(mac.def, MacroId::ProcMacroId(_) if mac.import.is_none()) {
|
||||
continue;
|
||||
}
|
||||
match mac.vis {
|
||||
Visibility::Module(_, visibility_explicitness) => {
|
||||
mac.vis = Visibility::Module(this_module, visibility_explicitness)
|
||||
}
|
||||
Visibility::Public => {
|
||||
mac.vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
|
||||
}
|
||||
}
|
||||
mac.vis = Visibility::PubCrate(krate)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -817,9 +803,7 @@ impl ItemScope {
|
|||
macro_invocations,
|
||||
extern_blocks,
|
||||
} = self;
|
||||
if let Some(it) = extern_blocks {
|
||||
it.shrink_to_fit();
|
||||
}
|
||||
extern_blocks.shrink_to_fit();
|
||||
types.shrink_to_fit();
|
||||
values.shrink_to_fit();
|
||||
macros.shrink_to_fit();
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,42 +2,40 @@
|
|||
|
||||
use std::{cell::OnceCell, collections::hash_map::Entry};
|
||||
|
||||
use base_db::FxIndexSet;
|
||||
use hir_expand::{
|
||||
HirFileId,
|
||||
mod_path::PathKind,
|
||||
name::AsName,
|
||||
span_map::{SpanMap, SpanMapRef},
|
||||
};
|
||||
use intern::{Symbol, sym};
|
||||
use la_arena::Arena;
|
||||
use span::{AstIdMap, SyntaxContext};
|
||||
use span::{AstIdMap, FileAstId, SyntaxContext};
|
||||
use syntax::{
|
||||
AstNode,
|
||||
ast::{self, HasModuleItem, HasName, IsString},
|
||||
ast::{self, HasModuleItem, HasName},
|
||||
};
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase,
|
||||
item_tree::{
|
||||
AssocItem, AttrOwner, Const, Enum, ExternBlock, ExternCrate, Field, FieldParent,
|
||||
FieldsShape, FileItemTreeId, Function, Idx, Impl, ImportAlias, Interned, ItemTree,
|
||||
ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, ModPath, Name, Range,
|
||||
RawAttrs, RawIdx, RawVisibility, RawVisibilityId, Static, Struct, StructKind, Trait,
|
||||
TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, Variant, VisibilityExplicitness,
|
||||
BigModItem, Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl,
|
||||
ImportAlias, Interned, ItemTree, ItemTreeAstId, Macro2, MacroCall, MacroRules, Mod,
|
||||
ModItemId, ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, SmallModItem,
|
||||
Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
|
||||
VisibilityExplicitness,
|
||||
},
|
||||
};
|
||||
|
||||
fn id<N>(index: Idx<N>) -> FileItemTreeId<N> {
|
||||
FileItemTreeId(index)
|
||||
}
|
||||
|
||||
pub(super) struct Ctx<'a> {
|
||||
db: &'a dyn DefDatabase,
|
||||
tree: ItemTree,
|
||||
source_ast_id_map: Arc<AstIdMap>,
|
||||
span_map: OnceCell<SpanMap>,
|
||||
file: HirFileId,
|
||||
top_level: Vec<ModItemId>,
|
||||
visibilities: FxIndexSet<RawVisibility>,
|
||||
}
|
||||
|
||||
impl<'a> Ctx<'a> {
|
||||
|
|
@ -48,6 +46,8 @@ impl<'a> Ctx<'a> {
|
|||
source_ast_id_map: db.ast_id_map(file),
|
||||
file,
|
||||
span_map: OnceCell::new(),
|
||||
visibilities: FxIndexSet::default(),
|
||||
top_level: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,13 +56,14 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
|
||||
pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
|
||||
self.tree.top_level =
|
||||
item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
|
||||
self.top_level = item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
|
||||
self.tree.vis.arena = self.visibilities.into_iter().collect();
|
||||
self.tree.top_level = self.top_level.into_boxed_slice();
|
||||
self.tree
|
||||
}
|
||||
|
||||
pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree {
|
||||
self.tree.top_level = stmts
|
||||
self.top_level = stmts
|
||||
.statements()
|
||||
.filter_map(|stmt| {
|
||||
match stmt {
|
||||
|
|
@ -86,17 +87,19 @@ impl<'a> Ctx<'a> {
|
|||
if let Some(call) = tail_macro.macro_call() {
|
||||
cov_mark::hit!(macro_stmt_with_trailing_macro_expr);
|
||||
if let Some(mod_item) = self.lower_mod_item(&call.into()) {
|
||||
self.tree.top_level.push(mod_item);
|
||||
self.top_level.push(mod_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.tree.vis.arena = self.visibilities.into_iter().collect();
|
||||
self.tree.top_level = self.top_level.into_boxed_slice();
|
||||
self.tree
|
||||
}
|
||||
|
||||
pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
|
||||
self.tree.attrs.insert(AttrOwner::TopLevel, RawAttrs::new(self.db, block, self.span_map()));
|
||||
self.tree.top_level = block
|
||||
self.tree.top_attrs = RawAttrs::new(self.db, block, self.span_map());
|
||||
self.top_level = block
|
||||
.statements()
|
||||
.filter_map(|stmt| match stmt {
|
||||
ast::Stmt::Item(item) => self.lower_mod_item(&item),
|
||||
|
|
@ -112,20 +115,17 @@ impl<'a> Ctx<'a> {
|
|||
if let Some(ast::Expr::MacroExpr(expr)) = block.tail_expr() {
|
||||
if let Some(call) = expr.macro_call() {
|
||||
if let Some(mod_item) = self.lower_mod_item(&call.into()) {
|
||||
self.tree.top_level.push(mod_item);
|
||||
self.top_level.push(mod_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.tree.vis.arena = self.visibilities.into_iter().collect();
|
||||
self.tree.top_level = self.top_level.into_boxed_slice();
|
||||
self.tree
|
||||
}
|
||||
|
||||
fn data(&mut self) -> &mut ItemTreeData {
|
||||
self.tree.data_mut()
|
||||
}
|
||||
|
||||
fn lower_mod_item(&mut self, item: &ast::Item) -> Option<ModItem> {
|
||||
let mod_item: ModItem = match item {
|
||||
fn lower_mod_item(&mut self, item: &ast::Item) -> Option<ModItemId> {
|
||||
let mod_item: ModItemId = match item {
|
||||
ast::Item::Struct(ast) => self.lower_struct(ast)?.into(),
|
||||
ast::Item::Union(ast) => self.lower_union(ast)?.into(),
|
||||
ast::Item::Enum(ast) => self.lower_enum(ast)?.into(),
|
||||
|
|
@ -145,12 +145,12 @@ impl<'a> Ctx<'a> {
|
|||
ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(),
|
||||
};
|
||||
let attrs = RawAttrs::new(self.db, item, self.span_map());
|
||||
self.add_attrs(mod_item.into(), attrs);
|
||||
self.add_attrs(mod_item.ast_id(), attrs);
|
||||
|
||||
Some(mod_item)
|
||||
}
|
||||
|
||||
fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
|
||||
fn add_attrs(&mut self, item: FileAstId<ast::Item>, attrs: RawAttrs) {
|
||||
if !attrs.is_empty() {
|
||||
match self.tree.attrs.entry(item) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
|
|
@ -163,208 +163,78 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_assoc_item(&mut self, item_node: &ast::AssocItem) -> Option<AssocItem> {
|
||||
let item: AssocItem = match item_node {
|
||||
ast::AssocItem::Fn(ast) => self.lower_function(ast).map(Into::into),
|
||||
ast::AssocItem::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into),
|
||||
ast::AssocItem::Const(ast) => Some(self.lower_const(ast).into()),
|
||||
ast::AssocItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
|
||||
}?;
|
||||
let attrs = RawAttrs::new(self.db, item_node, self.span_map());
|
||||
self.add_attrs(
|
||||
match item {
|
||||
AssocItem::Function(it) => AttrOwner::ModItem(ModItem::Function(it)),
|
||||
AssocItem::TypeAlias(it) => AttrOwner::ModItem(ModItem::TypeAlias(it)),
|
||||
AssocItem::Const(it) => AttrOwner::ModItem(ModItem::Const(it)),
|
||||
AssocItem::MacroCall(it) => AttrOwner::ModItem(ModItem::MacroCall(it)),
|
||||
},
|
||||
attrs,
|
||||
);
|
||||
Some(item)
|
||||
}
|
||||
|
||||
fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
|
||||
fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<ItemTreeAstId<Struct>> {
|
||||
let visibility = self.lower_visibility(strukt);
|
||||
let name = strukt.name()?.as_name();
|
||||
let ast_id = self.source_ast_id_map.ast_id(strukt);
|
||||
let (fields, kind, attrs) = self.lower_fields(&strukt.kind());
|
||||
let res = Struct { name, visibility, fields, shape: kind, ast_id };
|
||||
let id = id(self.data().structs.alloc(res));
|
||||
let shape = adt_shape(strukt.kind());
|
||||
let res = Struct { name, visibility, shape };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Struct(res));
|
||||
|
||||
for (idx, attr) in attrs {
|
||||
self.add_attrs(
|
||||
AttrOwner::Field(
|
||||
FieldParent::Struct(id),
|
||||
Idx::from_raw(RawIdx::from_u32(idx as u32)),
|
||||
),
|
||||
attr,
|
||||
);
|
||||
}
|
||||
Some(id)
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_fields(
|
||||
&mut self,
|
||||
strukt_kind: &ast::StructKind,
|
||||
) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
|
||||
match strukt_kind {
|
||||
ast::StructKind::Record(it) => {
|
||||
let mut fields = vec![];
|
||||
let mut attrs = vec![];
|
||||
|
||||
for (i, field) in it.fields().enumerate() {
|
||||
let data = self.lower_record_field(&field);
|
||||
fields.push(data);
|
||||
let attr = RawAttrs::new(self.db, &field, self.span_map());
|
||||
if !attr.is_empty() {
|
||||
attrs.push((i, attr))
|
||||
}
|
||||
}
|
||||
(fields.into(), FieldsShape::Record, attrs)
|
||||
}
|
||||
ast::StructKind::Tuple(it) => {
|
||||
let mut fields = vec![];
|
||||
let mut attrs = vec![];
|
||||
|
||||
for (i, field) in it.fields().enumerate() {
|
||||
let data = self.lower_tuple_field(i, &field);
|
||||
fields.push(data);
|
||||
let attr = RawAttrs::new(self.db, &field, self.span_map());
|
||||
if !attr.is_empty() {
|
||||
attrs.push((i, attr))
|
||||
}
|
||||
}
|
||||
(fields.into(), FieldsShape::Tuple, attrs)
|
||||
}
|
||||
ast::StructKind::Unit => (Box::default(), FieldsShape::Unit, Vec::default()),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_record_field(&mut self, field: &ast::RecordField) -> Field {
|
||||
let name = match field.name() {
|
||||
Some(name) => name.as_name(),
|
||||
None => Name::missing(),
|
||||
};
|
||||
let visibility = self.lower_visibility(field);
|
||||
|
||||
Field { name, visibility, is_unsafe: field.unsafe_token().is_some() }
|
||||
}
|
||||
|
||||
fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
|
||||
let name = Name::new_tuple_field(idx);
|
||||
let visibility = self.lower_visibility(field);
|
||||
Field { name, visibility, is_unsafe: false }
|
||||
}
|
||||
|
||||
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
|
||||
fn lower_union(&mut self, union: &ast::Union) -> Option<ItemTreeAstId<Union>> {
|
||||
let visibility = self.lower_visibility(union);
|
||||
let name = union.name()?.as_name();
|
||||
let ast_id = self.source_ast_id_map.ast_id(union);
|
||||
let (fields, _, attrs) = match union.record_field_list() {
|
||||
Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
|
||||
None => (Box::default(), FieldsShape::Record, Vec::default()),
|
||||
};
|
||||
let res = Union { name, visibility, fields, ast_id };
|
||||
let id = id(self.data().unions.alloc(res));
|
||||
for (idx, attr) in attrs {
|
||||
self.add_attrs(
|
||||
AttrOwner::Field(
|
||||
FieldParent::Union(id),
|
||||
Idx::from_raw(RawIdx::from_u32(idx as u32)),
|
||||
),
|
||||
attr,
|
||||
);
|
||||
}
|
||||
Some(id)
|
||||
let res = Union { name, visibility };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Union(res));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> {
|
||||
fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<ItemTreeAstId<Enum>> {
|
||||
let visibility = self.lower_visibility(enum_);
|
||||
let name = enum_.name()?.as_name();
|
||||
let ast_id = self.source_ast_id_map.ast_id(enum_);
|
||||
let variants = match &enum_.variant_list() {
|
||||
Some(variant_list) => self.lower_variants(variant_list),
|
||||
None => {
|
||||
FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
|
||||
}
|
||||
};
|
||||
let res = Enum { name, visibility, variants, ast_id };
|
||||
let id = id(self.data().enums.alloc(res));
|
||||
Some(id)
|
||||
let res = Enum { name, visibility };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Enum(res));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_variants(&mut self, variants: &ast::VariantList) -> Range<FileItemTreeId<Variant>> {
|
||||
let start = self.next_variant_idx();
|
||||
for variant in variants.variants() {
|
||||
let idx = self.lower_variant(&variant);
|
||||
self.add_attrs(id(idx).into(), RawAttrs::new(self.db, &variant, self.span_map()));
|
||||
}
|
||||
let end = self.next_variant_idx();
|
||||
FileItemTreeId(start)..FileItemTreeId(end)
|
||||
}
|
||||
|
||||
fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> {
|
||||
let name = match variant.name() {
|
||||
Some(name) => name.as_name(),
|
||||
None => Name::missing(),
|
||||
};
|
||||
let (fields, kind, attrs) = self.lower_fields(&variant.kind());
|
||||
let ast_id = self.source_ast_id_map.ast_id(variant);
|
||||
let res = Variant { name, fields, shape: kind, ast_id };
|
||||
let id = self.data().variants.alloc(res);
|
||||
for (idx, attr) in attrs {
|
||||
self.add_attrs(
|
||||
AttrOwner::Field(
|
||||
FieldParent::EnumVariant(FileItemTreeId(id)),
|
||||
Idx::from_raw(RawIdx::from_u32(idx as u32)),
|
||||
),
|
||||
attr,
|
||||
);
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
|
||||
fn lower_function(&mut self, func: &ast::Fn) -> Option<ItemTreeAstId<Function>> {
|
||||
let visibility = self.lower_visibility(func);
|
||||
let name = func.name()?.as_name();
|
||||
|
||||
let ast_id = self.source_ast_id_map.ast_id(func);
|
||||
|
||||
let res = Function { name, visibility, ast_id };
|
||||
let res = Function { name, visibility };
|
||||
|
||||
let id = id(self.data().functions.alloc(res));
|
||||
Some(id)
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Function(res));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_type_alias(
|
||||
&mut self,
|
||||
type_alias: &ast::TypeAlias,
|
||||
) -> Option<FileItemTreeId<TypeAlias>> {
|
||||
) -> Option<ItemTreeAstId<TypeAlias>> {
|
||||
let name = type_alias.name()?.as_name();
|
||||
let visibility = self.lower_visibility(type_alias);
|
||||
let ast_id = self.source_ast_id_map.ast_id(type_alias);
|
||||
let res = TypeAlias { name, visibility, ast_id };
|
||||
let id = id(self.data().type_aliases.alloc(res));
|
||||
Some(id)
|
||||
let res = TypeAlias { name, visibility };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TypeAlias(res));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
|
||||
fn lower_static(&mut self, static_: &ast::Static) -> Option<ItemTreeAstId<Static>> {
|
||||
let name = static_.name()?.as_name();
|
||||
let visibility = self.lower_visibility(static_);
|
||||
let ast_id = self.source_ast_id_map.ast_id(static_);
|
||||
let res = Static { name, visibility, ast_id };
|
||||
Some(id(self.data().statics.alloc(res)))
|
||||
let res = Static { name, visibility };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Static(res));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
|
||||
fn lower_const(&mut self, konst: &ast::Const) -> ItemTreeAstId<Const> {
|
||||
let name = konst.name().map(|it| it.as_name());
|
||||
let visibility = self.lower_visibility(konst);
|
||||
let ast_id = self.source_ast_id_map.ast_id(konst);
|
||||
let res = Const { name, visibility, ast_id };
|
||||
id(self.data().consts.alloc(res))
|
||||
let res = Const { name, visibility };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Const(res));
|
||||
ast_id
|
||||
}
|
||||
|
||||
fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> {
|
||||
fn lower_module(&mut self, module: &ast::Module) -> Option<ItemTreeAstId<Mod>> {
|
||||
let name = module.name()?.as_name();
|
||||
let visibility = self.lower_visibility(module);
|
||||
let kind = if module.semicolon_token().is_some() {
|
||||
|
|
@ -381,70 +251,59 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
};
|
||||
let ast_id = self.source_ast_id_map.ast_id(module);
|
||||
let res = Mod { name, visibility, kind, ast_id };
|
||||
Some(id(self.data().mods.alloc(res)))
|
||||
let res = Mod { name, visibility, kind };
|
||||
self.tree.big_data.insert(ast_id.upcast(), BigModItem::Mod(res));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait>> {
|
||||
fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<ItemTreeAstId<Trait>> {
|
||||
let name = trait_def.name()?.as_name();
|
||||
let visibility = self.lower_visibility(trait_def);
|
||||
let ast_id = self.source_ast_id_map.ast_id(trait_def);
|
||||
|
||||
let items = trait_def
|
||||
.assoc_item_list()
|
||||
.into_iter()
|
||||
.flat_map(|list| list.assoc_items())
|
||||
.filter_map(|item_node| self.lower_assoc_item(&item_node))
|
||||
.collect();
|
||||
|
||||
let def = Trait { name, visibility, items, ast_id };
|
||||
let id = id(self.data().traits.alloc(def));
|
||||
Some(id)
|
||||
let def = Trait { name, visibility };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Trait(def));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_trait_alias(
|
||||
&mut self,
|
||||
trait_alias_def: &ast::TraitAlias,
|
||||
) -> Option<FileItemTreeId<TraitAlias>> {
|
||||
) -> Option<ItemTreeAstId<TraitAlias>> {
|
||||
let name = trait_alias_def.name()?.as_name();
|
||||
let visibility = self.lower_visibility(trait_alias_def);
|
||||
let ast_id = self.source_ast_id_map.ast_id(trait_alias_def);
|
||||
|
||||
let alias = TraitAlias { name, visibility, ast_id };
|
||||
let id = id(self.data().trait_aliases.alloc(alias));
|
||||
Some(id)
|
||||
let alias = TraitAlias { name, visibility };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TraitAlias(alias));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> {
|
||||
fn lower_impl(&mut self, impl_def: &ast::Impl) -> ItemTreeAstId<Impl> {
|
||||
let ast_id = self.source_ast_id_map.ast_id(impl_def);
|
||||
// We cannot use `assoc_items()` here as that does not include macro calls.
|
||||
let items = impl_def
|
||||
.assoc_item_list()
|
||||
.into_iter()
|
||||
.flat_map(|it| it.assoc_items())
|
||||
.filter_map(|item| self.lower_assoc_item(&item))
|
||||
.collect();
|
||||
// Note that trait impls don't get implicit `Self` unlike traits, because here they are a
|
||||
// type alias rather than a type parameter, so this is handled by the resolver.
|
||||
let res = Impl { items, ast_id };
|
||||
id(self.data().impls.alloc(res))
|
||||
let res = Impl {};
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Impl(res));
|
||||
ast_id
|
||||
}
|
||||
|
||||
fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
|
||||
fn lower_use(&mut self, use_item: &ast::Use) -> Option<ItemTreeAstId<Use>> {
|
||||
let visibility = self.lower_visibility(use_item);
|
||||
let ast_id = self.source_ast_id_map.ast_id(use_item);
|
||||
let (use_tree, _) = lower_use_tree(self.db, use_item.use_tree()?, &mut |range| {
|
||||
self.span_map().span_for_range(range).ctx
|
||||
})?;
|
||||
|
||||
let res = Use { visibility, ast_id, use_tree };
|
||||
Some(id(self.data().uses.alloc(res)))
|
||||
let res = Use { visibility, use_tree };
|
||||
self.tree.big_data.insert(ast_id.upcast(), BigModItem::Use(res));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_extern_crate(
|
||||
&mut self,
|
||||
extern_crate: &ast::ExternCrate,
|
||||
) -> Option<FileItemTreeId<ExternCrate>> {
|
||||
) -> Option<ItemTreeAstId<ExternCrate>> {
|
||||
let name = extern_crate.name_ref()?.as_name();
|
||||
let alias = extern_crate.rename().map(|a| {
|
||||
a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
|
||||
|
|
@ -452,11 +311,12 @@ impl<'a> Ctx<'a> {
|
|||
let visibility = self.lower_visibility(extern_crate);
|
||||
let ast_id = self.source_ast_id_map.ast_id(extern_crate);
|
||||
|
||||
let res = ExternCrate { name, alias, visibility, ast_id };
|
||||
Some(id(self.data().extern_crates.alloc(res)))
|
||||
let res = ExternCrate { name, alias, visibility };
|
||||
self.tree.big_data.insert(ast_id.upcast(), BigModItem::ExternCrate(res));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
|
||||
fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<ItemTreeAstId<MacroCall>> {
|
||||
let span_map = self.span_map();
|
||||
let path = m.path()?;
|
||||
let range = path.syntax().text_range();
|
||||
|
|
@ -465,31 +325,33 @@ impl<'a> Ctx<'a> {
|
|||
})?);
|
||||
let ast_id = self.source_ast_id_map.ast_id(m);
|
||||
let expand_to = hir_expand::ExpandTo::from_call_site(m);
|
||||
let res = MacroCall { path, ast_id, expand_to, ctxt: span_map.span_for_range(range).ctx };
|
||||
Some(id(self.data().macro_calls.alloc(res)))
|
||||
let res = MacroCall { path, expand_to, ctxt: span_map.span_for_range(range).ctx };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::MacroCall(res));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option<FileItemTreeId<MacroRules>> {
|
||||
fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option<ItemTreeAstId<MacroRules>> {
|
||||
let name = m.name()?;
|
||||
let ast_id = self.source_ast_id_map.ast_id(m);
|
||||
|
||||
let res = MacroRules { name: name.as_name(), ast_id };
|
||||
Some(id(self.data().macro_rules.alloc(res)))
|
||||
let res = MacroRules { name: name.as_name() };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::MacroRules(res));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option<FileItemTreeId<Macro2>> {
|
||||
fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option<ItemTreeAstId<Macro2>> {
|
||||
let name = m.name()?;
|
||||
|
||||
let ast_id = self.source_ast_id_map.ast_id(m);
|
||||
let visibility = self.lower_visibility(m);
|
||||
|
||||
let res = Macro2 { name: name.as_name(), ast_id, visibility };
|
||||
Some(id(self.data().macro_defs.alloc(res)))
|
||||
let res = Macro2 { name: name.as_name(), visibility };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Macro2(res));
|
||||
Some(ast_id)
|
||||
}
|
||||
|
||||
fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> FileItemTreeId<ExternBlock> {
|
||||
fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> ItemTreeAstId<ExternBlock> {
|
||||
let ast_id = self.source_ast_id_map.ast_id(block);
|
||||
let abi = block.abi().map(lower_abi);
|
||||
let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| {
|
||||
list.extern_items()
|
||||
.filter_map(|item| {
|
||||
|
|
@ -497,42 +359,44 @@ impl<'a> Ctx<'a> {
|
|||
// (in other words, the knowledge that they're in an extern block must not be used).
|
||||
// This is because an extern block can contain macros whose ItemTree's top-level items
|
||||
// should be considered to be in an extern block too.
|
||||
let mod_item: ModItem = match &item {
|
||||
let mod_item: ModItemId = match &item {
|
||||
ast::ExternItem::Fn(ast) => self.lower_function(ast)?.into(),
|
||||
ast::ExternItem::Static(ast) => self.lower_static(ast)?.into(),
|
||||
ast::ExternItem::TypeAlias(ty) => self.lower_type_alias(ty)?.into(),
|
||||
ast::ExternItem::MacroCall(call) => self.lower_macro_call(call)?.into(),
|
||||
};
|
||||
let attrs = RawAttrs::new(self.db, &item, self.span_map());
|
||||
self.add_attrs(mod_item.into(), attrs);
|
||||
self.add_attrs(mod_item.ast_id(), attrs);
|
||||
Some(mod_item)
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
let res = ExternBlock { abi, ast_id, children };
|
||||
id(self.data().extern_blocks.alloc(res))
|
||||
let res = ExternBlock { children };
|
||||
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::ExternBlock(res));
|
||||
ast_id
|
||||
}
|
||||
|
||||
fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId {
|
||||
let vis = visibility_from_ast(self.db, item.visibility(), &mut |range| {
|
||||
self.span_map().span_for_range(range).ctx
|
||||
});
|
||||
self.data().vis.alloc(vis)
|
||||
}
|
||||
|
||||
fn next_variant_idx(&self) -> Idx<Variant> {
|
||||
Idx::from_raw(RawIdx::from(
|
||||
self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_abi(abi: ast::Abi) -> Symbol {
|
||||
match abi.abi_string() {
|
||||
Some(tok) => Symbol::intern(tok.text_without_quotes()),
|
||||
// `extern` default to be `extern "C"`.
|
||||
_ => sym::C,
|
||||
match &vis {
|
||||
RawVisibility::Public => RawVisibilityId::PUB,
|
||||
RawVisibility::Module(path, explicitness) if path.segments().is_empty() => {
|
||||
match (path.kind, explicitness) {
|
||||
(PathKind::SELF, VisibilityExplicitness::Explicit) => {
|
||||
RawVisibilityId::PRIV_EXPLICIT
|
||||
}
|
||||
(PathKind::SELF, VisibilityExplicitness::Implicit) => {
|
||||
RawVisibilityId::PRIV_IMPLICIT
|
||||
}
|
||||
(PathKind::Crate, _) => RawVisibilityId::PUB_CRATE,
|
||||
_ => RawVisibilityId(self.visibilities.insert_full(vis).0 as u32),
|
||||
}
|
||||
}
|
||||
_ => RawVisibilityId(self.visibilities.insert_full(vis).0 as u32),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -561,17 +425,15 @@ impl UseTreeLowering<'_> {
|
|||
}
|
||||
};
|
||||
|
||||
self.mapping.alloc(tree.clone());
|
||||
let list = use_tree_list
|
||||
.use_trees()
|
||||
.filter_map(|tree| self.lower_use_tree(tree, span_for_range))
|
||||
.collect();
|
||||
|
||||
Some(
|
||||
self.use_tree(
|
||||
UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
|
||||
tree,
|
||||
),
|
||||
)
|
||||
Some(UseTree {
|
||||
kind: UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
|
||||
})
|
||||
} else {
|
||||
let is_glob = tree.star_token().is_some();
|
||||
let path = match tree.path() {
|
||||
|
|
@ -590,23 +452,20 @@ impl UseTreeLowering<'_> {
|
|||
if path.is_none() {
|
||||
cov_mark::hit!(glob_enum_group);
|
||||
}
|
||||
Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree))
|
||||
self.mapping.alloc(tree.clone());
|
||||
Some(UseTree { kind: UseTreeKind::Glob { path: path.map(Interned::new) } })
|
||||
}
|
||||
// Globs can't be renamed
|
||||
(_, Some(_), true) | (None, None, false) => None,
|
||||
// `bla::{ as Name}` is invalid
|
||||
(None, Some(_), false) => None,
|
||||
(Some(path), alias, false) => Some(
|
||||
self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree),
|
||||
),
|
||||
(Some(path), alias, false) => {
|
||||
self.mapping.alloc(tree.clone());
|
||||
Some(UseTree { kind: UseTreeKind::Single { path: Interned::new(path), alias } })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree {
|
||||
let index = self.mapping.alloc(ast);
|
||||
UseTree { index, kind }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lower_use_tree(
|
||||
|
|
@ -626,7 +485,7 @@ fn private_vis() -> RawVisibility {
|
|||
)
|
||||
}
|
||||
|
||||
fn visibility_from_ast(
|
||||
pub(crate) fn visibility_from_ast(
|
||||
db: &dyn DefDatabase,
|
||||
node: Option<ast::Visibility>,
|
||||
span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext,
|
||||
|
|
@ -647,3 +506,11 @@ fn visibility_from_ast(
|
|||
};
|
||||
RawVisibility::Module(Interned::new(path), VisibilityExplicitness::Explicit)
|
||||
}
|
||||
|
||||
fn adt_shape(kind: StructKind) -> FieldsShape {
|
||||
match kind {
|
||||
StructKind::Record(_) => FieldsShape::Record,
|
||||
StructKind::Tuple(_) => FieldsShape::Tuple,
|
||||
StructKind::Unit => FieldsShape::Unit,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,15 +2,13 @@
|
|||
|
||||
use std::fmt::{self, Write};
|
||||
|
||||
use la_arena::{Idx, RawIdx};
|
||||
use span::{Edition, ErasedFileAstId};
|
||||
|
||||
use crate::{
|
||||
item_tree::{
|
||||
AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent,
|
||||
FieldsShape, FileItemTreeId, Function, Impl, ItemTree, Macro2, MacroCall, MacroRules, Mod,
|
||||
ModItem, ModKind, RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias,
|
||||
Union, Use, UseTree, UseTreeKind, Variant,
|
||||
Const, DefDatabase, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ItemTree,
|
||||
Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, RawAttrs, RawVisibilityId, Static,
|
||||
Struct, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
|
||||
},
|
||||
visibility::RawVisibility,
|
||||
};
|
||||
|
|
@ -19,9 +17,7 @@ pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree, edition: Ed
|
|||
let mut p =
|
||||
Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true, edition };
|
||||
|
||||
if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
|
||||
p.print_attrs(attrs, true, "\n");
|
||||
}
|
||||
p.print_attrs(&tree.top_attrs, true, "\n");
|
||||
p.blank();
|
||||
|
||||
for item in tree.top_level_items() {
|
||||
|
|
@ -103,8 +99,8 @@ impl Printer<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_attrs_of(&mut self, of: impl Into<AttrOwner>, separated_by: &str) {
|
||||
if let Some(attrs) = self.tree.attrs.get(&of.into()) {
|
||||
fn print_attrs_of(&mut self, of: ModItemId, separated_by: &str) {
|
||||
if let Some(attrs) = self.tree.attrs.get(&of.ast_id()) {
|
||||
self.print_attrs(attrs, false, separated_by);
|
||||
}
|
||||
}
|
||||
|
|
@ -112,50 +108,22 @@ impl Printer<'_> {
|
|||
fn print_visibility(&mut self, vis: RawVisibilityId) {
|
||||
match &self.tree[vis] {
|
||||
RawVisibility::Module(path, _expl) => {
|
||||
w!(self, "pub({}) ", path.display(self.db, self.edition))
|
||||
w!(self, "pub(in {}) ", path.display(self.db, self.edition))
|
||||
}
|
||||
RawVisibility::Public => w!(self, "pub "),
|
||||
RawVisibility::PubCrate => w!(self, "pub(crate) "),
|
||||
RawVisibility::PubSelf(_) => w!(self, "pub(self) "),
|
||||
};
|
||||
}
|
||||
|
||||
fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) {
|
||||
let edition = self.edition;
|
||||
fn print_fields(&mut self, kind: FieldsShape) {
|
||||
match kind {
|
||||
FieldsShape::Record => {
|
||||
self.whitespace();
|
||||
w!(self, "{{");
|
||||
self.indented(|this| {
|
||||
for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() {
|
||||
this.print_attrs_of(
|
||||
AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
|
||||
"\n",
|
||||
);
|
||||
this.print_visibility(*visibility);
|
||||
if *is_unsafe {
|
||||
w!(this, "unsafe ");
|
||||
}
|
||||
|
||||
wln!(this, "{},", name.display(self.db, edition));
|
||||
}
|
||||
});
|
||||
w!(self, "}}");
|
||||
w!(self, "{{ ... }}");
|
||||
}
|
||||
FieldsShape::Tuple => {
|
||||
w!(self, "(");
|
||||
self.indented(|this| {
|
||||
for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() {
|
||||
this.print_attrs_of(
|
||||
AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
|
||||
"\n",
|
||||
);
|
||||
this.print_visibility(*visibility);
|
||||
if *is_unsafe {
|
||||
w!(this, "unsafe ");
|
||||
}
|
||||
wln!(this, "{},", name.display(self.db, edition));
|
||||
}
|
||||
});
|
||||
w!(self, ")");
|
||||
w!(self, "(...)");
|
||||
}
|
||||
FieldsShape::Unit => {}
|
||||
}
|
||||
|
|
@ -191,20 +159,20 @@ impl Printer<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_mod_item(&mut self, item: ModItem) {
|
||||
fn print_mod_item(&mut self, item: ModItemId) {
|
||||
self.print_attrs_of(item, "\n");
|
||||
|
||||
match item {
|
||||
ModItem::Use(it) => {
|
||||
let Use { visibility, use_tree, ast_id } = &self.tree[it];
|
||||
ModItemId::Use(ast_id) => {
|
||||
let Use { visibility, use_tree } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "use ");
|
||||
self.print_use_tree(use_tree);
|
||||
wln!(self, ";");
|
||||
}
|
||||
ModItem::ExternCrate(it) => {
|
||||
let ExternCrate { name, alias, visibility, ast_id } = &self.tree[it];
|
||||
ModItemId::ExternCrate(ast_id) => {
|
||||
let ExternCrate { name, alias, visibility } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "extern crate {}", name.display(self.db, self.edition));
|
||||
|
|
@ -213,14 +181,10 @@ impl Printer<'_> {
|
|||
}
|
||||
wln!(self, ";");
|
||||
}
|
||||
ModItem::ExternBlock(it) => {
|
||||
let ExternBlock { abi, ast_id, children } = &self.tree[it];
|
||||
ModItemId::ExternBlock(ast_id) => {
|
||||
let ExternBlock { children } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
w!(self, "extern ");
|
||||
if let Some(abi) = abi {
|
||||
w!(self, "\"{}\" ", abi);
|
||||
}
|
||||
w!(self, "{{");
|
||||
w!(self, "extern {{");
|
||||
self.indented(|this| {
|
||||
for child in &**children {
|
||||
this.print_mod_item(*child);
|
||||
|
|
@ -228,52 +192,40 @@ impl Printer<'_> {
|
|||
});
|
||||
wln!(self, "}}");
|
||||
}
|
||||
ModItem::Function(it) => {
|
||||
let Function { name, visibility, ast_id } = &self.tree[it];
|
||||
ModItemId::Function(ast_id) => {
|
||||
let Function { name, visibility } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
wln!(self, "fn {};", name.display(self.db, self.edition));
|
||||
}
|
||||
ModItem::Struct(it) => {
|
||||
let Struct { visibility, name, fields, shape: kind, ast_id } = &self.tree[it];
|
||||
ModItemId::Struct(ast_id) => {
|
||||
let Struct { visibility, name, shape: kind } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "struct {}", name.display(self.db, self.edition));
|
||||
self.print_fields(FieldParent::Struct(it), *kind, fields);
|
||||
self.print_fields(*kind);
|
||||
if matches!(kind, FieldsShape::Record) {
|
||||
wln!(self);
|
||||
} else {
|
||||
wln!(self, ";");
|
||||
}
|
||||
}
|
||||
ModItem::Union(it) => {
|
||||
let Union { name, visibility, fields, ast_id } = &self.tree[it];
|
||||
ModItemId::Union(ast_id) => {
|
||||
let Union { name, visibility } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "union {}", name.display(self.db, self.edition));
|
||||
self.print_fields(FieldParent::Union(it), FieldsShape::Record, fields);
|
||||
self.print_fields(FieldsShape::Record);
|
||||
wln!(self);
|
||||
}
|
||||
ModItem::Enum(it) => {
|
||||
let Enum { name, visibility, variants, ast_id } = &self.tree[it];
|
||||
ModItemId::Enum(ast_id) => {
|
||||
let Enum { name, visibility } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "enum {}", name.display(self.db, self.edition));
|
||||
let edition = self.edition;
|
||||
self.indented(|this| {
|
||||
for variant in FileItemTreeId::range_iter(variants.clone()) {
|
||||
let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant];
|
||||
this.print_ast_id(ast_id.erase());
|
||||
this.print_attrs_of(variant, "\n");
|
||||
w!(this, "{}", name.display(self.db, edition));
|
||||
this.print_fields(FieldParent::EnumVariant(variant), *kind, fields);
|
||||
wln!(this, ",");
|
||||
}
|
||||
});
|
||||
wln!(self, "}}");
|
||||
w!(self, "enum {} {{ ... }}", name.display(self.db, self.edition));
|
||||
}
|
||||
ModItem::Const(it) => {
|
||||
let Const { name, visibility, ast_id } = &self.tree[it];
|
||||
ModItemId::Const(ast_id) => {
|
||||
let Const { name, visibility } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "const ");
|
||||
|
|
@ -283,8 +235,8 @@ impl Printer<'_> {
|
|||
}
|
||||
wln!(self, " = _;");
|
||||
}
|
||||
ModItem::Static(it) => {
|
||||
let Static { name, visibility, ast_id } = &self.tree[it];
|
||||
ModItemId::Static(ast_id) => {
|
||||
let Static { name, visibility } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "static ");
|
||||
|
|
@ -292,45 +244,33 @@ impl Printer<'_> {
|
|||
w!(self, " = _;");
|
||||
wln!(self);
|
||||
}
|
||||
ModItem::Trait(it) => {
|
||||
let Trait { name, visibility, items, ast_id } = &self.tree[it];
|
||||
ModItemId::Trait(ast_id) => {
|
||||
let Trait { name, visibility } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "trait {} {{", name.display(self.db, self.edition));
|
||||
self.indented(|this| {
|
||||
for item in &**items {
|
||||
this.print_mod_item((*item).into());
|
||||
}
|
||||
});
|
||||
wln!(self, "}}");
|
||||
w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition));
|
||||
}
|
||||
ModItem::TraitAlias(it) => {
|
||||
let TraitAlias { name, visibility, ast_id } = &self.tree[it];
|
||||
ModItemId::TraitAlias(ast_id) => {
|
||||
let TraitAlias { name, visibility } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
wln!(self, "trait {} = ..;", name.display(self.db, self.edition));
|
||||
}
|
||||
ModItem::Impl(it) => {
|
||||
let Impl { items, ast_id } = &self.tree[it];
|
||||
ModItemId::Impl(ast_id) => {
|
||||
let Impl {} = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
w!(self, "impl {{");
|
||||
self.indented(|this| {
|
||||
for item in &**items {
|
||||
this.print_mod_item((*item).into());
|
||||
}
|
||||
});
|
||||
wln!(self, "}}");
|
||||
w!(self, "impl {{ ... }}");
|
||||
}
|
||||
ModItem::TypeAlias(it) => {
|
||||
let TypeAlias { name, visibility, ast_id } = &self.tree[it];
|
||||
ModItemId::TypeAlias(ast_id) => {
|
||||
let TypeAlias { name, visibility } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "type {}", name.display(self.db, self.edition));
|
||||
w!(self, ";");
|
||||
wln!(self);
|
||||
}
|
||||
ModItem::Mod(it) => {
|
||||
let Mod { name, visibility, kind, ast_id } = &self.tree[it];
|
||||
ModItemId::Mod(ast_id) => {
|
||||
let Mod { name, visibility, kind } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "mod {}", name.display(self.db, self.edition));
|
||||
|
|
@ -349,24 +289,24 @@ impl Printer<'_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ModItem::MacroCall(it) => {
|
||||
let MacroCall { path, ast_id, expand_to, ctxt } = &self.tree[it];
|
||||
ModItemId::MacroCall(ast_id) => {
|
||||
let MacroCall { path, expand_to, ctxt } = &self.tree[ast_id];
|
||||
let _ = writeln!(
|
||||
self,
|
||||
"// AstId: {:?}, SyntaxContextId: {}, ExpandTo: {:?}",
|
||||
ast_id.erase().into_raw(),
|
||||
"// AstId: {:#?}, SyntaxContextId: {}, ExpandTo: {:?}",
|
||||
ast_id.erase(),
|
||||
ctxt,
|
||||
expand_to
|
||||
);
|
||||
wln!(self, "{}!(...);", path.display(self.db, self.edition));
|
||||
}
|
||||
ModItem::MacroRules(it) => {
|
||||
let MacroRules { name, ast_id } = &self.tree[it];
|
||||
ModItemId::MacroRules(ast_id) => {
|
||||
let MacroRules { name } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db, self.edition));
|
||||
}
|
||||
ModItem::Macro2(it) => {
|
||||
let Macro2 { name, visibility, ast_id } = &self.tree[it];
|
||||
ModItemId::Macro2(ast_id) => {
|
||||
let Macro2 { name, visibility } = &self.tree[ast_id];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
wln!(self, "macro {} {{ ... }}", name.display(self.db, self.edition));
|
||||
|
|
@ -377,7 +317,7 @@ impl Printer<'_> {
|
|||
}
|
||||
|
||||
fn print_ast_id(&mut self, ast_id: ErasedFileAstId) {
|
||||
wln!(self, "// AstId: {:?}", ast_id.into_raw());
|
||||
wln!(self, "// AstId: {ast_id:#?}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,23 +35,23 @@ use a::{c, d::{e}};
|
|||
#![no_std]
|
||||
#![doc = " another file comment"]
|
||||
|
||||
// AstId: 1
|
||||
// AstId: ExternCrate[5A82, 0]
|
||||
pub(self) extern crate self as renamed;
|
||||
|
||||
// AstId: 2
|
||||
pub(super) extern crate bli;
|
||||
// AstId: ExternCrate[7E1C, 0]
|
||||
pub(in super) extern crate bli;
|
||||
|
||||
// AstId: 3
|
||||
// AstId: Use[0000, 0]
|
||||
pub use crate::path::{nested, items as renamed, Trait as _};
|
||||
|
||||
// AstId: 4
|
||||
// AstId: Use[0000, 1]
|
||||
pub(self) use globs::*;
|
||||
|
||||
#[doc = " docs on import"]
|
||||
// AstId: 5
|
||||
// AstId: Use[0000, 2]
|
||||
pub(self) use crate::{A, B};
|
||||
|
||||
// AstId: 6
|
||||
// AstId: Use[0000, 3]
|
||||
pub(self) use a::{c, d::{e}};
|
||||
"##]],
|
||||
);
|
||||
|
|
@ -73,23 +73,23 @@ extern "C" {
|
|||
fn ex_fn();
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
#[on_extern_block]
|
||||
// AstId: 1
|
||||
extern "C" {
|
||||
// AstId: ExternBlock[0000, 0]
|
||||
extern {
|
||||
#[on_extern_type]
|
||||
// AstId: 2
|
||||
// AstId: TypeAlias[9FDF, 0]
|
||||
pub(self) type ExType;
|
||||
|
||||
#[on_extern_static]
|
||||
// AstId: 3
|
||||
// AstId: Static[43C1, 0]
|
||||
pub(self) static EX_STATIC = _;
|
||||
|
||||
#[on_extern_fn]
|
||||
// AstId: 4
|
||||
// AstId: Fn[452D, 0]
|
||||
pub(self) fn ex_fn;
|
||||
}
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -124,44 +124,21 @@ enum E {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
// AstId: 1
|
||||
// AstId: Struct[DFF3, 0]
|
||||
pub(self) struct Unit;
|
||||
|
||||
#[derive(Debug)]
|
||||
// AstId: 2
|
||||
pub(self) struct Struct {
|
||||
#[doc = " fld docs"]
|
||||
pub(self) fld,
|
||||
}
|
||||
// AstId: Struct[C7A1, 0]
|
||||
pub(self) struct Struct { ... }
|
||||
|
||||
// AstId: 3
|
||||
pub(self) struct Tuple(
|
||||
#[attr]
|
||||
pub(self) 0,
|
||||
);
|
||||
// AstId: Struct[DAC2, 0]
|
||||
pub(self) struct Tuple(...);
|
||||
|
||||
// AstId: 4
|
||||
pub(self) union Ize {
|
||||
pub(self) a,
|
||||
pub(self) b,
|
||||
}
|
||||
// AstId: Union[2DBB, 0]
|
||||
pub(self) union Ize { ... }
|
||||
|
||||
// AstId: 5
|
||||
pub(self) enum E
|
||||
// AstId: 6
|
||||
#[doc = " comment on Unit"]
|
||||
Unit,
|
||||
// AstId: 7
|
||||
#[doc = " comment on Tuple"]
|
||||
Tuple(
|
||||
pub(self) 0,
|
||||
),
|
||||
// AstId: 8
|
||||
Struct {
|
||||
#[doc = " comment on a: u8"]
|
||||
pub(self) a,
|
||||
},
|
||||
}
|
||||
// AstId: Enum[7FF8, 0]
|
||||
pub(self) enum E { ... }
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
@ -185,25 +162,19 @@ trait Tr: SuperTrait + 'lifetime {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
// AstId: 1
|
||||
// AstId: Static[B393, 0]
|
||||
pub static ST = _;
|
||||
|
||||
// AstId: 2
|
||||
// AstId: Const[B309, 0]
|
||||
pub(self) const _ = _;
|
||||
|
||||
#[attr]
|
||||
#[inner_attr_in_fn]
|
||||
// AstId: 3
|
||||
// AstId: Fn[75E3, 0]
|
||||
pub(self) fn f;
|
||||
|
||||
// AstId: 4
|
||||
pub(self) trait Tr {
|
||||
// AstId: 6
|
||||
pub(self) type Assoc;
|
||||
|
||||
// AstId: 7
|
||||
pub(self) fn method;
|
||||
}
|
||||
// AstId: Trait[2998, 0]
|
||||
pub(self) trait Tr { ... }
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
@ -226,16 +197,16 @@ mod outline;
|
|||
expect![[r##"
|
||||
#[doc = " outer"]
|
||||
#[doc = " inner"]
|
||||
// AstId: 1
|
||||
// AstId: Module[CF93, 0]
|
||||
pub(self) mod inline {
|
||||
// AstId: 3
|
||||
// AstId: Use[0000, 0]
|
||||
pub(self) use super::*;
|
||||
|
||||
// AstId: 4
|
||||
// AstId: Fn[1B26, 0]
|
||||
pub(self) fn fn_in_module;
|
||||
}
|
||||
|
||||
// AstId: 2
|
||||
// AstId: Module[8994, 0]
|
||||
pub(self) mod outline;
|
||||
"##]],
|
||||
);
|
||||
|
|
@ -254,13 +225,13 @@ pub macro m2() {}
|
|||
m!();
|
||||
"#,
|
||||
expect![[r#"
|
||||
// AstId: 1
|
||||
// AstId: MacroRules[88CE, 0]
|
||||
macro_rules! m { ... }
|
||||
|
||||
// AstId: 2
|
||||
// AstId: MacroDef[DC34, 0]
|
||||
pub macro m2 { ... }
|
||||
|
||||
// AstId: 3, SyntaxContextId: ROOT2024, ExpandTo: Items
|
||||
// AstId: MacroCall[612F, 0], SyntaxContextId: ROOT2024, ExpandTo: Items
|
||||
m!(...);
|
||||
"#]],
|
||||
);
|
||||
|
|
@ -273,7 +244,7 @@ fn pub_self() {
|
|||
pub(self) struct S;
|
||||
"#,
|
||||
expect![[r#"
|
||||
// AstId: 1
|
||||
// AstId: Struct[42E2, 0]
|
||||
pub(self) struct S;
|
||||
"#]],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
|
|||
for (_, module_data) in crate_def_map.modules() {
|
||||
for impl_def in module_data.scope.impls() {
|
||||
lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef);
|
||||
for &(_, assoc) in db.impl_items(impl_def).items.iter() {
|
||||
for &(_, assoc) in impl_def.impl_items(db).items.iter() {
|
||||
match assoc {
|
||||
AssocItemId::FunctionId(f) => {
|
||||
lang_items.collect_lang_item(db, f, LangItemTarget::Function)
|
||||
|
|
@ -125,7 +125,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
|
|||
}
|
||||
ModuleDefId::AdtId(AdtId::EnumId(e)) => {
|
||||
lang_items.collect_lang_item(db, e, LangItemTarget::EnumId);
|
||||
db.enum_variants(e).variants.iter().for_each(|&(id, _)| {
|
||||
e.enum_variants(db).variants.iter().for_each(|&(id, _, _)| {
|
||||
lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant);
|
||||
});
|
||||
}
|
||||
|
|
@ -377,6 +377,7 @@ language_item_table! {
|
|||
AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
|
||||
AsyncFnOnceOutput, sym::async_fn_once_output,async_fn_once_output, Target::AssocTy, GenericRequirement::None;
|
||||
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
|
||||
|
||||
Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
|
|
|
|||
|
|
@ -49,8 +49,9 @@ pub mod find_path;
|
|||
pub mod import_map;
|
||||
pub mod visibility;
|
||||
|
||||
use intern::{Interned, sym};
|
||||
use intern::{Interned, Symbol, sym};
|
||||
pub use rustc_abi as layout;
|
||||
use thin_vec::ThinVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
pub use crate::signatures::LocalFieldId;
|
||||
|
|
@ -74,12 +75,11 @@ use hir_expand::{
|
|||
name::Name,
|
||||
proc_macro::{CustomProcMacroExpander, ProcMacroKind},
|
||||
};
|
||||
use item_tree::ExternBlock;
|
||||
use la_arena::Idx;
|
||||
use nameres::DefMap;
|
||||
use span::{AstIdNode, Edition, FileAstId, SyntaxContext};
|
||||
use stdx::impl_from;
|
||||
use syntax::ast;
|
||||
use syntax::{AstNode, ast};
|
||||
|
||||
pub use hir_expand::{Intern, Lookup, tt};
|
||||
|
||||
|
|
@ -88,12 +88,11 @@ use crate::{
|
|||
builtin_type::BuiltinType,
|
||||
db::DefDatabase,
|
||||
hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId},
|
||||
item_tree::{
|
||||
Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules,
|
||||
Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant,
|
||||
nameres::{
|
||||
LocalDefMap, assoc::ImplItems, block_def_map, crate_def_map, crate_local_def_map,
|
||||
diagnostics::DefDiagnostics,
|
||||
},
|
||||
nameres::{LocalDefMap, block_def_map, crate_def_map, crate_local_def_map},
|
||||
signatures::VariantFields,
|
||||
signatures::{EnumVariants, InactiveEnumVariantCode, VariantFields},
|
||||
};
|
||||
|
||||
type FxIndexMap<K, V> = indexmap::IndexMap<K, V, rustc_hash::FxBuildHasher>;
|
||||
|
|
@ -113,70 +112,111 @@ pub struct ImportPathConfig {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ItemLoc<N: ItemTreeNode> {
|
||||
pub struct ItemLoc<N: AstIdNode> {
|
||||
pub container: ModuleId,
|
||||
pub id: ItemTreeId<N>,
|
||||
pub id: AstId<N>,
|
||||
}
|
||||
|
||||
impl<N: ItemTreeNode> Clone for ItemLoc<N> {
|
||||
impl<N: AstIdNode> Clone for ItemLoc<N> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: ItemTreeNode> Copy for ItemLoc<N> {}
|
||||
impl<N: AstIdNode> Copy for ItemLoc<N> {}
|
||||
|
||||
impl<N: ItemTreeNode> PartialEq for ItemLoc<N> {
|
||||
impl<N: AstIdNode> PartialEq for ItemLoc<N> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.container == other.container && self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: ItemTreeNode> Eq for ItemLoc<N> {}
|
||||
impl<N: AstIdNode> Eq for ItemLoc<N> {}
|
||||
|
||||
impl<N: ItemTreeNode> Hash for ItemLoc<N> {
|
||||
impl<N: AstIdNode> Hash for ItemLoc<N> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.container.hash(state);
|
||||
self.id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: AstIdNode> HasModule for ItemLoc<N> {
|
||||
#[inline]
|
||||
fn module(&self, _db: &dyn DefDatabase) -> ModuleId {
|
||||
self.container
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AssocItemLoc<N: ItemTreeNode> {
|
||||
pub struct AssocItemLoc<N: AstIdNode> {
|
||||
// FIXME: Store this as an erased `salsa::Id` to save space
|
||||
pub container: ItemContainerId,
|
||||
pub id: ItemTreeId<N>,
|
||||
pub id: AstId<N>,
|
||||
}
|
||||
|
||||
impl<N: ItemTreeNode> Clone for AssocItemLoc<N> {
|
||||
impl<N: AstIdNode> Clone for AssocItemLoc<N> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {}
|
||||
impl<N: AstIdNode> Copy for AssocItemLoc<N> {}
|
||||
|
||||
impl<N: ItemTreeNode> PartialEq for AssocItemLoc<N> {
|
||||
impl<N: AstIdNode> PartialEq for AssocItemLoc<N> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.container == other.container && self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: ItemTreeNode> Eq for AssocItemLoc<N> {}
|
||||
impl<N: AstIdNode> Eq for AssocItemLoc<N> {}
|
||||
|
||||
impl<N: ItemTreeNode> Hash for AssocItemLoc<N> {
|
||||
impl<N: AstIdNode> Hash for AssocItemLoc<N> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.container.hash(state);
|
||||
self.id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ItemTreeLoc {
|
||||
impl<N: AstIdNode> HasModule for AssocItemLoc<N> {
|
||||
#[inline]
|
||||
fn module(&self, db: &dyn DefDatabase) -> ModuleId {
|
||||
self.container.module(db)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AstIdLoc {
|
||||
type Container;
|
||||
type Id;
|
||||
fn item_tree_id(&self) -> ItemTreeId<Self::Id>;
|
||||
type Ast: AstNode;
|
||||
fn ast_id(&self) -> AstId<Self::Ast>;
|
||||
fn container(&self) -> Self::Container;
|
||||
}
|
||||
|
||||
impl<N: AstIdNode> AstIdLoc for ItemLoc<N> {
|
||||
type Container = ModuleId;
|
||||
type Ast = N;
|
||||
#[inline]
|
||||
fn ast_id(&self) -> AstId<Self::Ast> {
|
||||
self.id
|
||||
}
|
||||
#[inline]
|
||||
fn container(&self) -> Self::Container {
|
||||
self.container
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: AstIdNode> AstIdLoc for AssocItemLoc<N> {
|
||||
type Container = ItemContainerId;
|
||||
type Ast = N;
|
||||
#[inline]
|
||||
fn ast_id(&self) -> AstId<Self::Ast> {
|
||||
self.id
|
||||
}
|
||||
#[inline]
|
||||
fn container(&self) -> Self::Container {
|
||||
self.container
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_intern {
|
||||
($id:ident, $loc:ident, $intern:ident, $lookup:ident) => {
|
||||
impl_intern_key!($id, $loc);
|
||||
|
|
@ -186,74 +226,103 @@ macro_rules! impl_intern {
|
|||
|
||||
macro_rules! impl_loc {
|
||||
($loc:ident, $id:ident: $id_ty:ident, $container:ident: $container_type:ident) => {
|
||||
impl ItemTreeLoc for $loc {
|
||||
impl AstIdLoc for $loc {
|
||||
type Container = $container_type;
|
||||
type Id = $id_ty;
|
||||
fn item_tree_id(&self) -> ItemTreeId<Self::Id> {
|
||||
type Ast = ast::$id_ty;
|
||||
fn ast_id(&self) -> AstId<Self::Ast> {
|
||||
self.$id
|
||||
}
|
||||
fn container(&self) -> Self::Container {
|
||||
self.$container
|
||||
}
|
||||
}
|
||||
|
||||
impl HasModule for $loc {
|
||||
#[inline]
|
||||
fn module(&self, db: &dyn DefDatabase) -> ModuleId {
|
||||
self.$container.module(db)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
type FunctionLoc = AssocItemLoc<Function>;
|
||||
type FunctionLoc = AssocItemLoc<ast::Fn>;
|
||||
impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
|
||||
impl_loc!(FunctionLoc, id: Function, container: ItemContainerId);
|
||||
|
||||
type StructLoc = ItemLoc<Struct>;
|
||||
type StructLoc = ItemLoc<ast::Struct>;
|
||||
impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
|
||||
impl_loc!(StructLoc, id: Struct, container: ModuleId);
|
||||
|
||||
pub type UnionLoc = ItemLoc<Union>;
|
||||
pub type UnionLoc = ItemLoc<ast::Union>;
|
||||
impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
|
||||
impl_loc!(UnionLoc, id: Union, container: ModuleId);
|
||||
|
||||
pub type EnumLoc = ItemLoc<Enum>;
|
||||
pub type EnumLoc = ItemLoc<ast::Enum>;
|
||||
impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
|
||||
impl_loc!(EnumLoc, id: Enum, container: ModuleId);
|
||||
|
||||
type ConstLoc = AssocItemLoc<Const>;
|
||||
impl EnumId {
|
||||
#[inline]
|
||||
pub fn enum_variants(self, db: &dyn DefDatabase) -> &EnumVariants {
|
||||
&self.enum_variants_with_diagnostics(db).0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn enum_variants_with_diagnostics(
|
||||
self,
|
||||
db: &dyn DefDatabase,
|
||||
) -> &(EnumVariants, Option<ThinVec<InactiveEnumVariantCode>>) {
|
||||
EnumVariants::of(db, self)
|
||||
}
|
||||
}
|
||||
|
||||
type ConstLoc = AssocItemLoc<ast::Const>;
|
||||
impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
|
||||
impl_loc!(ConstLoc, id: Const, container: ItemContainerId);
|
||||
|
||||
pub type StaticLoc = AssocItemLoc<Static>;
|
||||
pub type StaticLoc = AssocItemLoc<ast::Static>;
|
||||
impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
|
||||
impl_loc!(StaticLoc, id: Static, container: ItemContainerId);
|
||||
|
||||
pub type TraitLoc = ItemLoc<Trait>;
|
||||
pub type TraitLoc = ItemLoc<ast::Trait>;
|
||||
impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
|
||||
impl_loc!(TraitLoc, id: Trait, container: ModuleId);
|
||||
|
||||
pub type TraitAliasLoc = ItemLoc<TraitAlias>;
|
||||
pub type TraitAliasLoc = ItemLoc<ast::TraitAlias>;
|
||||
impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias);
|
||||
impl_loc!(TraitAliasLoc, id: TraitAlias, container: ModuleId);
|
||||
|
||||
type TypeAliasLoc = AssocItemLoc<TypeAlias>;
|
||||
type TypeAliasLoc = AssocItemLoc<ast::TypeAlias>;
|
||||
impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias);
|
||||
impl_loc!(TypeAliasLoc, id: TypeAlias, container: ItemContainerId);
|
||||
|
||||
type ImplLoc = ItemLoc<Impl>;
|
||||
type ImplLoc = ItemLoc<ast::Impl>;
|
||||
impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
|
||||
impl_loc!(ImplLoc, id: Impl, container: ModuleId);
|
||||
|
||||
type UseLoc = ItemLoc<Use>;
|
||||
impl ImplId {
|
||||
#[inline]
|
||||
pub fn impl_items(self, db: &dyn DefDatabase) -> &ImplItems {
|
||||
&self.impl_items_with_diagnostics(db).0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn impl_items_with_diagnostics(self, db: &dyn DefDatabase) -> &(ImplItems, DefDiagnostics) {
|
||||
ImplItems::of(db, self)
|
||||
}
|
||||
}
|
||||
|
||||
type UseLoc = ItemLoc<ast::Use>;
|
||||
impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use);
|
||||
impl_loc!(UseLoc, id: Use, container: ModuleId);
|
||||
|
||||
type ExternCrateLoc = ItemLoc<ExternCrate>;
|
||||
type ExternCrateLoc = ItemLoc<ast::ExternCrate>;
|
||||
impl_intern!(ExternCrateId, ExternCrateLoc, intern_extern_crate, lookup_intern_extern_crate);
|
||||
impl_loc!(ExternCrateLoc, id: ExternCrate, container: ModuleId);
|
||||
|
||||
type ExternBlockLoc = ItemLoc<ExternBlock>;
|
||||
type ExternBlockLoc = ItemLoc<ast::ExternBlock>;
|
||||
impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block);
|
||||
impl_loc!(ExternBlockLoc, id: ExternBlock, container: ModuleId);
|
||||
|
||||
#[salsa::tracked]
|
||||
impl ExternBlockId {
|
||||
#[salsa::tracked]
|
||||
pub fn abi(self, db: &dyn DefDatabase) -> Option<Symbol> {
|
||||
signatures::extern_block_abi(db, self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct EnumVariantLoc {
|
||||
pub id: ItemTreeId<Variant>,
|
||||
pub id: AstId<ast::Variant>,
|
||||
pub parent: EnumId,
|
||||
pub index: u32,
|
||||
}
|
||||
|
|
@ -262,18 +331,18 @@ impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId);
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Macro2Loc {
|
||||
pub container: ModuleId,
|
||||
pub id: ItemTreeId<Macro2>,
|
||||
pub id: AstId<ast::MacroDef>,
|
||||
pub expander: MacroExpander,
|
||||
pub allow_internal_unsafe: bool,
|
||||
pub edition: Edition,
|
||||
}
|
||||
impl_intern!(Macro2Id, Macro2Loc, intern_macro2, lookup_intern_macro2);
|
||||
impl_loc!(Macro2Loc, id: Macro2, container: ModuleId);
|
||||
impl_loc!(Macro2Loc, id: MacroDef, container: ModuleId);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct MacroRulesLoc {
|
||||
pub container: ModuleId,
|
||||
pub id: ItemTreeId<MacroRules>,
|
||||
pub id: AstId<ast::MacroRules>,
|
||||
pub expander: MacroExpander,
|
||||
pub flags: MacroRulesLocFlags,
|
||||
pub edition: Edition,
|
||||
|
|
@ -301,13 +370,13 @@ pub enum MacroExpander {
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct ProcMacroLoc {
|
||||
pub container: CrateRootModuleId,
|
||||
pub id: ItemTreeId<Function>,
|
||||
pub id: AstId<ast::Fn>,
|
||||
pub expander: CustomProcMacroExpander,
|
||||
pub kind: ProcMacroKind,
|
||||
pub edition: Edition,
|
||||
}
|
||||
impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro);
|
||||
impl_loc!(ProcMacroLoc, id: Function, container: CrateRootModuleId);
|
||||
impl_loc!(ProcMacroLoc, id: Fn, container: CrateRootModuleId);
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
|
||||
pub struct BlockLoc {
|
||||
|
|
@ -315,7 +384,26 @@ pub struct BlockLoc {
|
|||
/// The containing module.
|
||||
pub module: ModuleId,
|
||||
}
|
||||
impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
|
||||
#[salsa_macros::tracked(debug)]
|
||||
#[derive(PartialOrd, Ord)]
|
||||
pub struct BlockIdLt<'db> {
|
||||
pub loc: BlockLoc,
|
||||
}
|
||||
pub type BlockId = BlockIdLt<'static>;
|
||||
impl hir_expand::Intern for BlockLoc {
|
||||
type Database = dyn DefDatabase;
|
||||
type ID = BlockId;
|
||||
fn intern(self, db: &Self::Database) -> Self::ID {
|
||||
unsafe { std::mem::transmute::<BlockIdLt<'_>, BlockId>(BlockIdLt::new(db, self)) }
|
||||
}
|
||||
}
|
||||
impl hir_expand::Lookup for BlockId {
|
||||
type Database = dyn DefDatabase;
|
||||
type Data = BlockLoc;
|
||||
fn lookup(&self, db: &Self::Database) -> Self::Data {
|
||||
self.loc(db)
|
||||
}
|
||||
}
|
||||
|
||||
/// A `ModuleId` that is always a crate's root module.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
|
@ -338,6 +426,18 @@ impl CrateRootModuleId {
|
|||
}
|
||||
}
|
||||
|
||||
impl HasModule for CrateRootModuleId {
|
||||
#[inline]
|
||||
fn module(&self, _db: &dyn DefDatabase) -> ModuleId {
|
||||
ModuleId { krate: self.krate, block: None, local_id: DefMap::ROOT }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn krate(&self, _db: &dyn DefDatabase) -> Crate {
|
||||
self.krate
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<ModuleId> for CrateRootModuleId {
|
||||
fn eq(&self, other: &ModuleId) -> bool {
|
||||
other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate
|
||||
|
|
@ -466,11 +566,19 @@ impl ModuleId {
|
|||
}
|
||||
}
|
||||
|
||||
impl HasModule for ModuleId {
|
||||
#[inline]
|
||||
fn module(&self, _db: &dyn DefDatabase) -> ModuleId {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
/// An ID of a module, **local** to a `DefMap`.
|
||||
pub type LocalModuleId = Idx<nameres::ModuleData>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct FieldId {
|
||||
// FIXME: Store this as an erased `salsa::Id` to save space
|
||||
pub parent: VariantId,
|
||||
pub local_id: LocalFieldId,
|
||||
}
|
||||
|
|
@ -486,6 +594,7 @@ pub struct TupleFieldId {
|
|||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct TypeOrConstParamId {
|
||||
// FIXME: Store this as an erased `salsa::Id` to save space
|
||||
pub parent: GenericDefId,
|
||||
pub local_id: LocalTypeOrConstParamId,
|
||||
}
|
||||
|
|
@ -544,6 +653,7 @@ impl From<ConstParamId> for TypeOrConstParamId {
|
|||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct LifetimeParamId {
|
||||
// FIXME: Store this as an erased `salsa::Id` to save space
|
||||
pub parent: GenericDefId,
|
||||
pub local_id: LocalLifetimeParamId,
|
||||
}
|
||||
|
|
@ -642,15 +752,10 @@ impl GeneralConstId {
|
|||
pub fn name(self, db: &dyn DefDatabase) -> String {
|
||||
match self {
|
||||
GeneralConstId::StaticId(it) => {
|
||||
let loc = it.lookup(db);
|
||||
let tree = loc.item_tree_id().item_tree(db);
|
||||
let name = tree[loc.id.value].name.display(db, Edition::CURRENT);
|
||||
name.to_string()
|
||||
db.static_signature(it).name.display(db, Edition::CURRENT).to_string()
|
||||
}
|
||||
GeneralConstId::ConstId(const_id) => {
|
||||
let loc = const_id.lookup(db);
|
||||
let tree = loc.item_tree_id().item_tree(db);
|
||||
tree[loc.id.value].name.as_ref().map_or_else(
|
||||
db.const_signature(const_id).name.as_ref().map_or_else(
|
||||
|| "_".to_owned(),
|
||||
|name| name.display(db, Edition::CURRENT).to_string(),
|
||||
)
|
||||
|
|
@ -692,7 +797,7 @@ impl DefWithBodyId {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, salsa_macros::Supertype)]
|
||||
pub enum AssocItemId {
|
||||
FunctionId(FunctionId),
|
||||
ConstId(ConstId),
|
||||
|
|
@ -768,8 +873,8 @@ impl GenericDefId {
|
|||
GenericDefId::TraitId(it) => file_id_and_params_of_item_loc(db, it),
|
||||
GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it),
|
||||
GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it),
|
||||
GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None),
|
||||
GenericDefId::StaticId(it) => (it.lookup(db).id.file_id(), None),
|
||||
GenericDefId::ConstId(it) => (it.lookup(db).id.file_id, None),
|
||||
GenericDefId::StaticId(it) => (it.lookup(db).id.file_id, None),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -935,9 +1040,9 @@ impl VariantId {
|
|||
|
||||
pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId {
|
||||
match self {
|
||||
VariantId::EnumVariantId(it) => it.lookup(db).id.file_id(),
|
||||
VariantId::StructId(it) => it.lookup(db).id.file_id(),
|
||||
VariantId::UnionId(it) => it.lookup(db).id.file_id(),
|
||||
VariantId::EnumVariantId(it) => it.lookup(db).id.file_id,
|
||||
VariantId::StructId(it) => it.lookup(db).id.file_id,
|
||||
VariantId::UnionId(it) => it.lookup(db).id.file_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -977,7 +1082,7 @@ pub trait HasModule {
|
|||
|
||||
impl<N, ItemId> HasModule for ItemId
|
||||
where
|
||||
N: ItemTreeNode,
|
||||
N: AstIdNode,
|
||||
ItemId: Lookup<Database = dyn DefDatabase, Data = ItemLoc<N>> + Copy,
|
||||
{
|
||||
#[inline]
|
||||
|
|
@ -1003,7 +1108,7 @@ where
|
|||
#[inline]
|
||||
fn module_for_assoc_item_loc<'db>(
|
||||
db: &(dyn 'db + DefDatabase),
|
||||
id: impl Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<impl ItemTreeNode>>,
|
||||
id: impl Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<impl AstIdNode>>,
|
||||
) -> ModuleId {
|
||||
id.lookup(db).container.module(db)
|
||||
}
|
||||
|
|
@ -1245,7 +1350,7 @@ pub struct SyntheticSyntax;
|
|||
// Crate authors can opt their type out of completions in some cases.
|
||||
// This is done with the `#[rust_analyzer::completions(...)]` attribute.
|
||||
//
|
||||
// All completeable things support `#[rust_analyzer::completions(ignore_flyimport)]`,
|
||||
// All completable things support `#[rust_analyzer::completions(ignore_flyimport)]`,
|
||||
// which causes the thing to get excluded from flyimport completion. It will still
|
||||
// be completed when in scope. This is analogous to the setting `rust-analyzer.completion.autoimport.exclude`
|
||||
// with `"type": "always"`.
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ macro_rules! f {
|
|||
};
|
||||
}
|
||||
|
||||
struct#0:1@58..64#14336# MyTraitMap2#0:2@31..42#ROOT2024# {#0:1@72..73#14336#
|
||||
map#0:1@86..89#14336#:#0:1@89..90#14336# #0:1@89..90#14336#::#0:1@91..93#14336#std#0:1@93..96#14336#::#0:1@96..98#14336#collections#0:1@98..109#14336#::#0:1@109..111#14336#HashSet#0:1@111..118#14336#<#0:1@118..119#14336#(#0:1@119..120#14336#)#0:1@120..121#14336#>#0:1@121..122#14336#,#0:1@122..123#14336#
|
||||
}#0:1@132..133#14336#
|
||||
struct#0:MacroRules[8C8E, 0]@58..64#14336# MyTraitMap2#0:MacroCall[D499, 0]@31..42#ROOT2024# {#0:MacroRules[8C8E, 0]@72..73#14336#
|
||||
map#0:MacroRules[8C8E, 0]@86..89#14336#:#0:MacroRules[8C8E, 0]@89..90#14336# #0:MacroRules[8C8E, 0]@89..90#14336#::#0:MacroRules[8C8E, 0]@91..93#14336#std#0:MacroRules[8C8E, 0]@93..96#14336#::#0:MacroRules[8C8E, 0]@96..98#14336#collections#0:MacroRules[8C8E, 0]@98..109#14336#::#0:MacroRules[8C8E, 0]@109..111#14336#HashSet#0:MacroRules[8C8E, 0]@111..118#14336#<#0:MacroRules[8C8E, 0]@118..119#14336#(#0:MacroRules[8C8E, 0]@119..120#14336#)#0:MacroRules[8C8E, 0]@120..121#14336#>#0:MacroRules[8C8E, 0]@121..122#14336#,#0:MacroRules[8C8E, 0]@122..123#14336#
|
||||
}#0:MacroRules[8C8E, 0]@132..133#14336#
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
@ -75,12 +75,12 @@ macro_rules! f {
|
|||
};
|
||||
}
|
||||
|
||||
fn#0:2@30..32#ROOT2024# main#0:2@33..37#ROOT2024#(#0:2@37..38#ROOT2024#)#0:2@38..39#ROOT2024# {#0:2@40..41#ROOT2024#
|
||||
1#0:2@50..51#ROOT2024#;#0:2@51..52#ROOT2024#
|
||||
1.0#0:2@61..64#ROOT2024#;#0:2@64..65#ROOT2024#
|
||||
(#0:2@74..75#ROOT2024#(#0:2@75..76#ROOT2024#1#0:2@76..77#ROOT2024#,#0:2@77..78#ROOT2024# )#0:2@78..79#ROOT2024#,#0:2@79..80#ROOT2024# )#0:2@80..81#ROOT2024#.#0:2@81..82#ROOT2024#0#0:2@82..85#ROOT2024#.#0:2@82..85#ROOT2024#0#0:2@82..85#ROOT2024#;#0:2@85..86#ROOT2024#
|
||||
let#0:2@95..98#ROOT2024# x#0:2@99..100#ROOT2024# =#0:2@101..102#ROOT2024# 1#0:2@103..104#ROOT2024#;#0:2@104..105#ROOT2024#
|
||||
}#0:2@110..111#ROOT2024#
|
||||
fn#0:MacroCall[D499, 0]@30..32#ROOT2024# main#0:MacroCall[D499, 0]@33..37#ROOT2024#(#0:MacroCall[D499, 0]@37..38#ROOT2024#)#0:MacroCall[D499, 0]@38..39#ROOT2024# {#0:MacroCall[D499, 0]@40..41#ROOT2024#
|
||||
1#0:MacroCall[D499, 0]@50..51#ROOT2024#;#0:MacroCall[D499, 0]@51..52#ROOT2024#
|
||||
1.0#0:MacroCall[D499, 0]@61..64#ROOT2024#;#0:MacroCall[D499, 0]@64..65#ROOT2024#
|
||||
(#0:MacroCall[D499, 0]@74..75#ROOT2024#(#0:MacroCall[D499, 0]@75..76#ROOT2024#1#0:MacroCall[D499, 0]@76..77#ROOT2024#,#0:MacroCall[D499, 0]@77..78#ROOT2024# )#0:MacroCall[D499, 0]@78..79#ROOT2024#,#0:MacroCall[D499, 0]@79..80#ROOT2024# )#0:MacroCall[D499, 0]@80..81#ROOT2024#.#0:MacroCall[D499, 0]@81..82#ROOT2024#0#0:MacroCall[D499, 0]@82..85#ROOT2024#.#0:MacroCall[D499, 0]@82..85#ROOT2024#0#0:MacroCall[D499, 0]@82..85#ROOT2024#;#0:MacroCall[D499, 0]@85..86#ROOT2024#
|
||||
let#0:MacroCall[D499, 0]@95..98#ROOT2024# x#0:MacroCall[D499, 0]@99..100#ROOT2024# =#0:MacroCall[D499, 0]@101..102#ROOT2024# 1#0:MacroCall[D499, 0]@103..104#ROOT2024#;#0:MacroCall[D499, 0]@104..105#ROOT2024#
|
||||
}#0:MacroCall[D499, 0]@110..111#ROOT2024#
|
||||
|
||||
|
||||
"#]],
|
||||
|
|
@ -171,7 +171,7 @@ fn main(foo: ()) {
|
|||
}
|
||||
|
||||
fn main(foo: ()) {
|
||||
/* error: unresolved macro unresolved */"helloworld!"#0:3@236..321#ROOT2024#;
|
||||
/* error: unresolved macro unresolved */"helloworld!"#0:Fn[B9C7, 0]@236..321#ROOT2024#;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +197,7 @@ macro_rules! mk_struct {
|
|||
#[macro_use]
|
||||
mod foo;
|
||||
|
||||
struct#1:1@59..65#14336# Foo#0:2@32..35#ROOT2024#(#1:1@70..71#14336#u32#0:2@41..44#ROOT2024#)#1:1@74..75#14336#;#1:1@75..76#14336#
|
||||
struct#1:MacroRules[E572, 0]@59..65#14336# Foo#0:MacroCall[BDD3, 0]@32..35#ROOT2024#(#1:MacroRules[E572, 0]@70..71#14336#u32#0:MacroCall[BDD3, 0]@41..44#ROOT2024#)#1:MacroRules[E572, 0]@74..75#14336#;#1:MacroRules[E572, 0]@75..76#14336#
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
@ -2029,3 +2029,25 @@ fn f() {
|
|||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lifetime_repeat() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
($($x:expr)'a*) => (stringify!($($x)'b*));
|
||||
}
|
||||
fn f() {
|
||||
let _ = m!(0 'a 1 'a 2);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! m {
|
||||
($($x:expr)'a*) => (stringify!($($x)'b*));
|
||||
}
|
||||
fn f() {
|
||||
let _ = stringify!(0 'b 1 'b 2);
|
||||
}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ macro_rules! m {
|
|||
($(x),*) => ();
|
||||
($(x)_*) => ();
|
||||
($(x)i*) => ();
|
||||
($(x)'a*) => ();
|
||||
($(x)'_*) => ();
|
||||
($($i:ident)*) => ($_);
|
||||
($($true:ident)*) => ($true);
|
||||
($($false:ident)*) => ($false);
|
||||
|
|
@ -28,6 +30,8 @@ macro_rules! m {
|
|||
($(x),*) => ();
|
||||
($(x)_*) => ();
|
||||
($(x)i*) => ();
|
||||
($(x)'a*) => ();
|
||||
($(x)'_*) => ();
|
||||
($($i:ident)*) => ($_);
|
||||
($($true:ident)*) => ($true);
|
||||
($($false:ident)*) => ($false);
|
||||
|
|
|
|||
|
|
@ -784,7 +784,7 @@ macro_rules! delegate_impl {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl <> Data for &'amut G where G: Data {}
|
||||
impl <> Data for &'a mut G where G: Data {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ mod builtin_fn_macro;
|
|||
mod mbe;
|
||||
mod proc_macros;
|
||||
|
||||
use std::{iter, ops::Range, sync};
|
||||
use std::{any::TypeId, iter, ops::Range, sync};
|
||||
|
||||
use base_db::RootQueryDb;
|
||||
use expect_test::Expect;
|
||||
|
|
@ -302,14 +302,15 @@ fn pretty_print_macro_expansion(
|
|||
(_, T!['{']) => " ",
|
||||
(T![;] | T!['{'] | T!['}'], _) => "\n",
|
||||
(_, T!['}']) => "\n",
|
||||
(IDENT | LIFETIME_IDENT, IDENT | LIFETIME_IDENT) => " ",
|
||||
_ if prev_kind.is_keyword(Edition::CURRENT)
|
||||
&& curr_kind.is_keyword(Edition::CURRENT) =>
|
||||
_ if (prev_kind.is_any_identifier()
|
||||
|| prev_kind == LIFETIME_IDENT
|
||||
|| prev_kind.is_literal())
|
||||
&& (curr_kind.is_any_identifier()
|
||||
|| curr_kind == LIFETIME_IDENT
|
||||
|| curr_kind.is_literal()) =>
|
||||
{
|
||||
" "
|
||||
}
|
||||
(IDENT, _) if curr_kind.is_keyword(Edition::CURRENT) => " ",
|
||||
(_, IDENT) if prev_kind.is_keyword(Edition::CURRENT) => " ",
|
||||
(T![>], IDENT) => " ",
|
||||
(T![>], _) if curr_kind.is_keyword(Edition::CURRENT) => " ",
|
||||
(T![->], _) | (_, T![->]) => " ",
|
||||
|
|
@ -380,4 +381,8 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander {
|
|||
panic!("got invalid macro input: {:?}", parse.errors());
|
||||
}
|
||||
}
|
||||
|
||||
fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
other.type_id() == TypeId::of::<Self>()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,9 +181,9 @@ fn foo(&self) {
|
|||
self.0. 1;
|
||||
}
|
||||
|
||||
fn#0:1@45..47#ROOT2024# foo#0:1@48..51#ROOT2024#(#0:1@51..52#ROOT2024#�:1@52..53#ROOT2024#self#0:1@53..57#ROOT2024# )#0:1@57..58#ROOT2024# {#0:1@59..60#ROOT2024#
|
||||
self#0:1@65..69#ROOT2024# .#0:1@69..70#ROOT2024#0#0:1@70..71#ROOT2024#.#0:1@71..72#ROOT2024#1#0:1@73..74#ROOT2024#;#0:1@74..75#ROOT2024#
|
||||
}#0:1@76..77#ROOT2024#"#]],
|
||||
fn#0:Fn[4D85, 0]@45..47#ROOT2024# foo#0:Fn[4D85, 0]@48..51#ROOT2024#(#0:Fn[4D85, 0]@51..52#ROOT2024#�:Fn[4D85, 0]@52..53#ROOT2024#self#0:Fn[4D85, 0]@53..57#ROOT2024# )#0:Fn[4D85, 0]@57..58#ROOT2024# {#0:Fn[4D85, 0]@59..60#ROOT2024#
|
||||
self#0:Fn[4D85, 0]@65..69#ROOT2024# .#0:Fn[4D85, 0]@69..70#ROOT2024#0#0:Fn[4D85, 0]@70..71#ROOT2024#.#0:Fn[4D85, 0]@71..72#ROOT2024#1#0:Fn[4D85, 0]@73..74#ROOT2024#;#0:Fn[4D85, 0]@74..75#ROOT2024#
|
||||
}#0:Fn[4D85, 0]@76..77#ROOT2024#"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,8 +62,8 @@ use std::ops::Deref;
|
|||
|
||||
use base_db::Crate;
|
||||
use hir_expand::{
|
||||
EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId, mod_path::ModPath,
|
||||
name::Name, proc_macro::ProcMacroKind,
|
||||
EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, mod_path::ModPath, name::Name,
|
||||
proc_macro::ProcMacroKind,
|
||||
};
|
||||
use intern::Symbol;
|
||||
use itertools::Itertools;
|
||||
|
|
@ -80,7 +80,7 @@ use crate::{
|
|||
LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
|
||||
db::DefDatabase,
|
||||
item_scope::{BuiltinShadowMode, ItemScope},
|
||||
item_tree::{ItemTreeId, Mod, TreeId},
|
||||
item_tree::TreeId,
|
||||
nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
|
||||
per_ns::PerNs,
|
||||
visibility::{Visibility, VisibilityExplicitness},
|
||||
|
|
@ -171,12 +171,10 @@ pub struct DefMap {
|
|||
/// ExternCrateId being None implies it being imported from the general prelude import.
|
||||
macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>,
|
||||
|
||||
// FIXME: AstId's are fairly unstable
|
||||
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
|
||||
/// attributes.
|
||||
// FIXME: Figure out a better way for the IDE layer to resolve these?
|
||||
derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
|
||||
// FIXME: AstId's are fairly unstable
|
||||
/// A mapping from [`hir_expand::MacroDefId`] to [`crate::MacroId`].
|
||||
pub macro_def_to_macro_id: FxHashMap<ErasedAstId, MacroId>,
|
||||
|
||||
|
|
@ -191,7 +189,7 @@ pub struct DefMap {
|
|||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
struct DefMapCrateData {
|
||||
/// Side table for resolving derive helpers.
|
||||
exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
|
||||
exported_derives: FxHashMap<MacroId, Box<[Name]>>,
|
||||
fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
|
||||
|
||||
/// Custom attributes registered with `#![register_attr]`.
|
||||
|
|
@ -291,11 +289,11 @@ pub enum ModuleOrigin {
|
|||
File {
|
||||
is_mod_rs: bool,
|
||||
declaration: FileAstId<ast::Module>,
|
||||
declaration_tree_id: ItemTreeId<Mod>,
|
||||
declaration_tree_id: TreeId,
|
||||
definition: EditionedFileId,
|
||||
},
|
||||
Inline {
|
||||
definition_tree_id: ItemTreeId<Mod>,
|
||||
definition_tree_id: TreeId,
|
||||
definition: FileAstId<ast::Module>,
|
||||
},
|
||||
/// Pseudo-module introduced by a block scope (contains only inner items).
|
||||
|
|
|
|||
|
|
@ -1,14 +1,28 @@
|
|||
//! Expansion of associated items
|
||||
|
||||
use hir_expand::{AstId, InFile, Intern, Lookup, MacroCallKind, MacroDefKind, name::Name};
|
||||
use syntax::ast;
|
||||
use std::mem;
|
||||
|
||||
use cfg::CfgOptions;
|
||||
use hir_expand::{
|
||||
AstId, ExpandTo, HirFileId, InFile, Intern, Lookup, MacroCallKind, MacroDefKind,
|
||||
mod_path::ModPath,
|
||||
name::{AsName, Name},
|
||||
span_map::SpanMap,
|
||||
};
|
||||
use intern::Interned;
|
||||
use span::AstIdMap;
|
||||
use syntax::{
|
||||
AstNode,
|
||||
ast::{self, HasModuleItem, HasName},
|
||||
};
|
||||
use thin_vec::ThinVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
AssocItemId, AstIdWithPath, ConstLoc, FunctionId, FunctionLoc, ImplId, ItemContainerId,
|
||||
ItemLoc, MacroCallId, ModuleId, TraitId, TypeAliasId, TypeAliasLoc,
|
||||
attr::Attrs,
|
||||
db::DefDatabase,
|
||||
item_tree::{AssocItem, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId},
|
||||
macro_call_as_call_id,
|
||||
nameres::{
|
||||
DefMap, LocalDefMap, MacroSubNs,
|
||||
|
|
@ -20,9 +34,8 @@ use crate::{
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TraitItems {
|
||||
pub items: Box<[(Name, AssocItemId)]>,
|
||||
// box it as the vec is usually empty anyways
|
||||
// FIXME: AstIds are rather unstable...
|
||||
pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
|
||||
// `ThinVec` as the vec is usually empty anyways
|
||||
pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>,
|
||||
}
|
||||
|
||||
impl TraitItems {
|
||||
|
|
@ -35,12 +48,12 @@ impl TraitItems {
|
|||
db: &dyn DefDatabase,
|
||||
tr: TraitId,
|
||||
) -> (Arc<TraitItems>, DefDiagnostics) {
|
||||
let ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
|
||||
let ItemLoc { container: module_id, id: ast_id } = tr.lookup(db);
|
||||
|
||||
let collector = AssocItemCollector::new(db, module_id, ItemContainerId::TraitId(tr));
|
||||
let item_tree = tree_id.item_tree(db);
|
||||
let (items, macro_calls, diagnostics) =
|
||||
collector.collect(&item_tree, tree_id.tree_id(), &item_tree[tree_id.value].items);
|
||||
let collector =
|
||||
AssocItemCollector::new(db, module_id, ItemContainerId::TraitId(tr), ast_id.file_id);
|
||||
let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db);
|
||||
let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list());
|
||||
|
||||
(Arc::new(TraitItems { macro_calls, items }), DefDiagnostics::new(diagnostics))
|
||||
}
|
||||
|
|
@ -76,41 +89,36 @@ impl TraitItems {
|
|||
}
|
||||
|
||||
pub fn macro_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
|
||||
self.macro_calls.iter().flat_map(|it| it.iter()).copied()
|
||||
self.macro_calls.iter().copied()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ImplItems {
|
||||
pub items: Box<[(Name, AssocItemId)]>,
|
||||
// box it as the vec is usually empty anyways
|
||||
// FIXME: AstIds are rather unstable...
|
||||
pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
|
||||
// `ThinVec` as the vec is usually empty anyways
|
||||
pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl ImplItems {
|
||||
#[salsa::tracked(returns(ref))]
|
||||
pub fn of(db: &dyn DefDatabase, id: ImplId) -> (ImplItems, DefDiagnostics) {
|
||||
let _p = tracing::info_span!("impl_items_with_diagnostics_query").entered();
|
||||
let ItemLoc { container: module_id, id: ast_id } = id.lookup(db);
|
||||
|
||||
let collector =
|
||||
AssocItemCollector::new(db, module_id, ItemContainerId::ImplId(id), ast_id.file_id);
|
||||
let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db);
|
||||
let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list());
|
||||
|
||||
(ImplItems { items, macro_calls }, DefDiagnostics::new(diagnostics))
|
||||
}
|
||||
}
|
||||
|
||||
impl ImplItems {
|
||||
#[inline]
|
||||
pub(crate) fn impl_items_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplItems> {
|
||||
db.impl_items_with_diagnostics(id).0
|
||||
}
|
||||
|
||||
pub(crate) fn impl_items_with_diagnostics_query(
|
||||
db: &dyn DefDatabase,
|
||||
id: ImplId,
|
||||
) -> (Arc<ImplItems>, DefDiagnostics) {
|
||||
let _p = tracing::info_span!("impl_items_with_diagnostics_query").entered();
|
||||
let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
|
||||
|
||||
let collector = AssocItemCollector::new(db, module_id, ItemContainerId::ImplId(id));
|
||||
let item_tree = tree_id.item_tree(db);
|
||||
let (items, macro_calls, diagnostics) =
|
||||
collector.collect(&item_tree, tree_id.tree_id(), &item_tree[tree_id.value].items);
|
||||
|
||||
(Arc::new(ImplItems { items, macro_calls }), DefDiagnostics::new(diagnostics))
|
||||
}
|
||||
|
||||
pub fn macro_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
|
||||
self.macro_calls.iter().flat_map(|it| it.iter()).copied()
|
||||
self.macro_calls.iter().copied()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -119,67 +127,73 @@ struct AssocItemCollector<'a> {
|
|||
module_id: ModuleId,
|
||||
def_map: &'a DefMap,
|
||||
local_def_map: &'a LocalDefMap,
|
||||
ast_id_map: Arc<AstIdMap>,
|
||||
span_map: SpanMap,
|
||||
cfg_options: &'a CfgOptions,
|
||||
file_id: HirFileId,
|
||||
diagnostics: Vec<DefDiagnostic>,
|
||||
container: ItemContainerId,
|
||||
|
||||
depth: usize,
|
||||
items: Vec<(Name, AssocItemId)>,
|
||||
macro_calls: Vec<(AstId<ast::Item>, MacroCallId)>,
|
||||
macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>,
|
||||
}
|
||||
|
||||
impl<'a> AssocItemCollector<'a> {
|
||||
fn new(db: &'a dyn DefDatabase, module_id: ModuleId, container: ItemContainerId) -> Self {
|
||||
fn new(
|
||||
db: &'a dyn DefDatabase,
|
||||
module_id: ModuleId,
|
||||
container: ItemContainerId,
|
||||
file_id: HirFileId,
|
||||
) -> Self {
|
||||
let (def_map, local_def_map) = module_id.local_def_map(db);
|
||||
Self {
|
||||
db,
|
||||
module_id,
|
||||
def_map,
|
||||
local_def_map,
|
||||
ast_id_map: db.ast_id_map(file_id),
|
||||
span_map: db.span_map(file_id),
|
||||
cfg_options: module_id.krate.cfg_options(db),
|
||||
file_id,
|
||||
container,
|
||||
items: Vec::new(),
|
||||
|
||||
depth: 0,
|
||||
macro_calls: Vec::new(),
|
||||
macro_calls: ThinVec::new(),
|
||||
diagnostics: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn collect(
|
||||
mut self,
|
||||
item_tree: &ItemTree,
|
||||
tree_id: TreeId,
|
||||
assoc_items: &[AssocItem],
|
||||
) -> (
|
||||
Box<[(Name, AssocItemId)]>,
|
||||
Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
|
||||
Vec<DefDiagnostic>,
|
||||
) {
|
||||
self.items.reserve(assoc_items.len());
|
||||
for &item in assoc_items {
|
||||
self.collect_item(item_tree, tree_id, item);
|
||||
item_list: Option<ast::AssocItemList>,
|
||||
) -> (Box<[(Name, AssocItemId)]>, ThinVec<(AstId<ast::Item>, MacroCallId)>, Vec<DefDiagnostic>)
|
||||
{
|
||||
if let Some(item_list) = item_list {
|
||||
for item in item_list.assoc_items() {
|
||||
self.collect_item(item);
|
||||
}
|
||||
}
|
||||
(
|
||||
self.items.into_boxed_slice(),
|
||||
if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) },
|
||||
self.diagnostics,
|
||||
)
|
||||
self.macro_calls.shrink_to_fit();
|
||||
(self.items.into_boxed_slice(), self.macro_calls, self.diagnostics)
|
||||
}
|
||||
|
||||
fn collect_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocItem) {
|
||||
let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into());
|
||||
if !attrs.is_cfg_enabled(self.module_id.krate.cfg_options(self.db)) {
|
||||
fn collect_item(&mut self, item: ast::AssocItem) {
|
||||
let ast_id = self.ast_id_map.ast_id(&item);
|
||||
let attrs = Attrs::new(self.db, &item, self.span_map.as_ref(), self.cfg_options);
|
||||
if let Err(cfg) = attrs.is_cfg_enabled(self.cfg_options) {
|
||||
self.diagnostics.push(DefDiagnostic::unconfigured_code(
|
||||
self.module_id.local_id,
|
||||
tree_id,
|
||||
ModItem::from(item).into(),
|
||||
attrs.cfg().unwrap(),
|
||||
self.module_id.krate.cfg_options(self.db).clone(),
|
||||
InFile::new(self.file_id, ast_id.erase()),
|
||||
cfg,
|
||||
self.cfg_options.clone(),
|
||||
));
|
||||
return;
|
||||
}
|
||||
let ast_id = InFile::new(self.file_id, ast_id.upcast());
|
||||
|
||||
'attrs: for attr in &*attrs {
|
||||
let ast_id = AstId::new(tree_id.file_id(), item.ast_id(item_tree).upcast());
|
||||
let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id };
|
||||
|
||||
match self.def_map.resolve_attr_macro(
|
||||
|
|
@ -223,34 +237,51 @@ impl<'a> AssocItemCollector<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
self.record_item(item_tree, tree_id, item);
|
||||
self.record_item(item);
|
||||
}
|
||||
|
||||
fn record_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocItem) {
|
||||
fn record_item(&mut self, item: ast::AssocItem) {
|
||||
match item {
|
||||
AssocItem::Function(id) => {
|
||||
let item = &item_tree[id];
|
||||
ast::AssocItem::Fn(function) => {
|
||||
let Some(name) = function.name() else { return };
|
||||
let ast_id = self.ast_id_map.ast_id(&function);
|
||||
let def = FunctionLoc {
|
||||
container: self.container,
|
||||
id: InFile::new(self.file_id, ast_id),
|
||||
}
|
||||
.intern(self.db);
|
||||
self.items.push((name.as_name(), def.into()));
|
||||
}
|
||||
ast::AssocItem::TypeAlias(type_alias) => {
|
||||
let Some(name) = type_alias.name() else { return };
|
||||
let ast_id = self.ast_id_map.ast_id(&type_alias);
|
||||
let def = TypeAliasLoc {
|
||||
container: self.container,
|
||||
id: InFile::new(self.file_id, ast_id),
|
||||
}
|
||||
.intern(self.db);
|
||||
self.items.push((name.as_name(), def.into()));
|
||||
}
|
||||
ast::AssocItem::Const(konst) => {
|
||||
let Some(name) = konst.name() else { return };
|
||||
let ast_id = self.ast_id_map.ast_id(&konst);
|
||||
let def =
|
||||
FunctionLoc { container: self.container, id: ItemTreeId::new(tree_id, id) }
|
||||
ConstLoc { container: self.container, id: InFile::new(self.file_id, ast_id) }
|
||||
.intern(self.db);
|
||||
self.items.push((item.name.clone(), def.into()));
|
||||
self.items.push((name.as_name(), def.into()));
|
||||
}
|
||||
AssocItem::TypeAlias(id) => {
|
||||
let item = &item_tree[id];
|
||||
let def =
|
||||
TypeAliasLoc { container: self.container, id: ItemTreeId::new(tree_id, id) }
|
||||
.intern(self.db);
|
||||
self.items.push((item.name.clone(), def.into()));
|
||||
}
|
||||
AssocItem::Const(id) => {
|
||||
let item = &item_tree[id];
|
||||
let Some(name) = item.name.clone() else { return };
|
||||
let def = ConstLoc { container: self.container, id: ItemTreeId::new(tree_id, id) }
|
||||
.intern(self.db);
|
||||
self.items.push((name, def.into()));
|
||||
}
|
||||
AssocItem::MacroCall(call) => {
|
||||
let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call];
|
||||
ast::AssocItem::MacroCall(call) => {
|
||||
let ast_id = self.ast_id_map.ast_id(&call);
|
||||
let ast_id = InFile::new(self.file_id, ast_id);
|
||||
let Some(path) = call.path() else { return };
|
||||
let range = path.syntax().text_range();
|
||||
let Some(path) = ModPath::from_src(self.db, path, &mut |range| {
|
||||
self.span_map.span_for_range(range).ctx
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
let path = Interned::new(path);
|
||||
let ctxt = self.span_map.span_for_range(range).ctx;
|
||||
|
||||
let resolver = |path: &_| {
|
||||
self.def_map
|
||||
|
|
@ -268,10 +299,10 @@ impl<'a> AssocItemCollector<'a> {
|
|||
};
|
||||
match macro_call_as_call_id(
|
||||
self.db,
|
||||
InFile::new(tree_id.file_id(), ast_id),
|
||||
path,
|
||||
ast_id,
|
||||
&path,
|
||||
ctxt,
|
||||
expand_to,
|
||||
ExpandTo::Items,
|
||||
self.module_id.krate(),
|
||||
resolver,
|
||||
&mut |ptr, call_id| {
|
||||
|
|
@ -281,8 +312,7 @@ impl<'a> AssocItemCollector<'a> {
|
|||
// FIXME: Expansion error?
|
||||
Ok(call_id) => match call_id.value {
|
||||
Some(call_id) => {
|
||||
self.macro_calls
|
||||
.push((InFile::new(tree_id.file_id(), ast_id.upcast()), call_id));
|
||||
self.macro_calls.push((ast_id.upcast(), call_id));
|
||||
self.collect_macro_items(call_id);
|
||||
}
|
||||
None => (),
|
||||
|
|
@ -291,11 +321,11 @@ impl<'a> AssocItemCollector<'a> {
|
|||
self.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
||||
self.module_id.local_id,
|
||||
MacroCallKind::FnLike {
|
||||
ast_id: InFile::new(tree_id.file_id(), ast_id),
|
||||
expand_to,
|
||||
ast_id,
|
||||
expand_to: ExpandTo::Items,
|
||||
eager: None,
|
||||
},
|
||||
Clone::clone(path),
|
||||
(*path).clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -308,13 +338,29 @@ impl<'a> AssocItemCollector<'a> {
|
|||
tracing::warn!("macro expansion is too deep");
|
||||
return;
|
||||
}
|
||||
let tree_id = TreeId::new(macro_call_id.into(), None);
|
||||
let item_tree = self.db.file_item_tree(macro_call_id.into());
|
||||
|
||||
let (syntax, span_map) = self.db.parse_macro_expansion(macro_call_id).value;
|
||||
let old_file_id = mem::replace(&mut self.file_id, macro_call_id.into());
|
||||
let old_ast_id_map = mem::replace(&mut self.ast_id_map, self.db.ast_id_map(self.file_id));
|
||||
let old_span_map = mem::replace(&mut self.span_map, SpanMap::ExpansionSpanMap(span_map));
|
||||
self.depth += 1;
|
||||
for item in item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item) {
|
||||
self.collect_item(&item_tree, tree_id, item);
|
||||
|
||||
let items = ast::MacroItems::cast(syntax.syntax_node()).expect("not `MacroItems`");
|
||||
for item in items.items() {
|
||||
let item = match item {
|
||||
ast::Item::Fn(it) => ast::AssocItem::from(it),
|
||||
ast::Item::Const(it) => it.into(),
|
||||
ast::Item::TypeAlias(it) => it.into(),
|
||||
ast::Item::MacroCall(it) => it.into(),
|
||||
// FIXME: Should error on disallowed item kinds.
|
||||
_ => continue,
|
||||
};
|
||||
self.collect_item(item);
|
||||
}
|
||||
|
||||
self.depth -= 1;
|
||||
self.file_id = old_file_id;
|
||||
self.ast_id_map = old_ast_id_map;
|
||||
self.span_map = old_span_map;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin};
|
|||
use cfg::{CfgAtom, CfgExpr, CfgOptions};
|
||||
use either::Either;
|
||||
use hir_expand::{
|
||||
EditionedFileId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId,
|
||||
MacroDefKind,
|
||||
EditionedFileId, ErasedAstId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind,
|
||||
MacroDefId, MacroDefKind,
|
||||
attrs::{Attr, AttrId},
|
||||
builtin::{find_builtin_attr, find_builtin_derive, find_builtin_macro},
|
||||
mod_path::{ModPath, PathKind},
|
||||
|
|
@ -35,9 +35,8 @@ use crate::{
|
|||
db::DefDatabase,
|
||||
item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports},
|
||||
item_tree::{
|
||||
self, AttrOwner, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree,
|
||||
ItemTreeId, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
|
||||
UseTreeKind,
|
||||
self, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, Macro2, MacroCall,
|
||||
MacroRules, Mod, ModItemId, ModKind, TreeId,
|
||||
},
|
||||
macro_call_as_call_id,
|
||||
nameres::{
|
||||
|
|
@ -154,14 +153,14 @@ struct Import {
|
|||
impl Import {
|
||||
fn from_use(
|
||||
tree: &ItemTree,
|
||||
item_tree_id: ItemTreeId<item_tree::Use>,
|
||||
item: FileAstId<ast::Use>,
|
||||
id: UseId,
|
||||
is_prelude: bool,
|
||||
mut cb: impl FnMut(Self),
|
||||
) {
|
||||
let it = &tree[item_tree_id.value];
|
||||
let it = &tree[item];
|
||||
let visibility = &tree[it.visibility];
|
||||
it.use_tree.expand(|idx, path, kind, alias| {
|
||||
it.expand(|idx, path, kind, alias| {
|
||||
cb(Self {
|
||||
path,
|
||||
alias,
|
||||
|
|
@ -181,15 +180,15 @@ struct ImportDirective {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
struct MacroDirective {
|
||||
struct MacroDirective<'db> {
|
||||
module_id: LocalModuleId,
|
||||
depth: usize,
|
||||
kind: MacroDirectiveKind,
|
||||
kind: MacroDirectiveKind<'db>,
|
||||
container: ItemContainerId,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
enum MacroDirectiveKind {
|
||||
enum MacroDirectiveKind<'db> {
|
||||
FnLike {
|
||||
ast_id: AstIdWithPath<ast::MacroCall>,
|
||||
expand_to: ExpandTo,
|
||||
|
|
@ -206,30 +205,31 @@ enum MacroDirectiveKind {
|
|||
Attr {
|
||||
ast_id: AstIdWithPath<ast::Item>,
|
||||
attr: Attr,
|
||||
mod_item: ModItem,
|
||||
mod_item: ModItemId,
|
||||
/* is this needed? */ tree: TreeId,
|
||||
item_tree: &'db ItemTree,
|
||||
},
|
||||
}
|
||||
|
||||
/// Walks the tree of module recursively
|
||||
struct DefCollector<'a> {
|
||||
db: &'a dyn DefDatabase,
|
||||
struct DefCollector<'db> {
|
||||
db: &'db dyn DefDatabase,
|
||||
def_map: DefMap,
|
||||
local_def_map: LocalDefMap,
|
||||
/// Set only in case of blocks.
|
||||
crate_local_def_map: Option<&'a LocalDefMap>,
|
||||
crate_local_def_map: Option<&'db LocalDefMap>,
|
||||
// The dependencies of the current crate, including optional deps like `test`.
|
||||
deps: FxHashMap<Name, BuiltDependency>,
|
||||
glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>,
|
||||
unresolved_imports: Vec<ImportDirective>,
|
||||
indeterminate_imports: Vec<(ImportDirective, PerNs)>,
|
||||
unresolved_macros: Vec<MacroDirective>,
|
||||
unresolved_macros: Vec<MacroDirective<'db>>,
|
||||
// We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
|
||||
// resolve. When we emit diagnostics for unresolved imports, we only do so if the import
|
||||
// doesn't start with an unresolved crate's name.
|
||||
unresolved_extern_crates: FxHashSet<Name>,
|
||||
mod_dirs: FxHashMap<LocalModuleId, ModDir>,
|
||||
cfg_options: &'a CfgOptions,
|
||||
cfg_options: &'db CfgOptions,
|
||||
/// 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
|
||||
|
|
@ -244,10 +244,10 @@ struct DefCollector<'a> {
|
|||
/// This also stores the attributes to skip when we resolve derive helpers and non-macro
|
||||
/// non-builtin attributes in general.
|
||||
// FIXME: There has to be a better way to do this
|
||||
skip_attrs: FxHashMap<InFile<ModItem>, AttrId>,
|
||||
skip_attrs: FxHashMap<InFile<FileAstId<ast::Item>>, AttrId>,
|
||||
}
|
||||
|
||||
impl DefCollector<'_> {
|
||||
impl<'db> DefCollector<'db> {
|
||||
fn seed_with_top_level(&mut self) {
|
||||
let _p = tracing::info_span!("seed_with_top_level").entered();
|
||||
|
||||
|
|
@ -355,7 +355,7 @@ impl DefCollector<'_> {
|
|||
macro_depth: 0,
|
||||
module_id: DefMap::ROOT,
|
||||
tree_id: TreeId::new(file_id.into(), None),
|
||||
item_tree: &item_tree,
|
||||
item_tree,
|
||||
mod_dir: ModDir::root(),
|
||||
}
|
||||
.collect_in_top_module(item_tree.top_level_items());
|
||||
|
|
@ -376,7 +376,7 @@ impl DefCollector<'_> {
|
|||
macro_depth: 0,
|
||||
module_id: DefMap::ROOT,
|
||||
tree_id,
|
||||
item_tree: &item_tree,
|
||||
item_tree,
|
||||
mod_dir: ModDir::root(),
|
||||
}
|
||||
.collect_in_top_module(item_tree.top_level_items());
|
||||
|
|
@ -437,9 +437,8 @@ impl DefCollector<'_> {
|
|||
// 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 module_id = self.def_map.module_id(DefMap::ROOT);
|
||||
let root = &mut self.def_map.modules[DefMap::ROOT];
|
||||
root.scope.censor_non_proc_macros(module_id);
|
||||
root.scope.censor_non_proc_macros(self.def_map.krate);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -459,7 +458,7 @@ impl DefCollector<'_> {
|
|||
self.unresolved_macros.iter().enumerate().find_map(|(idx, directive)| match &directive
|
||||
.kind
|
||||
{
|
||||
MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree } => {
|
||||
MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree, item_tree } => {
|
||||
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
||||
directive.module_id,
|
||||
MacroCallKind::Attr {
|
||||
|
|
@ -470,16 +469,22 @@ impl DefCollector<'_> {
|
|||
attr.path().clone(),
|
||||
));
|
||||
|
||||
self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), attr.id);
|
||||
self.skip_attrs.insert(ast_id.ast_id.with_value(mod_item.ast_id()), attr.id);
|
||||
|
||||
Some((idx, directive, *mod_item, *tree))
|
||||
Some((idx, directive, *mod_item, *tree, *item_tree))
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
match unresolved_attr {
|
||||
Some((pos, &MacroDirective { module_id, depth, container, .. }, mod_item, tree_id)) => {
|
||||
let item_tree = &tree_id.item_tree(self.db);
|
||||
Some((
|
||||
pos,
|
||||
&MacroDirective { module_id, depth, container, .. },
|
||||
mod_item,
|
||||
tree_id,
|
||||
item_tree,
|
||||
)) => {
|
||||
// FIXME: Remove this clone
|
||||
let mod_dir = self.mod_dirs[&module_id].clone();
|
||||
ModCollector {
|
||||
def_collector: self,
|
||||
|
|
@ -576,13 +581,7 @@ impl DefCollector<'_> {
|
|||
/// 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.
|
||||
fn export_proc_macro(
|
||||
&mut self,
|
||||
def: ProcMacroDef,
|
||||
id: ItemTreeId<item_tree::Function>,
|
||||
ast_id: AstId<ast::Fn>,
|
||||
fn_id: FunctionId,
|
||||
) {
|
||||
fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>, fn_id: FunctionId) {
|
||||
let kind = def.kind.to_basedb_kind();
|
||||
let (expander, kind) = match self.proc_macros.iter().find(|(n, _, _)| n == &def.name) {
|
||||
Some(_)
|
||||
|
|
@ -598,7 +597,7 @@ impl DefCollector<'_> {
|
|||
|
||||
let proc_macro_id = ProcMacroLoc {
|
||||
container: self.def_map.crate_root(),
|
||||
id,
|
||||
id: ast_id,
|
||||
expander,
|
||||
kind,
|
||||
edition: self.def_map.data.edition,
|
||||
|
|
@ -609,7 +608,7 @@ impl DefCollector<'_> {
|
|||
self.define_proc_macro(def.name.clone(), proc_macro_id);
|
||||
let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap();
|
||||
if let ProcMacroKind::Derive { helpers } = def.kind {
|
||||
crate_data.exported_derives.insert(self.db.macro_def(proc_macro_id.into()), helpers);
|
||||
crate_data.exported_derives.insert(proc_macro_id.into(), helpers);
|
||||
}
|
||||
crate_data.fn_proc_macro_mapping.insert(fn_id, proc_macro_id);
|
||||
}
|
||||
|
|
@ -887,9 +886,31 @@ impl DefCollector<'_> {
|
|||
let imp = ImportOrExternCrate::Import(ImportId { use_: id, idx: use_tree });
|
||||
tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
|
||||
|
||||
// `extern crate crate_name` things can be re-exported as `pub use crate_name`.
|
||||
// But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
|
||||
// or `pub use ::crate_name`.
|
||||
//
|
||||
// This has been historically allowed, but may be not allowed in future
|
||||
// https://github.com/rust-lang/rust/issues/127909
|
||||
if let Some(def) = def.types.as_mut() {
|
||||
let is_extern_crate_reimport_without_prefix = || {
|
||||
let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else {
|
||||
return false;
|
||||
};
|
||||
if kind == ImportKind::Glob {
|
||||
return false;
|
||||
}
|
||||
matches!(import.path.kind, PathKind::Plain | PathKind::SELF)
|
||||
&& import.path.segments().len() < 2
|
||||
};
|
||||
if is_extern_crate_reimport_without_prefix() {
|
||||
def.vis = vis;
|
||||
}
|
||||
}
|
||||
|
||||
self.update(module_id, &[(name.cloned(), def)], vis, Some(imp));
|
||||
}
|
||||
ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree } => {
|
||||
ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree, .. } => {
|
||||
tracing::debug!("glob import: {:?}", import);
|
||||
let glob = GlobId { use_: id, idx: use_tree };
|
||||
match def.take_types() {
|
||||
|
|
@ -973,12 +994,11 @@ impl DefCollector<'_> {
|
|||
Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
|
||||
cov_mark::hit!(glob_enum);
|
||||
// glob import from enum => just import all the variants
|
||||
let resolutions = self
|
||||
.db
|
||||
.enum_variants(e)
|
||||
let resolutions = e
|
||||
.enum_variants(self.db)
|
||||
.variants
|
||||
.iter()
|
||||
.map(|&(variant, ref name)| {
|
||||
.map(|&(variant, ref name, _)| {
|
||||
let res = PerNs::both(variant.into(), variant.into(), vis, None);
|
||||
(Some(name.clone()), res)
|
||||
})
|
||||
|
|
@ -1150,33 +1170,8 @@ impl DefCollector<'_> {
|
|||
vis: Visibility,
|
||||
def_import_type: Option<ImportOrExternCrate>,
|
||||
) -> bool {
|
||||
// `extern crate crate_name` things can be re-exported as `pub use crate_name`.
|
||||
// But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
|
||||
// or `pub use ::crate_name`.
|
||||
//
|
||||
// This has been historically allowed, but may be not allowed in future
|
||||
// https://github.com/rust-lang/rust/issues/127909
|
||||
if let Some(def) = defs.types.as_mut() {
|
||||
let is_extern_crate_reimport_without_prefix = || {
|
||||
let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else {
|
||||
return false;
|
||||
};
|
||||
let Some(ImportOrExternCrate::Import(id)) = def_import_type else {
|
||||
return false;
|
||||
};
|
||||
let use_id = id.use_.lookup(self.db).id;
|
||||
let item_tree = use_id.item_tree(self.db);
|
||||
let use_kind = item_tree[use_id.value].use_tree.kind();
|
||||
let UseTreeKind::Single { path, .. } = use_kind else {
|
||||
return false;
|
||||
};
|
||||
path.segments().len() < 2
|
||||
};
|
||||
if is_extern_crate_reimport_without_prefix() {
|
||||
def.vis = vis;
|
||||
} else {
|
||||
def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
|
||||
}
|
||||
def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
|
||||
}
|
||||
if let Some(def) = defs.values.as_mut() {
|
||||
def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
|
||||
|
|
@ -1259,7 +1254,7 @@ impl DefCollector<'_> {
|
|||
fn resolve_macros(&mut self) -> ReachedFixedPoint {
|
||||
let mut macros = mem::take(&mut self.unresolved_macros);
|
||||
let mut resolved = Vec::new();
|
||||
let mut push_resolved = |directive: &MacroDirective, call_id| {
|
||||
let mut push_resolved = |directive: &MacroDirective<'_>, call_id| {
|
||||
resolved.push((directive.module_id, directive.depth, directive.container, call_id));
|
||||
};
|
||||
|
||||
|
|
@ -1272,7 +1267,7 @@ impl DefCollector<'_> {
|
|||
let mut eager_callback_buffer = vec![];
|
||||
let mut res = ReachedFixedPoint::Yes;
|
||||
// Retain unresolved macros after this round of resolution.
|
||||
let mut retain = |directive: &MacroDirective| {
|
||||
let mut retain = |directive: &MacroDirective<'db>| {
|
||||
let subns = match &directive.kind {
|
||||
MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang,
|
||||
MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => {
|
||||
|
|
@ -1349,7 +1344,7 @@ impl DefCollector<'_> {
|
|||
// Record its helper attributes.
|
||||
if def_id.krate != self.def_map.krate {
|
||||
let def_map = crate_def_map(self.db, def_id.krate);
|
||||
if let Some(helpers) = def_map.data.exported_derives.get(&def_id) {
|
||||
if let Some(helpers) = def_map.data.exported_derives.get(¯o_id) {
|
||||
self.def_map
|
||||
.derive_helpers_in_scope
|
||||
.entry(ast_id.ast_id.map(|it| it.upcast()))
|
||||
|
|
@ -1367,22 +1362,29 @@ impl DefCollector<'_> {
|
|||
return Resolved::Yes;
|
||||
}
|
||||
}
|
||||
MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => {
|
||||
MacroDirectiveKind::Attr {
|
||||
ast_id: file_ast_id,
|
||||
mod_item,
|
||||
attr,
|
||||
tree,
|
||||
item_tree,
|
||||
} => {
|
||||
let &AstIdWithPath { ast_id, ref path } = file_ast_id;
|
||||
let file_id = ast_id.file_id;
|
||||
|
||||
let mut recollect_without = |collector: &mut Self| {
|
||||
// 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);
|
||||
collector
|
||||
.skip_attrs
|
||||
.insert(InFile::new(file_id, mod_item.ast_id()), attr.id);
|
||||
|
||||
let item_tree = tree.item_tree(self.db);
|
||||
ModCollector {
|
||||
def_collector: collector,
|
||||
macro_depth: directive.depth,
|
||||
module_id: directive.module_id,
|
||||
tree_id: *tree,
|
||||
item_tree: &item_tree,
|
||||
item_tree,
|
||||
mod_dir,
|
||||
}
|
||||
.collect(&[*mod_item], directive.container);
|
||||
|
|
@ -1435,11 +1437,10 @@ impl DefCollector<'_> {
|
|||
// normal (as that would just be an identity expansion with extra output)
|
||||
// Instead we treat derive attributes special and apply them separately.
|
||||
|
||||
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(),
|
||||
ModItemId::Struct(ast_id) => ast_id.upcast(),
|
||||
ModItemId::Union(ast_id) => ast_id.upcast(),
|
||||
ModItemId::Enum(ast_id) => ast_id.upcast(),
|
||||
_ => {
|
||||
let diag = DefDiagnostic::invalid_derive_target(
|
||||
directive.module_id,
|
||||
|
|
@ -1571,7 +1572,7 @@ impl DefCollector<'_> {
|
|||
macro_depth: depth,
|
||||
tree_id: TreeId::new(file_id, None),
|
||||
module_id,
|
||||
item_tree: &item_tree,
|
||||
item_tree,
|
||||
mod_dir,
|
||||
}
|
||||
.collect(item_tree.top_level_items(), container);
|
||||
|
|
@ -1672,22 +1673,22 @@ impl DefCollector<'_> {
|
|||
}
|
||||
|
||||
/// Walks a single module, populating defs, imports and macros
|
||||
struct ModCollector<'a, 'b> {
|
||||
def_collector: &'a mut DefCollector<'b>,
|
||||
struct ModCollector<'a, 'db> {
|
||||
def_collector: &'a mut DefCollector<'db>,
|
||||
macro_depth: usize,
|
||||
module_id: LocalModuleId,
|
||||
tree_id: TreeId,
|
||||
item_tree: &'a ItemTree,
|
||||
item_tree: &'db ItemTree,
|
||||
mod_dir: ModDir,
|
||||
}
|
||||
|
||||
impl ModCollector<'_, '_> {
|
||||
fn collect_in_top_module(&mut self, items: &[ModItem]) {
|
||||
fn collect_in_top_module(&mut self, items: &[ModItemId]) {
|
||||
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) {
|
||||
fn collect(&mut self, items: &[ModItemId], container: ItemContainerId) {
|
||||
let krate = self.def_collector.def_map.krate;
|
||||
let is_crate_root =
|
||||
self.module_id == DefMap::ROOT && self.def_collector.def_map.block.is_none();
|
||||
|
|
@ -1726,11 +1727,12 @@ impl ModCollector<'_, '_> {
|
|||
.unwrap_or(Visibility::Public)
|
||||
};
|
||||
|
||||
let mut process_mod_item = |item: ModItem| {
|
||||
let attrs = self.item_tree.attrs(db, krate, item.into());
|
||||
let mut process_mod_item = |item: ModItemId| {
|
||||
let attrs = self.item_tree.attrs(db, krate, item.ast_id());
|
||||
if let Some(cfg) = attrs.cfg() {
|
||||
if !self.is_cfg_enabled(&cfg) {
|
||||
self.emit_unconfigured_diagnostic(self.tree_id, item.into(), &cfg);
|
||||
let ast_id = item.ast_id().erase();
|
||||
self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1747,39 +1749,31 @@ impl ModCollector<'_, '_> {
|
|||
self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map);
|
||||
|
||||
match item {
|
||||
ModItem::Mod(m) => self.collect_module(m, &attrs),
|
||||
ModItem::Use(item_tree_id) => {
|
||||
let id = UseLoc {
|
||||
container: module,
|
||||
id: ItemTreeId::new(self.tree_id, item_tree_id),
|
||||
}
|
||||
.intern(db);
|
||||
ModItemId::Mod(m) => self.collect_module(m, &attrs),
|
||||
ModItemId::Use(item_tree_id) => {
|
||||
let id =
|
||||
UseLoc { container: module, id: InFile::new(self.file_id(), item_tree_id) }
|
||||
.intern(db);
|
||||
let is_prelude = attrs.by_key(sym::prelude_import).exists();
|
||||
Import::from_use(
|
||||
self.item_tree,
|
||||
ItemTreeId::new(self.tree_id, item_tree_id),
|
||||
id,
|
||||
is_prelude,
|
||||
|import| {
|
||||
self.def_collector.unresolved_imports.push(ImportDirective {
|
||||
module_id: self.module_id,
|
||||
import,
|
||||
status: PartialResolvedImport::Unresolved,
|
||||
});
|
||||
},
|
||||
)
|
||||
Import::from_use(self.item_tree, item_tree_id, id, is_prelude, |import| {
|
||||
self.def_collector.unresolved_imports.push(ImportDirective {
|
||||
module_id: self.module_id,
|
||||
import,
|
||||
status: PartialResolvedImport::Unresolved,
|
||||
});
|
||||
})
|
||||
}
|
||||
ModItem::ExternCrate(item_tree_id) => {
|
||||
ModItemId::ExternCrate(item_tree_id) => {
|
||||
let item_tree::ExternCrate { name, visibility, alias } =
|
||||
&self.item_tree[item_tree_id];
|
||||
|
||||
let id = ExternCrateLoc {
|
||||
container: module,
|
||||
id: ItemTreeId::new(self.tree_id, item_tree_id),
|
||||
id: InFile::new(self.tree_id.file_id(), item_tree_id),
|
||||
}
|
||||
.intern(db);
|
||||
def_map.modules[self.module_id].scope.define_extern_crate_decl(id);
|
||||
|
||||
let item_tree::ExternCrate { name, visibility, alias, ast_id } =
|
||||
&self.item_tree[item_tree_id];
|
||||
|
||||
let is_self = *name == sym::self_;
|
||||
let resolved = if is_self {
|
||||
cov_mark::hit!(extern_crate_self_as);
|
||||
|
|
@ -1838,15 +1832,15 @@ impl ModCollector<'_, '_> {
|
|||
self.def_collector.def_map.diagnostics.push(
|
||||
DefDiagnostic::unresolved_extern_crate(
|
||||
module_id,
|
||||
InFile::new(self.file_id(), *ast_id),
|
||||
InFile::new(self.file_id(), item_tree_id),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
ModItem::ExternBlock(block) => {
|
||||
ModItemId::ExternBlock(block) => {
|
||||
let extern_block_id = ExternBlockLoc {
|
||||
container: module,
|
||||
id: ItemTreeId::new(self.tree_id, block),
|
||||
id: InFile::new(self.file_id(), block),
|
||||
}
|
||||
.intern(db);
|
||||
self.def_collector.def_map.modules[self.module_id]
|
||||
|
|
@ -1857,19 +1851,20 @@ impl ModCollector<'_, '_> {
|
|||
ItemContainerId::ExternBlockId(extern_block_id),
|
||||
)
|
||||
}
|
||||
ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container),
|
||||
ModItem::MacroRules(id) => self.collect_macro_rules(id, module),
|
||||
ModItem::Macro2(id) => self.collect_macro_def(id, module),
|
||||
ModItem::Impl(imp) => {
|
||||
ModItemId::MacroCall(mac) => self.collect_macro_call(mac, container),
|
||||
ModItemId::MacroRules(id) => self.collect_macro_rules(id, module),
|
||||
ModItemId::Macro2(id) => self.collect_macro_def(id, module),
|
||||
ModItemId::Impl(imp) => {
|
||||
let impl_id =
|
||||
ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) }
|
||||
ImplLoc { container: module, id: InFile::new(self.file_id(), imp) }
|
||||
.intern(db);
|
||||
self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
|
||||
}
|
||||
ModItem::Function(id) => {
|
||||
ModItemId::Function(id) => {
|
||||
let it = &self.item_tree[id];
|
||||
let fn_id =
|
||||
FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
|
||||
FunctionLoc { container, id: InFile::new(self.tree_id.file_id(), id) }
|
||||
.intern(db);
|
||||
|
||||
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
|
||||
|
||||
|
|
@ -1880,8 +1875,7 @@ impl ModCollector<'_, '_> {
|
|||
if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
|
||||
self.def_collector.export_proc_macro(
|
||||
proc_macro,
|
||||
ItemTreeId::new(self.tree_id, id),
|
||||
InFile::new(self.file_id(), self.item_tree[id].ast_id()),
|
||||
InFile::new(self.file_id(), id),
|
||||
fn_id,
|
||||
);
|
||||
}
|
||||
|
|
@ -1889,13 +1883,13 @@ impl ModCollector<'_, '_> {
|
|||
|
||||
update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
|
||||
}
|
||||
ModItem::Struct(id) => {
|
||||
ModItemId::Struct(id) => {
|
||||
let it = &self.item_tree[id];
|
||||
|
||||
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
|
||||
update_def(
|
||||
self.def_collector,
|
||||
StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
|
||||
StructLoc { container: module, id: InFile::new(self.file_id(), id) }
|
||||
.intern(db)
|
||||
.into(),
|
||||
&it.name,
|
||||
|
|
@ -1903,13 +1897,13 @@ impl ModCollector<'_, '_> {
|
|||
!matches!(it.shape, FieldsShape::Record),
|
||||
);
|
||||
}
|
||||
ModItem::Union(id) => {
|
||||
ModItemId::Union(id) => {
|
||||
let it = &self.item_tree[id];
|
||||
|
||||
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
|
||||
update_def(
|
||||
self.def_collector,
|
||||
UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
|
||||
UnionLoc { container: module, id: InFile::new(self.file_id(), id) }
|
||||
.intern(db)
|
||||
.into(),
|
||||
&it.name,
|
||||
|
|
@ -1917,19 +1911,20 @@ impl ModCollector<'_, '_> {
|
|||
false,
|
||||
);
|
||||
}
|
||||
ModItem::Enum(id) => {
|
||||
ModItemId::Enum(id) => {
|
||||
let it = &self.item_tree[id];
|
||||
let enum_ =
|
||||
EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
|
||||
EnumLoc { container: module, id: InFile::new(self.tree_id.file_id(), id) }
|
||||
.intern(db);
|
||||
|
||||
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
|
||||
update_def(self.def_collector, enum_.into(), &it.name, vis, false);
|
||||
}
|
||||
ModItem::Const(id) => {
|
||||
ModItemId::Const(id) => {
|
||||
let it = &self.item_tree[id];
|
||||
let const_id =
|
||||
ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
|
||||
ConstLoc { container, id: InFile::new(self.tree_id.file_id(), id) }
|
||||
.intern(db);
|
||||
|
||||
match &it.name {
|
||||
Some(name) => {
|
||||
|
|
@ -1945,13 +1940,13 @@ impl ModCollector<'_, '_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ModItem::Static(id) => {
|
||||
ModItemId::Static(id) => {
|
||||
let it = &self.item_tree[id];
|
||||
|
||||
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
|
||||
update_def(
|
||||
self.def_collector,
|
||||
StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
|
||||
StaticLoc { container, id: InFile::new(self.file_id(), id) }
|
||||
.intern(db)
|
||||
.into(),
|
||||
&it.name,
|
||||
|
|
@ -1959,13 +1954,13 @@ impl ModCollector<'_, '_> {
|
|||
false,
|
||||
);
|
||||
}
|
||||
ModItem::Trait(id) => {
|
||||
ModItemId::Trait(id) => {
|
||||
let it = &self.item_tree[id];
|
||||
|
||||
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
|
||||
update_def(
|
||||
self.def_collector,
|
||||
TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
|
||||
TraitLoc { container: module, id: InFile::new(self.file_id(), id) }
|
||||
.intern(db)
|
||||
.into(),
|
||||
&it.name,
|
||||
|
|
@ -1973,13 +1968,13 @@ impl ModCollector<'_, '_> {
|
|||
false,
|
||||
);
|
||||
}
|
||||
ModItem::TraitAlias(id) => {
|
||||
ModItemId::TraitAlias(id) => {
|
||||
let it = &self.item_tree[id];
|
||||
|
||||
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
|
||||
update_def(
|
||||
self.def_collector,
|
||||
TraitAliasLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
|
||||
TraitAliasLoc { container: module, id: InFile::new(self.file_id(), id) }
|
||||
.intern(db)
|
||||
.into(),
|
||||
&it.name,
|
||||
|
|
@ -1987,13 +1982,13 @@ impl ModCollector<'_, '_> {
|
|||
false,
|
||||
);
|
||||
}
|
||||
ModItem::TypeAlias(id) => {
|
||||
ModItemId::TypeAlias(id) => {
|
||||
let it = &self.item_tree[id];
|
||||
|
||||
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
|
||||
update_def(
|
||||
self.def_collector,
|
||||
TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
|
||||
TypeAliasLoc { container, id: InFile::new(self.file_id(), id) }
|
||||
.intern(db)
|
||||
.into(),
|
||||
&it.name,
|
||||
|
|
@ -2010,12 +2005,12 @@ impl ModCollector<'_, '_> {
|
|||
if is_crate_root {
|
||||
items
|
||||
.iter()
|
||||
.filter(|it| matches!(it, ModItem::ExternCrate(..)))
|
||||
.filter(|it| matches!(it, ModItemId::ExternCrate(..)))
|
||||
.copied()
|
||||
.for_each(&mut process_mod_item);
|
||||
items
|
||||
.iter()
|
||||
.filter(|it| !matches!(it, ModItem::ExternCrate(..)))
|
||||
.filter(|it| !matches!(it, ModItemId::ExternCrate(..)))
|
||||
.copied()
|
||||
.for_each(process_mod_item);
|
||||
} else {
|
||||
|
|
@ -2056,19 +2051,18 @@ impl ModCollector<'_, '_> {
|
|||
);
|
||||
}
|
||||
|
||||
fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
|
||||
fn collect_module(&mut self, module_ast_id: ItemTreeAstId<Mod>, attrs: &Attrs) {
|
||||
let path_attr = attrs.by_key(sym::path).string_value_unescape();
|
||||
let is_macro_use = attrs.by_key(sym::macro_use).exists();
|
||||
let module = &self.item_tree[module_id];
|
||||
let module = &self.item_tree[module_ast_id];
|
||||
match &module.kind {
|
||||
// inline module, just recurse
|
||||
ModKind::Inline { items } => {
|
||||
let module_id = self.push_child_module(
|
||||
module.name.clone(),
|
||||
module.ast_id,
|
||||
module_ast_id,
|
||||
None,
|
||||
&self.item_tree[module.visibility],
|
||||
module_id,
|
||||
);
|
||||
|
||||
let Some(mod_dir) =
|
||||
|
|
@ -2091,7 +2085,7 @@ impl ModCollector<'_, '_> {
|
|||
}
|
||||
// out of line module, resolve, parse and recurse
|
||||
ModKind::Outline => {
|
||||
let ast_id = AstId::new(self.file_id(), module.ast_id);
|
||||
let ast_id = AstId::new(self.file_id(), module_ast_id);
|
||||
let db = self.def_collector.db;
|
||||
match self.mod_dir.resolve_declaration(
|
||||
db,
|
||||
|
|
@ -2110,8 +2104,7 @@ impl ModCollector<'_, '_> {
|
|||
match is_enabled {
|
||||
Err(cfg) => {
|
||||
self.emit_unconfigured_diagnostic(
|
||||
self.tree_id,
|
||||
AttrOwner::ModItem(module_id.into()),
|
||||
InFile::new(self.file_id(), module_ast_id.erase()),
|
||||
&cfg,
|
||||
);
|
||||
}
|
||||
|
|
@ -2121,14 +2114,13 @@ impl ModCollector<'_, '_> {
|
|||
ast_id.value,
|
||||
Some((file_id, is_mod_rs)),
|
||||
&self.item_tree[module.visibility],
|
||||
module_id,
|
||||
);
|
||||
ModCollector {
|
||||
def_collector: self.def_collector,
|
||||
macro_depth: self.macro_depth,
|
||||
module_id,
|
||||
tree_id: TreeId::new(file_id.into(), None),
|
||||
item_tree: &item_tree,
|
||||
item_tree,
|
||||
mod_dir,
|
||||
}
|
||||
.collect_in_top_module(item_tree.top_level_items());
|
||||
|
|
@ -2149,7 +2141,6 @@ impl ModCollector<'_, '_> {
|
|||
ast_id.value,
|
||||
None,
|
||||
&self.item_tree[module.visibility],
|
||||
module_id,
|
||||
);
|
||||
self.def_collector.def_map.diagnostics.push(
|
||||
DefDiagnostic::unresolved_module(self.module_id, ast_id, candidates),
|
||||
|
|
@ -2166,7 +2157,6 @@ impl ModCollector<'_, '_> {
|
|||
declaration: FileAstId<ast::Module>,
|
||||
definition: Option<(EditionedFileId, bool)>,
|
||||
visibility: &crate::visibility::RawVisibility,
|
||||
mod_tree_id: FileItemTreeId<Mod>,
|
||||
) -> LocalModuleId {
|
||||
let def_map = &mut self.def_collector.def_map;
|
||||
let vis = def_map
|
||||
|
|
@ -2179,15 +2169,14 @@ impl ModCollector<'_, '_> {
|
|||
)
|
||||
.unwrap_or(Visibility::Public);
|
||||
let origin = match definition {
|
||||
None => ModuleOrigin::Inline {
|
||||
definition: declaration,
|
||||
definition_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
|
||||
},
|
||||
None => {
|
||||
ModuleOrigin::Inline { definition: declaration, definition_tree_id: self.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),
|
||||
declaration_tree_id: self.tree_id,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -2228,11 +2217,14 @@ impl ModCollector<'_, '_> {
|
|||
fn resolve_attributes(
|
||||
&mut self,
|
||||
attrs: &Attrs,
|
||||
mod_item: ModItem,
|
||||
mod_item: ModItemId,
|
||||
container: ItemContainerId,
|
||||
) -> Result<(), ()> {
|
||||
let mut ignore_up_to =
|
||||
self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied();
|
||||
let mut ignore_up_to = self
|
||||
.def_collector
|
||||
.skip_attrs
|
||||
.get(&InFile::new(self.file_id(), mod_item.ast_id()))
|
||||
.copied();
|
||||
let iter = attrs
|
||||
.iter()
|
||||
.dedup_by(|a, b| {
|
||||
|
|
@ -2262,11 +2254,7 @@ impl ModCollector<'_, '_> {
|
|||
attr.path.display(self.def_collector.db, Edition::LATEST)
|
||||
);
|
||||
|
||||
let ast_id = AstIdWithPath::new(
|
||||
self.file_id(),
|
||||
mod_item.ast_id(self.item_tree),
|
||||
attr.path.clone(),
|
||||
);
|
||||
let ast_id = AstIdWithPath::new(self.file_id(), mod_item.ast_id(), attr.path.clone());
|
||||
self.def_collector.unresolved_macros.push(MacroDirective {
|
||||
module_id: self.module_id,
|
||||
depth: self.macro_depth + 1,
|
||||
|
|
@ -2275,6 +2263,7 @@ impl ModCollector<'_, '_> {
|
|||
attr: attr.clone(),
|
||||
mod_item,
|
||||
tree: self.tree_id,
|
||||
item_tree: self.item_tree,
|
||||
},
|
||||
container,
|
||||
});
|
||||
|
|
@ -2285,11 +2274,11 @@ impl ModCollector<'_, '_> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>, module: ModuleId) {
|
||||
fn collect_macro_rules(&mut self, ast_id: ItemTreeAstId<MacroRules>, module: ModuleId) {
|
||||
let krate = self.def_collector.def_map.krate;
|
||||
let mac = &self.item_tree[id];
|
||||
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
|
||||
let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
|
||||
let mac = &self.item_tree[ast_id];
|
||||
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ast_id.upcast());
|
||||
let f_ast_id = InFile::new(self.file_id(), ast_id.upcast());
|
||||
|
||||
let export_attr = || attrs.by_key(sym::macro_export);
|
||||
|
||||
|
|
@ -2336,7 +2325,7 @@ impl ModCollector<'_, '_> {
|
|||
self.def_collector
|
||||
.def_map
|
||||
.diagnostics
|
||||
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
|
||||
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, f_ast_id));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -2352,16 +2341,13 @@ impl ModCollector<'_, '_> {
|
|||
|
||||
let macro_id = MacroRulesLoc {
|
||||
container: module,
|
||||
id: ItemTreeId::new(self.tree_id, id),
|
||||
id: InFile::new(self.file_id(), ast_id),
|
||||
flags,
|
||||
expander,
|
||||
edition: self.def_collector.def_map.data.edition,
|
||||
}
|
||||
.intern(self.def_collector.db);
|
||||
self.def_collector.def_map.macro_def_to_macro_id.insert(
|
||||
InFile::new(self.file_id(), self.item_tree[id].ast_id()).erase(),
|
||||
macro_id.into(),
|
||||
);
|
||||
self.def_collector.def_map.macro_def_to_macro_id.insert(f_ast_id.erase(), macro_id.into());
|
||||
self.def_collector.define_macro_rules(
|
||||
self.module_id,
|
||||
mac.name.clone(),
|
||||
|
|
@ -2370,14 +2356,14 @@ impl ModCollector<'_, '_> {
|
|||
);
|
||||
}
|
||||
|
||||
fn collect_macro_def(&mut self, id: FileItemTreeId<Macro2>, module: ModuleId) {
|
||||
fn collect_macro_def(&mut self, ast_id: ItemTreeAstId<Macro2>, module: ModuleId) {
|
||||
let krate = self.def_collector.def_map.krate;
|
||||
let mac = &self.item_tree[id];
|
||||
let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
|
||||
let mac = &self.item_tree[ast_id];
|
||||
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ast_id.upcast());
|
||||
let f_ast_id = InFile::new(self.file_id(), ast_id.upcast());
|
||||
|
||||
// Case 1: builtin macros
|
||||
let mut helpers_opt = None;
|
||||
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
|
||||
let expander = if attrs.by_key(sym::rustc_builtin_macro).exists() {
|
||||
if let Some(expander) = find_builtin_macro(&mac.name) {
|
||||
match expander {
|
||||
|
|
@ -2409,7 +2395,7 @@ impl ModCollector<'_, '_> {
|
|||
self.def_collector
|
||||
.def_map
|
||||
.diagnostics
|
||||
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
|
||||
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, f_ast_id));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -2420,16 +2406,13 @@ impl ModCollector<'_, '_> {
|
|||
|
||||
let macro_id = Macro2Loc {
|
||||
container: module,
|
||||
id: ItemTreeId::new(self.tree_id, id),
|
||||
id: InFile::new(self.file_id(), ast_id),
|
||||
expander,
|
||||
allow_internal_unsafe,
|
||||
edition: self.def_collector.def_map.data.edition,
|
||||
}
|
||||
.intern(self.def_collector.db);
|
||||
self.def_collector.def_map.macro_def_to_macro_id.insert(
|
||||
InFile::new(self.file_id(), self.item_tree[id].ast_id()).erase(),
|
||||
macro_id.into(),
|
||||
);
|
||||
self.def_collector.def_map.macro_def_to_macro_id.insert(f_ast_id.erase(), macro_id.into());
|
||||
self.def_collector.define_macro_def(
|
||||
self.module_id,
|
||||
mac.name.clone(),
|
||||
|
|
@ -2441,16 +2424,17 @@ impl ModCollector<'_, '_> {
|
|||
Arc::get_mut(&mut self.def_collector.def_map.data)
|
||||
.unwrap()
|
||||
.exported_derives
|
||||
.insert(self.def_collector.db.macro_def(macro_id.into()), helpers);
|
||||
.insert(macro_id.into(), helpers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_macro_call(
|
||||
&mut self,
|
||||
&MacroCall { ref path, ast_id, expand_to, ctxt }: &MacroCall,
|
||||
ast_id: FileAstId<ast::MacroCall>,
|
||||
container: ItemContainerId,
|
||||
) {
|
||||
let &MacroCall { ref path, expand_to, ctxt } = &self.item_tree[ast_id];
|
||||
let ast_id = AstIdWithPath::new(self.file_id(), ast_id, path.clone());
|
||||
let db = self.def_collector.db;
|
||||
|
||||
|
|
@ -2565,16 +2549,16 @@ impl ModCollector<'_, '_> {
|
|||
self.def_collector.cfg_options.check(cfg) != Some(false)
|
||||
}
|
||||
|
||||
fn emit_unconfigured_diagnostic(&mut self, tree_id: TreeId, item: AttrOwner, cfg: &CfgExpr) {
|
||||
fn emit_unconfigured_diagnostic(&mut self, ast_id: ErasedAstId, cfg: &CfgExpr) {
|
||||
self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
|
||||
self.module_id,
|
||||
tree_id,
|
||||
item,
|
||||
ast_id,
|
||||
cfg.clone(),
|
||||
self.def_collector.cfg_options.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn file_id(&self) -> HirFileId {
|
||||
self.tree_id.file_id()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,22 +3,18 @@
|
|||
use std::ops::Not;
|
||||
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
use hir_expand::{ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath};
|
||||
use hir_expand::{ErasedAstId, ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath};
|
||||
use la_arena::Idx;
|
||||
use syntax::ast;
|
||||
|
||||
use crate::{
|
||||
AstId,
|
||||
item_tree::{self, AttrOwner, ItemTreeId, TreeId},
|
||||
nameres::LocalModuleId,
|
||||
};
|
||||
use crate::{AstId, nameres::LocalModuleId};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum DefDiagnosticKind {
|
||||
UnresolvedModule { ast: AstId<ast::Module>, candidates: Box<[String]> },
|
||||
UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
|
||||
UnresolvedImport { id: ItemTreeId<item_tree::Use>, index: Idx<ast::UseTree> },
|
||||
UnconfiguredCode { tree: TreeId, item: AttrOwner, cfg: CfgExpr, opts: CfgOptions },
|
||||
UnresolvedImport { id: AstId<ast::Use>, index: Idx<ast::UseTree> },
|
||||
UnconfiguredCode { ast_id: ErasedAstId, cfg: CfgExpr, opts: CfgOptions },
|
||||
UnresolvedMacroCall { ast: MacroCallKind, path: ModPath },
|
||||
UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
|
||||
InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
|
||||
|
|
@ -28,7 +24,7 @@ pub enum DefDiagnosticKind {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct DefDiagnostics(Option<triomphe::Arc<Box<[DefDiagnostic]>>>);
|
||||
pub struct DefDiagnostics(Option<triomphe::ThinArc<(), DefDiagnostic>>);
|
||||
|
||||
impl DefDiagnostics {
|
||||
pub fn new(diagnostics: Vec<DefDiagnostic>) -> Self {
|
||||
|
|
@ -36,12 +32,12 @@ impl DefDiagnostics {
|
|||
diagnostics
|
||||
.is_empty()
|
||||
.not()
|
||||
.then(|| triomphe::Arc::new(diagnostics.into_boxed_slice())),
|
||||
.then(|| triomphe::ThinArc::from_header_and_iter((), diagnostics.into_iter())),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &DefDiagnostic> {
|
||||
self.0.as_ref().into_iter().flat_map(|it| &***it)
|
||||
self.0.as_ref().into_iter().flat_map(|it| &it.slice)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +71,7 @@ impl DefDiagnostic {
|
|||
|
||||
pub(super) fn unresolved_import(
|
||||
container: LocalModuleId,
|
||||
id: ItemTreeId<item_tree::Use>,
|
||||
id: AstId<ast::Use>,
|
||||
index: Idx<ast::UseTree>,
|
||||
) -> Self {
|
||||
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } }
|
||||
|
|
@ -92,14 +88,13 @@ impl DefDiagnostic {
|
|||
|
||||
pub fn unconfigured_code(
|
||||
container: LocalModuleId,
|
||||
tree: TreeId,
|
||||
item: AttrOwner,
|
||||
ast_id: ErasedAstId,
|
||||
cfg: CfgExpr,
|
||||
opts: CfgOptions,
|
||||
) -> Self {
|
||||
Self {
|
||||
in_module: container,
|
||||
kind: DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts },
|
||||
kind: DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
use either::Either;
|
||||
use hir_expand::{
|
||||
Lookup,
|
||||
mod_path::{ModPath, PathKind},
|
||||
name::Name,
|
||||
};
|
||||
|
|
@ -107,7 +106,7 @@ impl DefMap {
|
|||
visibility: &RawVisibility,
|
||||
within_impl: bool,
|
||||
) -> Option<Visibility> {
|
||||
let mut vis = match visibility {
|
||||
let vis = match visibility {
|
||||
RawVisibility::Module(path, explicitness) => {
|
||||
let (result, remaining) = self.resolve_path(
|
||||
local_def_map,
|
||||
|
|
@ -121,29 +120,36 @@ impl DefMap {
|
|||
return None;
|
||||
}
|
||||
let types = result.take_types()?;
|
||||
match types {
|
||||
let mut vis = match types {
|
||||
ModuleDefId::ModuleId(m) => Visibility::Module(m, *explicitness),
|
||||
// error: visibility needs to refer to module
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
// In block expressions, `self` normally refers to the containing non-block module, and
|
||||
// `super` to its parent (etc.). However, visibilities must only refer to a module in the
|
||||
// DefMap they're written in, so we restrict them when that happens.
|
||||
if let Visibility::Module(m, mv) = vis {
|
||||
// ...unless we're resolving visibility for an associated item in an impl.
|
||||
if self.block_id() != m.block && !within_impl {
|
||||
vis = Visibility::Module(self.module_id(Self::ROOT), mv);
|
||||
tracing::debug!(
|
||||
"visibility {:?} points outside DefMap, adjusting to {:?}",
|
||||
m,
|
||||
vis
|
||||
);
|
||||
}
|
||||
}
|
||||
vis
|
||||
}
|
||||
RawVisibility::PubSelf(explicitness) => {
|
||||
Visibility::Module(self.module_id(original_module), *explicitness)
|
||||
}
|
||||
RawVisibility::Public => Visibility::Public,
|
||||
RawVisibility::PubCrate => Visibility::PubCrate(self.krate),
|
||||
};
|
||||
|
||||
// In block expressions, `self` normally refers to the containing non-block module, and
|
||||
// `super` to its parent (etc.). However, visibilities must only refer to a module in the
|
||||
// DefMap they're written in, so we restrict them when that happens.
|
||||
if let Visibility::Module(m, mv) = vis {
|
||||
// ...unless we're resolving visibility for an associated item in an impl.
|
||||
if self.block_id() != m.block && !within_impl {
|
||||
cov_mark::hit!(adjust_vis_in_block_def_map);
|
||||
vis = Visibility::Module(self.module_id(Self::ROOT), mv);
|
||||
tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
|
||||
}
|
||||
}
|
||||
|
||||
Some(vis)
|
||||
}
|
||||
|
||||
|
|
@ -529,23 +535,22 @@ impl DefMap {
|
|||
// enum variant
|
||||
cov_mark::hit!(can_import_enum_variant);
|
||||
|
||||
let res =
|
||||
db.enum_variants(e).variants.iter().find(|(_, name)| name == segment).map(
|
||||
|&(variant, _)| {
|
||||
let item_tree_id = variant.lookup(db).id;
|
||||
match item_tree_id.item_tree(db)[item_tree_id.value].shape {
|
||||
FieldsShape::Record => {
|
||||
PerNs::types(variant.into(), Visibility::Public, None)
|
||||
}
|
||||
FieldsShape::Tuple | FieldsShape::Unit => PerNs::both(
|
||||
variant.into(),
|
||||
variant.into(),
|
||||
Visibility::Public,
|
||||
None,
|
||||
),
|
||||
}
|
||||
},
|
||||
);
|
||||
let res = e
|
||||
.enum_variants(db)
|
||||
.variants
|
||||
.iter()
|
||||
.find(|(_, name, _)| name == segment)
|
||||
.map(|&(variant, _, shape)| match shape {
|
||||
FieldsShape::Record => {
|
||||
PerNs::types(variant.into(), Visibility::Public, None)
|
||||
}
|
||||
FieldsShape::Tuple | FieldsShape::Unit => PerNs::both(
|
||||
variant.into(),
|
||||
variant.into(),
|
||||
Visibility::Public,
|
||||
None,
|
||||
),
|
||||
});
|
||||
// FIXME: Need to filter visibility here and below? Not sure.
|
||||
return match res {
|
||||
Some(res) => {
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ use base_db::{
|
|||
CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData,
|
||||
DependencyBuilder, Env, RootQueryDb, SourceDatabase,
|
||||
};
|
||||
use expect_test::{Expect, expect};
|
||||
use intern::Symbol;
|
||||
use span::Edition;
|
||||
use test_fixture::WithFixture;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
AdtId, ModuleDefId,
|
||||
db::DefDatabase,
|
||||
nameres::{crate_def_map, tests::TestDB},
|
||||
};
|
||||
|
|
@ -16,29 +16,29 @@ use crate::{
|
|||
fn check_def_map_is_not_recomputed(
|
||||
#[rust_analyzer::rust_fixture] ra_fixture_initial: &str,
|
||||
#[rust_analyzer::rust_fixture] ra_fixture_change: &str,
|
||||
expecta: Expect,
|
||||
expectb: Expect,
|
||||
) {
|
||||
let (mut db, pos) = TestDB::with_position(ra_fixture_initial);
|
||||
let krate = db.fetch_test_crate();
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
crate_def_map(&db, krate);
|
||||
});
|
||||
assert!(
|
||||
format!("{events:?}").contains("crate_local_def_map"),
|
||||
"no crate def map computed:\n{events:#?}",
|
||||
)
|
||||
}
|
||||
},
|
||||
&[],
|
||||
expecta,
|
||||
);
|
||||
db.set_file_text(pos.file_id.file_id(&db), ra_fixture_change);
|
||||
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
crate_def_map(&db, krate);
|
||||
});
|
||||
assert!(
|
||||
!format!("{events:?}").contains("crate_local_def_map"),
|
||||
"crate def map invalidated:\n{events:#?}",
|
||||
)
|
||||
}
|
||||
},
|
||||
&[("crate_local_def_map", 0)],
|
||||
expectb,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -104,15 +104,20 @@ pub const BAZ: u32 = 0;
|
|||
Arc::ptr_eq(&all_crates_before, &all_crates_after),
|
||||
"the all_crates list should not have been invalidated"
|
||||
);
|
||||
|
||||
let events = db.log_executed(|| {
|
||||
for &krate in db.all_crates().iter() {
|
||||
crate_def_map(&db, krate);
|
||||
}
|
||||
});
|
||||
let invalidated_def_maps =
|
||||
events.iter().filter(|event| event.contains("crate_local_def_map")).count();
|
||||
assert_eq!(invalidated_def_maps, 1, "{events:#?}")
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
for &krate in db.all_crates().iter() {
|
||||
crate_def_map(&db, krate);
|
||||
}
|
||||
},
|
||||
&[("crate_local_def_map", 1)],
|
||||
expect![[r#"
|
||||
[
|
||||
"crate_local_def_map",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -152,6 +157,33 @@ fn foo() -> i32 { 92 }
|
|||
#[cfg(never)]
|
||||
fn no() {}
|
||||
",
|
||||
expect![[r#"
|
||||
[
|
||||
"crate_local_def_map",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"of_",
|
||||
]
|
||||
"#]],
|
||||
expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"of_",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -183,6 +215,41 @@ m!(Y);
|
|||
|
||||
pub struct S {}
|
||||
",
|
||||
expect![[r#"
|
||||
[
|
||||
"crate_local_def_map",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"macro_def_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_macro_expansion_shim",
|
||||
"macro_arg_shim",
|
||||
"decl_macro_expander_shim",
|
||||
]
|
||||
"#]],
|
||||
expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"macro_arg_shim",
|
||||
"parse_macro_expansion_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -206,6 +273,49 @@ fn f() {}
|
|||
#[proc_macros::identity]
|
||||
fn f() { foo }
|
||||
",
|
||||
expect![[r#"
|
||||
[
|
||||
"crate_local_def_map",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"crate_local_def_map",
|
||||
"proc_macros_for_crate_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"macro_def_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_macro_expansion_shim",
|
||||
"expand_proc_macro_shim",
|
||||
"macro_arg_shim",
|
||||
"proc_macro_span_shim",
|
||||
]
|
||||
"#]],
|
||||
expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"macro_arg_shim",
|
||||
"expand_proc_macro_shim",
|
||||
"parse_macro_expansion_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -287,6 +397,60 @@ m2!(X);
|
|||
#[derive(proc_macros::DeriveIdentity)]
|
||||
pub struct S {}
|
||||
",
|
||||
expect![[r#"
|
||||
[
|
||||
"crate_local_def_map",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"macro_def_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_macro_expansion_shim",
|
||||
"macro_arg_shim",
|
||||
"decl_macro_expander_shim",
|
||||
"macro_def_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_macro_expansion_shim",
|
||||
"macro_arg_shim",
|
||||
"decl_macro_expander_shim",
|
||||
"crate_local_def_map",
|
||||
"proc_macros_for_crate_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"macro_def_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_macro_expansion_shim",
|
||||
"expand_proc_macro_shim",
|
||||
"macro_arg_shim",
|
||||
"proc_macro_span_shim",
|
||||
]
|
||||
"#]],
|
||||
expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"macro_arg_shim",
|
||||
"macro_arg_shim",
|
||||
"decl_macro_expander_shim",
|
||||
"macro_arg_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -341,19 +505,46 @@ m!(Z);
|
|||
"#,
|
||||
);
|
||||
let krate = db.test_crate();
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let crate_def_map = crate_def_map(&db, krate);
|
||||
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
|
||||
assert_eq!(module_data.scope.resolutions().count(), 4);
|
||||
});
|
||||
let n_recalculated_item_trees =
|
||||
events.iter().filter(|it| it.contains("file_item_tree_shim")).count();
|
||||
assert_eq!(n_recalculated_item_trees, 6);
|
||||
let n_reparsed_macros =
|
||||
events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count();
|
||||
assert_eq!(n_reparsed_macros, 3);
|
||||
}
|
||||
},
|
||||
&[("file_item_tree_query", 6), ("parse_macro_expansion_shim", 3)],
|
||||
expect![[r#"
|
||||
[
|
||||
"crate_local_def_map",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"macro_def_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_macro_expansion_shim",
|
||||
"macro_arg_shim",
|
||||
"decl_macro_expander_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_macro_expansion_shim",
|
||||
"macro_arg_shim",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_macro_expansion_shim",
|
||||
"macro_arg_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
|
||||
let new_text = r#"
|
||||
m!(X);
|
||||
|
|
@ -363,28 +554,31 @@ m!(Z);
|
|||
"#;
|
||||
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
||||
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let crate_def_map = crate_def_map(&db, krate);
|
||||
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
|
||||
assert_eq!(module_data.scope.resolutions().count(), 4);
|
||||
});
|
||||
let n_recalculated_item_trees =
|
||||
events.iter().filter(|it| it.contains("file_item_tree_shim")).count();
|
||||
assert_eq!(n_recalculated_item_trees, 1, "{events:#?}");
|
||||
let n_reparsed_macros =
|
||||
events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count();
|
||||
assert_eq!(n_reparsed_macros, 0);
|
||||
}
|
||||
},
|
||||
&[("file_item_tree_query", 1), ("parse_macro_expansion_shim", 0)],
|
||||
expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"macro_arg_shim",
|
||||
"macro_arg_shim",
|
||||
"macro_arg_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn item_tree_prevents_reparsing() {
|
||||
// The `ItemTree` is used by both name resolution and the various queries in `adt.rs` and
|
||||
// `data.rs`. After computing the `ItemTree` and deleting the parse tree, we should be able to
|
||||
// run those other queries without triggering a reparse.
|
||||
|
||||
let (db, pos) = TestDB::with_position(
|
||||
let (mut db, pos) = TestDB::with_position(
|
||||
r#"
|
||||
pub struct S;
|
||||
pub union U {}
|
||||
|
|
@ -399,53 +593,54 @@ pub static ST: u8 = 0;
|
|||
pub type Ty = ();
|
||||
"#,
|
||||
);
|
||||
let krate = db.test_crate();
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
db.file_item_tree(pos.file_id.into());
|
||||
});
|
||||
let n_calculated_item_trees =
|
||||
events.iter().filter(|it| it.contains("file_item_tree_shim")).count();
|
||||
assert_eq!(n_calculated_item_trees, 1);
|
||||
let n_parsed_files = events.iter().filter(|it| it.contains("parse")).count();
|
||||
assert_eq!(n_parsed_files, 1);
|
||||
}
|
||||
},
|
||||
&[("file_item_tree_query", 1), ("parse", 1)],
|
||||
expect![[r#"
|
||||
[
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
|
||||
// FIXME(salsa-transition): bring this back
|
||||
// base_db::ParseQuery.in_db(&db).purge();
|
||||
let file_id = pos.file_id.file_id(&db);
|
||||
let file_text = db.file_text(file_id).text(&db);
|
||||
db.set_file_text(file_id, &format!("{file_text}\n"));
|
||||
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
let crate_def_map = crate_def_map(&db, krate);
|
||||
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
|
||||
assert_eq!(module_data.scope.resolutions().count(), 8);
|
||||
assert_eq!(module_data.scope.impls().count(), 1);
|
||||
|
||||
for imp in module_data.scope.impls() {
|
||||
db.impl_signature(imp);
|
||||
}
|
||||
|
||||
for (_, res) in module_data.scope.resolutions() {
|
||||
match res.values.map(|it| it.def).or(res.types.map(|it| it.def)).unwrap() {
|
||||
ModuleDefId::FunctionId(f) => _ = db.function_signature(f),
|
||||
ModuleDefId::AdtId(adt) => match adt {
|
||||
AdtId::StructId(it) => _ = db.struct_signature(it),
|
||||
AdtId::UnionId(it) => _ = db.union_signature(it),
|
||||
AdtId::EnumId(it) => _ = db.enum_signature(it),
|
||||
},
|
||||
ModuleDefId::ConstId(it) => _ = db.const_signature(it),
|
||||
ModuleDefId::StaticId(it) => _ = db.static_signature(it),
|
||||
ModuleDefId::TraitId(it) => _ = db.trait_signature(it),
|
||||
ModuleDefId::TraitAliasId(it) => _ = db.trait_alias_signature(it),
|
||||
ModuleDefId::TypeAliasId(it) => _ = db.type_alias_signature(it),
|
||||
ModuleDefId::EnumVariantId(_)
|
||||
| ModuleDefId::ModuleId(_)
|
||||
| ModuleDefId::MacroId(_)
|
||||
| ModuleDefId::BuiltinType(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
});
|
||||
let n_reparsed_files = events.iter().filter(|it| it.contains("parse(")).count();
|
||||
assert_eq!(n_reparsed_files, 0);
|
||||
}
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
db.file_item_tree(pos.file_id.into());
|
||||
},
|
||||
&[("file_item_tree_query", 1), ("parse", 1)],
|
||||
expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
fn execute_assert_events(
|
||||
db: &TestDB,
|
||||
f: impl FnOnce(),
|
||||
required: &[(&str, usize)],
|
||||
expect: Expect,
|
||||
) {
|
||||
let events = db.log_executed(f);
|
||||
for (event, count) in required {
|
||||
let n = events.iter().filter(|it| it.contains(event)).count();
|
||||
assert_eq!(n, *count, "Expected {event} to be executed {count} times, but only got {n}");
|
||||
}
|
||||
expect.assert_debug_eq(&events);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,21 +5,22 @@ use base_db::Crate;
|
|||
use hir_expand::{
|
||||
MacroDefId,
|
||||
mod_path::{ModPath, PathKind},
|
||||
name::Name,
|
||||
name::{AsName, Name},
|
||||
};
|
||||
use intern::{Symbol, sym};
|
||||
use itertools::Itertools as _;
|
||||
use rustc_hash::FxHashSet;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use span::SyntaxContext;
|
||||
use syntax::ast::HasName;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
|
||||
ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule,
|
||||
ImplId, ItemContainerId, ItemTreeLoc, LifetimeParamId, LocalModuleId, Lookup, Macro2Id,
|
||||
MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId,
|
||||
TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId,
|
||||
AdtId, AstIdLoc, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId,
|
||||
EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId,
|
||||
GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup,
|
||||
Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId,
|
||||
TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId,
|
||||
builtin_type::BuiltinType,
|
||||
db::DefDatabase,
|
||||
expr_store::{
|
||||
|
|
@ -32,10 +33,10 @@ use crate::{
|
|||
generics::{GenericParams, TypeOrConstParamData},
|
||||
},
|
||||
item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope},
|
||||
item_tree::ImportAlias,
|
||||
lang_item::LangItemTarget,
|
||||
nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map},
|
||||
per_ns::PerNs,
|
||||
src::HasSource,
|
||||
type_ref::LifetimeRef,
|
||||
visibility::{RawVisibility, Visibility},
|
||||
};
|
||||
|
|
@ -304,6 +305,10 @@ impl<'db> Resolver<'db> {
|
|||
}),
|
||||
)
|
||||
}
|
||||
RawVisibility::PubSelf(explicitness) => {
|
||||
Some(Visibility::Module(self.module(), *explicitness))
|
||||
}
|
||||
RawVisibility::PubCrate => Some(Visibility::PubCrate(self.krate())),
|
||||
RawVisibility::Public => Some(Visibility::Public),
|
||||
}
|
||||
}
|
||||
|
|
@ -627,14 +632,14 @@ impl<'db> Resolver<'db> {
|
|||
.extern_crate_decls()
|
||||
.filter_map(|id| {
|
||||
let loc = id.lookup(db);
|
||||
let tree = loc.item_tree_id().item_tree(db);
|
||||
match &tree[loc.id.value].alias {
|
||||
Some(alias) => match alias {
|
||||
ImportAlias::Underscore => None,
|
||||
ImportAlias::Alias(name) => Some(name.clone()),
|
||||
},
|
||||
None => Some(tree[loc.id.value].name.clone()),
|
||||
}
|
||||
let extern_crate = loc.source(db);
|
||||
// If there is a rename (`as x`), extract the renamed name, or remove the `extern crate`
|
||||
// if it is an underscore.
|
||||
extern_crate
|
||||
.value
|
||||
.rename()
|
||||
.map(|a| a.name().map(|it| it.as_name()))
|
||||
.unwrap_or_else(|| extern_crate.value.name_ref().map(|it| it.as_name()))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1471,10 +1476,7 @@ impl HasResolver for MacroRulesId {
|
|||
|
||||
fn lookup_resolver(
|
||||
db: &dyn DefDatabase,
|
||||
lookup: impl Lookup<
|
||||
Database = dyn DefDatabase,
|
||||
Data = impl ItemTreeLoc<Container = impl HasResolver>,
|
||||
>,
|
||||
lookup: impl Lookup<Database = dyn DefDatabase, Data = impl AstIdLoc<Container = impl HasResolver>>,
|
||||
) -> Resolver<'_> {
|
||||
lookup.lookup(db).container().resolver(db)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,21 +4,25 @@ use std::ops::Not as _;
|
|||
|
||||
use bitflags::bitflags;
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
use either::Either;
|
||||
use hir_expand::{InFile, Intern, Lookup, name::Name};
|
||||
use hir_expand::{
|
||||
InFile, Intern, Lookup,
|
||||
name::{AsName, Name},
|
||||
};
|
||||
use intern::{Symbol, sym};
|
||||
use la_arena::{Arena, Idx};
|
||||
use rustc_abi::{IntegerType, ReprOptions};
|
||||
use syntax::{
|
||||
AstNode, SyntaxNodePtr,
|
||||
ast::{self, HasGenericParams, IsString},
|
||||
NodeOrToken, SyntaxNodePtr, T,
|
||||
ast::{self, HasGenericParams, HasName, HasVisibility, IsString},
|
||||
};
|
||||
use thin_vec::ThinVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
ConstId, EnumId, EnumVariantId, EnumVariantLoc, FunctionId, HasModule, ImplId, ItemContainerId,
|
||||
ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, VariantId,
|
||||
ConstId, EnumId, EnumVariantId, EnumVariantLoc, ExternBlockId, FunctionId, HasModule, ImplId,
|
||||
ItemContainerId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId,
|
||||
VariantId,
|
||||
attr::Attrs,
|
||||
db::DefDatabase,
|
||||
expr_store::{
|
||||
ExpressionStore, ExpressionStoreSourceMap,
|
||||
|
|
@ -28,15 +32,17 @@ use crate::{
|
|||
},
|
||||
},
|
||||
hir::{ExprId, PatId, generics::GenericParams},
|
||||
item_tree::{
|
||||
AttrOwner, Field, FieldParent, FieldsShape, FileItemTreeId, ItemTree, ItemTreeId, ModItem,
|
||||
RawVisibility, RawVisibilityId,
|
||||
},
|
||||
item_tree::{FieldsShape, RawVisibility, visibility_from_ast},
|
||||
lang_item::LangItem,
|
||||
src::HasSource,
|
||||
type_ref::{TraitRef, TypeBound, TypeRefId},
|
||||
};
|
||||
|
||||
#[inline]
|
||||
fn as_name_opt(name: Option<ast::Name>) -> Name {
|
||||
name.map_or_else(Name::missing, |it| it.as_name())
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct StructSignature {
|
||||
pub name: Name,
|
||||
|
|
@ -70,8 +76,8 @@ bitflags! {
|
|||
impl StructSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: StructId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
|
||||
let InFile { file_id, value: source } = loc.source(db);
|
||||
let attrs = db.attrs(id.into());
|
||||
|
||||
let mut flags = StructFlags::empty();
|
||||
if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
|
|
@ -91,23 +97,23 @@ impl StructSignature {
|
|||
}
|
||||
}
|
||||
let repr = attrs.repr();
|
||||
let shape = adt_shape(source.kind());
|
||||
|
||||
let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
|
||||
let (store, generic_params, source_map) = lower_generic_params(
|
||||
db,
|
||||
loc.container,
|
||||
id.into(),
|
||||
file_id,
|
||||
value.generic_param_list(),
|
||||
value.where_clause(),
|
||||
source.generic_param_list(),
|
||||
source.where_clause(),
|
||||
);
|
||||
(
|
||||
Arc::new(StructSignature {
|
||||
generic_params,
|
||||
store,
|
||||
flags,
|
||||
shape: item_tree[loc.id.value].shape,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
shape,
|
||||
name: as_name_opt(source.name()),
|
||||
repr,
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
|
|
@ -115,6 +121,15 @@ impl StructSignature {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn adt_shape(adt_kind: ast::StructKind) -> FieldsShape {
|
||||
match adt_kind {
|
||||
ast::StructKind::Record(_) => FieldsShape::Record,
|
||||
ast::StructKind::Tuple(_) => FieldsShape::Tuple,
|
||||
ast::StructKind::Unit => FieldsShape::Unit,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct UnionSignature {
|
||||
pub name: Name,
|
||||
|
|
@ -127,9 +142,7 @@ pub struct UnionSignature {
|
|||
impl UnionSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: UnionId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let krate = loc.container.krate;
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
|
||||
let attrs = db.attrs(id.into());
|
||||
let mut flags = StructFlags::empty();
|
||||
if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
flags |= StructFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
|
||||
|
|
@ -140,14 +153,14 @@ impl UnionSignature {
|
|||
|
||||
let repr = attrs.repr();
|
||||
|
||||
let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
|
||||
let InFile { file_id, value: source } = loc.source(db);
|
||||
let (store, generic_params, source_map) = lower_generic_params(
|
||||
db,
|
||||
loc.container,
|
||||
id.into(),
|
||||
file_id,
|
||||
value.generic_param_list(),
|
||||
value.where_clause(),
|
||||
source.generic_param_list(),
|
||||
source.where_clause(),
|
||||
);
|
||||
(
|
||||
Arc::new(UnionSignature {
|
||||
|
|
@ -155,7 +168,7 @@ impl UnionSignature {
|
|||
store,
|
||||
flags,
|
||||
repr,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
name: as_name_opt(source.name()),
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
|
|
@ -181,8 +194,7 @@ pub struct EnumSignature {
|
|||
impl EnumSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: EnumId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
|
||||
let attrs = db.attrs(id.into());
|
||||
let mut flags = EnumFlags::empty();
|
||||
if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
flags |= EnumFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
|
||||
|
|
@ -190,14 +202,14 @@ impl EnumSignature {
|
|||
|
||||
let repr = attrs.repr();
|
||||
|
||||
let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
|
||||
let InFile { file_id, value: source } = loc.source(db);
|
||||
let (store, generic_params, source_map) = lower_generic_params(
|
||||
db,
|
||||
loc.container,
|
||||
id.into(),
|
||||
file_id,
|
||||
value.generic_param_list(),
|
||||
value.where_clause(),
|
||||
source.generic_param_list(),
|
||||
source.where_clause(),
|
||||
);
|
||||
|
||||
(
|
||||
|
|
@ -206,7 +218,7 @@ impl EnumSignature {
|
|||
store,
|
||||
flags,
|
||||
repr,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
name: as_name_opt(source.name()),
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
|
|
@ -239,10 +251,9 @@ pub struct ConstSignature {
|
|||
impl ConstSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: ConstId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let module = loc.container.module(db);
|
||||
let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
|
||||
let attrs = db.attrs(id.into());
|
||||
let mut flags = ConstFlags::empty();
|
||||
if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
|
||||
flags |= ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
|
||||
|
|
@ -253,14 +264,14 @@ impl ConstSignature {
|
|||
}
|
||||
|
||||
let (store, source_map, type_ref) =
|
||||
crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty()));
|
||||
crate::expr_store::lower::lower_type_ref(db, module, source.as_ref().map(|it| it.ty()));
|
||||
|
||||
(
|
||||
Arc::new(ConstSignature {
|
||||
store: Arc::new(store),
|
||||
type_ref,
|
||||
flags,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
name: source.value.name().map(|it| it.as_name()),
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
|
|
@ -295,10 +306,9 @@ pub struct StaticSignature {
|
|||
impl StaticSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: StaticId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let module = loc.container.module(db);
|
||||
let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
|
||||
let attrs = db.attrs(id.into());
|
||||
let mut flags = StaticFlags::empty();
|
||||
if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
|
||||
flags |= StaticFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
|
||||
|
|
@ -323,14 +333,14 @@ impl StaticSignature {
|
|||
}
|
||||
|
||||
let (store, source_map, type_ref) =
|
||||
crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty()));
|
||||
crate::expr_store::lower::lower_type_ref(db, module, source.as_ref().map(|it| it.ty()));
|
||||
|
||||
(
|
||||
Arc::new(StaticSignature {
|
||||
store: Arc::new(store),
|
||||
type_ref,
|
||||
flags,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
name: as_name_opt(source.value.name()),
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
|
|
@ -407,10 +417,9 @@ pub struct TraitSignature {
|
|||
impl TraitSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: TraitId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let mut flags = TraitFlags::empty();
|
||||
let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
|
||||
let attrs = db.attrs(id.into());
|
||||
let source = loc.source(db);
|
||||
if source.value.auto_token().is_some() {
|
||||
flags.insert(TraitFlags::AUTO);
|
||||
|
|
@ -446,15 +455,11 @@ impl TraitSignature {
|
|||
flags |= TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH;
|
||||
}
|
||||
|
||||
let name = as_name_opt(source.value.name());
|
||||
let (store, source_map, generic_params) = lower_trait(db, loc.container, source, id);
|
||||
|
||||
(
|
||||
Arc::new(TraitSignature {
|
||||
store: Arc::new(store),
|
||||
generic_params,
|
||||
flags,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
}),
|
||||
Arc::new(TraitSignature { store: Arc::new(store), generic_params, flags, name }),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
|
|
@ -473,17 +478,13 @@ impl TraitAliasSignature {
|
|||
id: TraitAliasId,
|
||||
) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let source = loc.source(db);
|
||||
let name = as_name_opt(source.value.name());
|
||||
let (store, source_map, generic_params) = lower_trait_alias(db, loc.container, source, id);
|
||||
|
||||
(
|
||||
Arc::new(TraitAliasSignature {
|
||||
generic_params,
|
||||
store: Arc::new(store),
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
}),
|
||||
Arc::new(TraitAliasSignature { generic_params, store: Arc::new(store), name }),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
|
|
@ -530,10 +531,9 @@ impl FunctionSignature {
|
|||
) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let module = loc.container.module(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let mut flags = FnFlags::empty();
|
||||
let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
|
||||
let attrs = db.attrs(id.into());
|
||||
if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
|
||||
flags.insert(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL);
|
||||
}
|
||||
|
|
@ -568,6 +568,7 @@ impl FunctionSignature {
|
|||
flags.insert(FnFlags::HAS_BODY);
|
||||
}
|
||||
|
||||
let name = as_name_opt(source.value.name());
|
||||
let abi = source.value.abi().map(|abi| {
|
||||
abi.abi_string().map_or_else(|| sym::C, |it| Symbol::intern(it.text_without_quotes()))
|
||||
});
|
||||
|
|
@ -588,7 +589,7 @@ impl FunctionSignature {
|
|||
abi,
|
||||
flags,
|
||||
legacy_const_generics_indices,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
name,
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
|
|
@ -662,14 +663,9 @@ impl TypeAliasSignature {
|
|||
id: TypeAliasId,
|
||||
) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let mut flags = TypeAliasFlags::empty();
|
||||
let attrs = item_tree.attrs(
|
||||
db,
|
||||
loc.container.module(db).krate(),
|
||||
ModItem::from(loc.id.value).into(),
|
||||
);
|
||||
let attrs = db.attrs(id.into());
|
||||
if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
flags.insert(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPL);
|
||||
}
|
||||
|
|
@ -680,6 +676,7 @@ impl TypeAliasSignature {
|
|||
flags.insert(TypeAliasFlags::IS_EXTERN);
|
||||
}
|
||||
let source = loc.source(db);
|
||||
let name = as_name_opt(source.value.name());
|
||||
let (store, source_map, generic_params, bounds, ty) =
|
||||
lower_type_alias(db, loc.container.module(db), source, id);
|
||||
|
||||
|
|
@ -689,7 +686,7 @@ impl TypeAliasSignature {
|
|||
generic_params,
|
||||
flags,
|
||||
bounds,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
name,
|
||||
ty,
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
|
|
@ -743,104 +740,41 @@ impl VariantFields {
|
|||
let (shape, (fields, store, source_map)) = match id {
|
||||
VariantId::EnumVariantId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let parent = loc.parent.lookup(db);
|
||||
let variant = &item_tree[loc.id.value];
|
||||
(
|
||||
variant.shape,
|
||||
lower_fields(
|
||||
db,
|
||||
parent.container,
|
||||
&item_tree,
|
||||
FieldParent::EnumVariant(loc.id.value),
|
||||
loc.source(db).map(|src| {
|
||||
variant.fields.iter().zip(
|
||||
src.field_list()
|
||||
.map(|it| {
|
||||
match it {
|
||||
ast::FieldList::RecordFieldList(record_field_list) => {
|
||||
Either::Left(record_field_list.fields().map(|it| {
|
||||
(SyntaxNodePtr::new(it.syntax()), it.ty())
|
||||
}))
|
||||
}
|
||||
ast::FieldList::TupleFieldList(field_list) => {
|
||||
Either::Right(field_list.fields().map(|it| {
|
||||
(SyntaxNodePtr::new(it.syntax()), it.ty())
|
||||
}))
|
||||
}
|
||||
}
|
||||
.into_iter()
|
||||
})
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
)
|
||||
}),
|
||||
Some(item_tree[parent.id.value].visibility),
|
||||
),
|
||||
)
|
||||
let source = loc.source(db);
|
||||
let shape = adt_shape(source.value.kind());
|
||||
let span_map = db.span_map(source.file_id);
|
||||
let override_visibility = visibility_from_ast(
|
||||
db,
|
||||
source.value.parent_enum().visibility(),
|
||||
&mut |range| span_map.span_for_range(range).ctx,
|
||||
);
|
||||
let fields = lower_field_list(
|
||||
db,
|
||||
parent.container,
|
||||
source.map(|src| src.field_list()),
|
||||
Some(override_visibility),
|
||||
);
|
||||
(shape, fields)
|
||||
}
|
||||
VariantId::StructId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let strukt = &item_tree[loc.id.value];
|
||||
(
|
||||
strukt.shape,
|
||||
lower_fields(
|
||||
db,
|
||||
loc.container,
|
||||
&item_tree,
|
||||
FieldParent::Struct(loc.id.value),
|
||||
loc.source(db).map(|src| {
|
||||
strukt.fields.iter().zip(
|
||||
src.field_list()
|
||||
.map(|it| {
|
||||
match it {
|
||||
ast::FieldList::RecordFieldList(record_field_list) => {
|
||||
Either::Left(record_field_list.fields().map(|it| {
|
||||
(SyntaxNodePtr::new(it.syntax()), it.ty())
|
||||
}))
|
||||
}
|
||||
ast::FieldList::TupleFieldList(field_list) => {
|
||||
Either::Right(field_list.fields().map(|it| {
|
||||
(SyntaxNodePtr::new(it.syntax()), it.ty())
|
||||
}))
|
||||
}
|
||||
}
|
||||
.into_iter()
|
||||
})
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
)
|
||||
}),
|
||||
None,
|
||||
),
|
||||
)
|
||||
let source = loc.source(db);
|
||||
let shape = adt_shape(source.value.kind());
|
||||
let fields =
|
||||
lower_field_list(db, loc.container, source.map(|src| src.field_list()), None);
|
||||
(shape, fields)
|
||||
}
|
||||
VariantId::UnionId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let union = &item_tree[loc.id.value];
|
||||
(
|
||||
FieldsShape::Record,
|
||||
lower_fields(
|
||||
db,
|
||||
loc.container,
|
||||
&item_tree,
|
||||
FieldParent::Union(loc.id.value),
|
||||
loc.source(db).map(|src| {
|
||||
union.fields.iter().zip(
|
||||
src.record_field_list()
|
||||
.map(|it| {
|
||||
it.fields()
|
||||
.map(|it| (SyntaxNodePtr::new(it.syntax()), it.ty()))
|
||||
})
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
)
|
||||
}),
|
||||
None,
|
||||
),
|
||||
)
|
||||
let source = loc.source(db);
|
||||
let fields = lower_field_list(
|
||||
db,
|
||||
loc.container,
|
||||
source.map(|src| src.record_field_list().map(ast::FieldList::RecordFieldList)),
|
||||
None,
|
||||
);
|
||||
(FieldsShape::Record, fields)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -860,39 +794,81 @@ impl VariantFields {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_fields<'a>(
|
||||
fn lower_field_list(
|
||||
db: &dyn DefDatabase,
|
||||
module: ModuleId,
|
||||
item_tree: &ItemTree,
|
||||
parent: FieldParent,
|
||||
fields: InFile<impl Iterator<Item = (&'a Field, (SyntaxNodePtr, Option<ast::Type>))>>,
|
||||
override_visibility: Option<RawVisibilityId>,
|
||||
fields: InFile<Option<ast::FieldList>>,
|
||||
override_visibility: Option<RawVisibility>,
|
||||
) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) {
|
||||
let file_id = fields.file_id;
|
||||
match fields.value {
|
||||
Some(ast::FieldList::RecordFieldList(fields)) => lower_fields(
|
||||
db,
|
||||
module,
|
||||
InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))),
|
||||
|_, field| as_name_opt(field.name()),
|
||||
override_visibility,
|
||||
),
|
||||
Some(ast::FieldList::TupleFieldList(fields)) => lower_fields(
|
||||
db,
|
||||
module,
|
||||
InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))),
|
||||
|idx, _| Name::new_tuple_field(idx),
|
||||
override_visibility,
|
||||
),
|
||||
None => lower_fields(
|
||||
db,
|
||||
module,
|
||||
InFile::new(file_id, std::iter::empty::<(Option<ast::Type>, ast::RecordField)>()),
|
||||
|_, _| Name::missing(),
|
||||
None,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>(
|
||||
db: &dyn DefDatabase,
|
||||
module: ModuleId,
|
||||
fields: InFile<impl Iterator<Item = (Option<ast::Type>, Field)>>,
|
||||
mut field_name: impl FnMut(usize, &Field) -> Name,
|
||||
override_visibility: Option<RawVisibility>,
|
||||
) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) {
|
||||
let mut arena = Arena::new();
|
||||
let cfg_options = module.krate.cfg_options(db);
|
||||
let mut col = ExprCollector::new(db, module, fields.file_id);
|
||||
for (idx, (field, (ptr, ty))) in fields.value.enumerate() {
|
||||
let attr_owner = AttrOwner::make_field_indexed(parent, idx);
|
||||
let attrs = item_tree.attrs(db, module.krate, attr_owner);
|
||||
if attrs.is_cfg_enabled(cfg_options) {
|
||||
arena.alloc(FieldData {
|
||||
name: field.name.clone(),
|
||||
type_ref: col
|
||||
.lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator),
|
||||
visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
|
||||
is_unsafe: field.is_unsafe,
|
||||
});
|
||||
} else {
|
||||
col.source_map.diagnostics.push(
|
||||
crate::expr_store::ExpressionStoreDiagnostics::InactiveCode {
|
||||
node: InFile::new(fields.file_id, ptr),
|
||||
cfg: attrs.cfg().unwrap(),
|
||||
opts: cfg_options.clone(),
|
||||
},
|
||||
);
|
||||
let mut idx = 0;
|
||||
for (ty, field) in fields.value {
|
||||
match Attrs::is_cfg_enabled_for(db, &field, col.span_map(), cfg_options) {
|
||||
Ok(()) => {
|
||||
let type_ref =
|
||||
col.lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator);
|
||||
let visibility = override_visibility.clone().unwrap_or_else(|| {
|
||||
visibility_from_ast(db, field.visibility(), &mut |range| {
|
||||
col.span_map().span_for_range(range).ctx
|
||||
})
|
||||
});
|
||||
let is_unsafe = field
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(NodeOrToken::into_token)
|
||||
.any(|token| token.kind() == T![unsafe]);
|
||||
let name = field_name(idx, &field);
|
||||
arena.alloc(FieldData { name, type_ref, visibility, is_unsafe });
|
||||
idx += 1;
|
||||
}
|
||||
Err(cfg) => {
|
||||
col.source_map.diagnostics.push(
|
||||
crate::expr_store::ExpressionStoreDiagnostics::InactiveCode {
|
||||
node: InFile::new(fields.file_id, SyntaxNodePtr::new(field.syntax())),
|
||||
cfg,
|
||||
opts: cfg_options.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
let store = col.store.finish();
|
||||
arena.shrink_to_fit();
|
||||
(arena, store, col.source_map)
|
||||
}
|
||||
|
||||
|
|
@ -905,56 +881,71 @@ pub struct InactiveEnumVariantCode {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EnumVariants {
|
||||
pub variants: Box<[(EnumVariantId, Name)]>,
|
||||
pub variants: Box<[(EnumVariantId, Name, FieldsShape)]>,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl EnumVariants {
|
||||
pub(crate) fn enum_variants_query(
|
||||
#[salsa::tracked(returns(ref))]
|
||||
pub(crate) fn of(
|
||||
db: &dyn DefDatabase,
|
||||
e: EnumId,
|
||||
) -> (Arc<EnumVariants>, Option<Arc<ThinVec<InactiveEnumVariantCode>>>) {
|
||||
) -> (EnumVariants, Option<ThinVec<InactiveEnumVariantCode>>) {
|
||||
let loc = e.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let source = loc.source(db);
|
||||
let ast_id_map = db.ast_id_map(source.file_id);
|
||||
let span_map = db.span_map(source.file_id);
|
||||
|
||||
let mut diagnostics = ThinVec::new();
|
||||
let cfg_options = loc.container.krate.cfg_options(db);
|
||||
let mut index = 0;
|
||||
let variants = FileItemTreeId::range_iter(item_tree[loc.id.value].variants.clone())
|
||||
let Some(variants) = source.value.variant_list() else {
|
||||
return (EnumVariants { variants: Box::default() }, None);
|
||||
};
|
||||
let variants = variants
|
||||
.variants()
|
||||
.filter_map(|variant| {
|
||||
let attrs = item_tree.attrs(db, loc.container.krate, variant.into());
|
||||
if attrs.is_cfg_enabled(cfg_options) {
|
||||
let enum_variant = EnumVariantLoc {
|
||||
id: ItemTreeId::new(loc.id.tree_id(), variant),
|
||||
parent: e,
|
||||
index,
|
||||
let ast_id = ast_id_map.ast_id(&variant);
|
||||
match Attrs::is_cfg_enabled_for(db, &variant, span_map.as_ref(), cfg_options) {
|
||||
Ok(()) => {
|
||||
let enum_variant =
|
||||
EnumVariantLoc { id: source.with_value(ast_id), parent: e, index }
|
||||
.intern(db);
|
||||
index += 1;
|
||||
let name = as_name_opt(variant.name());
|
||||
let shape = adt_shape(variant.kind());
|
||||
Some((enum_variant, name, shape))
|
||||
}
|
||||
Err(cfg) => {
|
||||
diagnostics.push(InactiveEnumVariantCode {
|
||||
ast_id,
|
||||
cfg,
|
||||
opts: cfg_options.clone(),
|
||||
});
|
||||
None
|
||||
}
|
||||
.intern(db);
|
||||
index += 1;
|
||||
Some((enum_variant, item_tree[variant].name.clone()))
|
||||
} else {
|
||||
diagnostics.push(InactiveEnumVariantCode {
|
||||
ast_id: item_tree[variant].ast_id,
|
||||
cfg: attrs.cfg().unwrap(),
|
||||
opts: cfg_options.clone(),
|
||||
});
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
(
|
||||
Arc::new(EnumVariants { variants }),
|
||||
diagnostics.is_empty().not().then(|| Arc::new(diagnostics)),
|
||||
)
|
||||
(EnumVariants { variants }, diagnostics.is_empty().not().then_some(diagnostics))
|
||||
}
|
||||
}
|
||||
|
||||
impl EnumVariants {
|
||||
pub fn variant(&self, name: &Name) -> Option<EnumVariantId> {
|
||||
self.variants.iter().find_map(|(v, n, _)| if n == name { Some(*v) } else { None })
|
||||
}
|
||||
|
||||
pub fn variant(&self, name: &Name) -> Option<EnumVariantId> {
|
||||
self.variants.iter().find_map(|(v, n)| if n == name { Some(*v) } else { None })
|
||||
pub fn variant_name_by_id(&self, variant_id: EnumVariantId) -> Option<Name> {
|
||||
self.variants
|
||||
.iter()
|
||||
.find_map(|(id, name, _)| if *id == variant_id { Some(name.clone()) } else { None })
|
||||
}
|
||||
|
||||
// [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448)
|
||||
pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool {
|
||||
self.variants.iter().all(|&(v, _)| {
|
||||
self.variants.iter().all(|&(v, _, _)| {
|
||||
// The condition check order is slightly modified from rustc
|
||||
// to improve performance by early returning with relatively fast checks
|
||||
let variant = &db.variant_fields(v.into());
|
||||
|
|
@ -973,3 +964,17 @@ impl EnumVariants {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn extern_block_abi(
|
||||
db: &dyn DefDatabase,
|
||||
extern_block: ExternBlockId,
|
||||
) -> Option<Symbol> {
|
||||
let source = extern_block.lookup(db).source(db);
|
||||
source.value.abi().map(|abi| {
|
||||
match abi.abi_string() {
|
||||
Some(tok) => Symbol::intern(tok.text_without_quotes()),
|
||||
// `extern` default to be `extern "C"`.
|
||||
_ => sym::C,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
//! Utilities for mapping between hir IDs and the surface syntax.
|
||||
|
||||
use either::Either;
|
||||
use hir_expand::InFile;
|
||||
use la_arena::ArenaMap;
|
||||
use hir_expand::{AstId, InFile};
|
||||
use la_arena::{Arena, ArenaMap, Idx};
|
||||
use syntax::{AstNode, AstPtr, ast};
|
||||
|
||||
use crate::{
|
||||
GenericDefId, ItemTreeLoc, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
|
||||
UseId, VariantId,
|
||||
db::DefDatabase,
|
||||
item_tree::{AttrOwner, FieldParent, ItemTreeNode},
|
||||
AstIdLoc, GenericDefId, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
|
||||
UseId, VariantId, attr::Attrs, db::DefDatabase,
|
||||
};
|
||||
|
||||
pub trait HasSource {
|
||||
|
|
@ -23,18 +21,13 @@ pub trait HasSource {
|
|||
|
||||
impl<T> HasSource for T
|
||||
where
|
||||
T: ItemTreeLoc,
|
||||
T::Id: ItemTreeNode,
|
||||
T: AstIdLoc,
|
||||
{
|
||||
type Value = <T::Id as ItemTreeNode>::Source;
|
||||
type Value = T::Ast;
|
||||
fn ast_ptr(&self, db: &dyn DefDatabase) -> InFile<AstPtr<Self::Value>> {
|
||||
let id = self.item_tree_id();
|
||||
let file_id = id.file_id();
|
||||
let tree = id.item_tree(db);
|
||||
let ast_id_map = db.ast_id_map(file_id);
|
||||
let node = &tree[id.value];
|
||||
|
||||
InFile::new(file_id, ast_id_map.get(node.ast_id()))
|
||||
let id = self.ast_id();
|
||||
let ast_id_map = db.ast_id_map(id.file_id);
|
||||
InFile::new(id.file_id, ast_id_map.get(id.value))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -43,18 +36,37 @@ pub trait HasChildSource<ChildId> {
|
|||
fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<ChildId, Self::Value>>;
|
||||
}
|
||||
|
||||
/// Maps a `UseTree` contained in this import back to its AST node.
|
||||
pub fn use_tree_to_ast(
|
||||
db: &dyn DefDatabase,
|
||||
use_ast_id: AstId<ast::Use>,
|
||||
index: Idx<ast::UseTree>,
|
||||
) -> ast::UseTree {
|
||||
use_tree_source_map(db, use_ast_id)[index].clone()
|
||||
}
|
||||
|
||||
/// Maps a `UseTree` contained in this import back to its AST node.
|
||||
fn use_tree_source_map(db: &dyn DefDatabase, use_ast_id: AstId<ast::Use>) -> Arena<ast::UseTree> {
|
||||
// Re-lower the AST item and get the source map.
|
||||
// Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
|
||||
let ast = use_ast_id.to_node(db);
|
||||
let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
|
||||
let mut span_map = None;
|
||||
crate::item_tree::lower_use_tree(db, ast_use_tree, &mut |range| {
|
||||
span_map.get_or_insert_with(|| db.span_map(use_ast_id.file_id)).span_for_range(range).ctx
|
||||
})
|
||||
.expect("failed to lower use tree")
|
||||
.1
|
||||
}
|
||||
|
||||
impl HasChildSource<la_arena::Idx<ast::UseTree>> for UseId {
|
||||
type Value = ast::UseTree;
|
||||
fn child_source(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
) -> InFile<ArenaMap<la_arena::Idx<ast::UseTree>, Self::Value>> {
|
||||
let loc = &self.lookup(db);
|
||||
let use_ = &loc.id.item_tree(db)[loc.id.value];
|
||||
InFile::new(
|
||||
loc.id.file_id(),
|
||||
use_.use_tree_source_map(db, loc.id.file_id()).into_iter().collect(),
|
||||
)
|
||||
let loc = self.lookup(db);
|
||||
InFile::new(loc.id.file_id, use_tree_source_map(db, loc.id).into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -124,49 +136,30 @@ impl HasChildSource<LocalFieldId> for VariantId {
|
|||
type Value = Either<ast::TupleField, ast::RecordField>;
|
||||
|
||||
fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<LocalFieldId, Self::Value>> {
|
||||
let item_tree;
|
||||
let (src, parent, container) = match *self {
|
||||
let (src, container) = match *self {
|
||||
VariantId::EnumVariantId(it) => {
|
||||
let lookup = it.lookup(db);
|
||||
item_tree = lookup.id.item_tree(db);
|
||||
(
|
||||
lookup.source(db).map(|it| it.kind()),
|
||||
FieldParent::EnumVariant(lookup.id.value),
|
||||
lookup.parent.lookup(db).container,
|
||||
)
|
||||
(lookup.source(db).map(|it| it.kind()), lookup.parent.lookup(db).container)
|
||||
}
|
||||
VariantId::StructId(it) => {
|
||||
let lookup = it.lookup(db);
|
||||
item_tree = lookup.id.item_tree(db);
|
||||
(
|
||||
lookup.source(db).map(|it| it.kind()),
|
||||
FieldParent::Struct(lookup.id.value),
|
||||
lookup.container,
|
||||
)
|
||||
(lookup.source(db).map(|it| it.kind()), lookup.container)
|
||||
}
|
||||
VariantId::UnionId(it) => {
|
||||
let lookup = it.lookup(db);
|
||||
item_tree = lookup.id.item_tree(db);
|
||||
(
|
||||
lookup.source(db).map(|it| it.kind()),
|
||||
FieldParent::Union(lookup.id.value),
|
||||
lookup.container,
|
||||
)
|
||||
(lookup.source(db).map(|it| it.kind()), lookup.container)
|
||||
}
|
||||
};
|
||||
|
||||
let span_map = db.span_map(src.file_id);
|
||||
let mut map = ArenaMap::new();
|
||||
match &src.value {
|
||||
ast::StructKind::Tuple(fl) => {
|
||||
let cfg_options = container.krate.cfg_options(db);
|
||||
let mut idx = 0;
|
||||
for (i, fd) in fl.fields().enumerate() {
|
||||
let attrs = item_tree.attrs(
|
||||
db,
|
||||
container.krate,
|
||||
AttrOwner::make_field_indexed(parent, i),
|
||||
);
|
||||
if !attrs.is_cfg_enabled(cfg_options) {
|
||||
for fd in fl.fields() {
|
||||
let enabled =
|
||||
Attrs::is_cfg_enabled_for(db, &fd, span_map.as_ref(), cfg_options).is_ok();
|
||||
if !enabled {
|
||||
continue;
|
||||
}
|
||||
map.insert(
|
||||
|
|
@ -179,13 +172,10 @@ impl HasChildSource<LocalFieldId> for VariantId {
|
|||
ast::StructKind::Record(fl) => {
|
||||
let cfg_options = container.krate.cfg_options(db);
|
||||
let mut idx = 0;
|
||||
for (i, fd) in fl.fields().enumerate() {
|
||||
let attrs = item_tree.attrs(
|
||||
db,
|
||||
container.krate,
|
||||
AttrOwner::make_field_indexed(parent, i),
|
||||
);
|
||||
if !attrs.is_cfg_enabled(cfg_options) {
|
||||
for fd in fl.fields() {
|
||||
let enabled =
|
||||
Attrs::is_cfg_enabled_for(db, &fd, span_map.as_ref(), cfg_options).is_ok();
|
||||
if !enabled {
|
||||
continue;
|
||||
}
|
||||
map.insert(
|
||||
|
|
@ -195,7 +185,7 @@ impl HasChildSource<LocalFieldId> for VariantId {
|
|||
idx += 1;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
ast::StructKind::Unit => (),
|
||||
}
|
||||
InFile::new(src.file_id, map)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,15 @@
|
|||
|
||||
use std::iter;
|
||||
|
||||
use hir_expand::Lookup;
|
||||
use base_db::Crate;
|
||||
use hir_expand::{InFile, Lookup};
|
||||
use la_arena::ArenaMap;
|
||||
use syntax::ast::{self, HasVisibility};
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
ConstId, FunctionId, HasModule, ItemContainerId, ItemLoc, ItemTreeLoc, LocalFieldId,
|
||||
LocalModuleId, ModuleId, TraitId, TypeAliasId, VariantId,
|
||||
db::DefDatabase,
|
||||
nameres::DefMap,
|
||||
resolver::{HasResolver, Resolver},
|
||||
AssocItemId, HasModule, ItemContainerId, LocalFieldId, LocalModuleId, ModuleId, TraitId,
|
||||
VariantId, db::DefDatabase, nameres::DefMap, resolver::HasResolver, src::HasSource,
|
||||
};
|
||||
|
||||
pub use crate::item_tree::{RawVisibility, VisibilityExplicitness};
|
||||
|
|
@ -21,6 +20,8 @@ pub use crate::item_tree::{RawVisibility, VisibilityExplicitness};
|
|||
pub enum Visibility {
|
||||
/// Visibility is restricted to a certain module.
|
||||
Module(ModuleId, VisibilityExplicitness),
|
||||
/// Visibility is restricted to the crate.
|
||||
PubCrate(Crate),
|
||||
/// Visibility is unrestricted.
|
||||
Public,
|
||||
}
|
||||
|
|
@ -43,8 +44,13 @@ impl Visibility {
|
|||
pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
|
||||
let to_module = match self {
|
||||
Visibility::Module(m, _) => m,
|
||||
Visibility::PubCrate(krate) => return from_module.krate == krate,
|
||||
Visibility::Public => return true,
|
||||
};
|
||||
if from_module == to_module {
|
||||
// if the modules are the same, visibility is trivially satisfied
|
||||
return true;
|
||||
}
|
||||
// if they're not in the same crate, it can't be visible
|
||||
if from_module.krate != to_module.krate {
|
||||
return false;
|
||||
|
|
@ -61,12 +67,18 @@ impl Visibility {
|
|||
) -> bool {
|
||||
let to_module = match self {
|
||||
Visibility::Module(m, _) => m,
|
||||
Visibility::PubCrate(krate) => return def_map.krate() == krate,
|
||||
Visibility::Public => return true,
|
||||
};
|
||||
// if they're not in the same crate, it can't be visible
|
||||
if def_map.krate() != to_module.krate {
|
||||
return false;
|
||||
}
|
||||
|
||||
if from_module == to_module.local_id && def_map.block_id() == to_module.block {
|
||||
// if the modules are the same, visibility is trivially satisfied
|
||||
return true;
|
||||
}
|
||||
Self::is_visible_from_def_map_(db, def_map, to_module, from_module)
|
||||
}
|
||||
|
||||
|
|
@ -90,9 +102,7 @@ impl Visibility {
|
|||
// `to_module` is not a block, so there is no parent def map to use.
|
||||
(None, _) => (),
|
||||
// `to_module` is at `def_map`'s block, no need to move further.
|
||||
(Some(a), Some(b)) if a == b => {
|
||||
cov_mark::hit!(is_visible_from_same_block_def_map);
|
||||
}
|
||||
(Some(a), Some(b)) if a == b => {}
|
||||
_ => {
|
||||
if let Some(parent) = to_module.def_map(db).parent() {
|
||||
to_module = parent;
|
||||
|
|
@ -134,26 +144,56 @@ impl Visibility {
|
|||
pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
|
||||
match (self, other) {
|
||||
(_, Visibility::Public) | (Visibility::Public, _) => Some(Visibility::Public),
|
||||
(Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => {
|
||||
if krate == krateb {
|
||||
Some(Visibility::PubCrate(krate))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
(Visibility::Module(mod_, _), Visibility::PubCrate(krate))
|
||||
| (Visibility::PubCrate(krate), Visibility::Module(mod_, _)) => {
|
||||
if mod_.krate == krate {
|
||||
Some(Visibility::PubCrate(krate))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
(Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
|
||||
if mod_a.krate != mod_b.krate {
|
||||
if mod_a == mod_b {
|
||||
// Most module visibilities are `pub(self)`, and assuming no errors
|
||||
// this will be the common and thus fast path.
|
||||
return Some(Visibility::Module(
|
||||
mod_a,
|
||||
match (expl_a, expl_b) {
|
||||
(VisibilityExplicitness::Explicit, _)
|
||||
| (_, VisibilityExplicitness::Explicit) => {
|
||||
VisibilityExplicitness::Explicit
|
||||
}
|
||||
_ => VisibilityExplicitness::Implicit,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let def_block = def_map.block_id();
|
||||
if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
|
||||
if mod_a.containing_block() != def_block || mod_b.containing_block() != def_block {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut a_ancestors =
|
||||
iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
|
||||
let mut b_ancestors =
|
||||
iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
|
||||
|
||||
if a_ancestors.any(|m| m == mod_b.local_id) {
|
||||
// B is above A
|
||||
return Some(Visibility::Module(mod_b, expl_b));
|
||||
}
|
||||
|
||||
let mut b_ancestors =
|
||||
iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
|
||||
if b_ancestors.any(|m| m == mod_a.local_id) {
|
||||
// A is above B
|
||||
return Some(Visibility::Module(mod_a, expl_a));
|
||||
|
|
@ -171,26 +211,52 @@ impl Visibility {
|
|||
pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
|
||||
match (self, other) {
|
||||
(vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis),
|
||||
(Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => {
|
||||
if krate == krateb {
|
||||
Some(Visibility::PubCrate(krate))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
(Visibility::Module(mod_, exp), Visibility::PubCrate(krate))
|
||||
| (Visibility::PubCrate(krate), Visibility::Module(mod_, exp)) => {
|
||||
if mod_.krate == krate { Some(Visibility::Module(mod_, exp)) } else { None }
|
||||
}
|
||||
(Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
|
||||
if mod_a.krate != mod_b.krate {
|
||||
if mod_a == mod_b {
|
||||
// Most module visibilities are `pub(self)`, and assuming no errors
|
||||
// this will be the common and thus fast path.
|
||||
return Some(Visibility::Module(
|
||||
mod_a,
|
||||
match (expl_a, expl_b) {
|
||||
(VisibilityExplicitness::Explicit, _)
|
||||
| (_, VisibilityExplicitness::Explicit) => {
|
||||
VisibilityExplicitness::Explicit
|
||||
}
|
||||
_ => VisibilityExplicitness::Implicit,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let def_block = def_map.block_id();
|
||||
if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
|
||||
if mod_a.containing_block() != def_block || mod_b.containing_block() != def_block {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut a_ancestors =
|
||||
iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
|
||||
let mut b_ancestors =
|
||||
iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
|
||||
|
||||
if a_ancestors.any(|m| m == mod_b.local_id) {
|
||||
// B is above A
|
||||
return Some(Visibility::Module(mod_a, expl_a));
|
||||
}
|
||||
|
||||
let mut b_ancestors =
|
||||
iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
|
||||
if b_ancestors.any(|m| m == mod_a.local_id) {
|
||||
// A is above B
|
||||
return Some(Visibility::Module(mod_b, expl_b));
|
||||
|
|
@ -217,49 +283,62 @@ pub(crate) fn field_visibilities_query(
|
|||
for (field_id, field_data) in fields.iter() {
|
||||
res.insert(field_id, Visibility::resolve(db, &resolver, &field_data.visibility));
|
||||
}
|
||||
res.shrink_to_fit();
|
||||
Arc::new(res)
|
||||
}
|
||||
|
||||
/// Resolve visibility of a function.
|
||||
pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility {
|
||||
let resolver = def.resolver(db);
|
||||
let loc = def.lookup(db);
|
||||
let tree = loc.item_tree_id().item_tree(db);
|
||||
if let ItemContainerId::TraitId(trait_id) = loc.container {
|
||||
trait_vis(db, &resolver, trait_id)
|
||||
} else {
|
||||
Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility])
|
||||
pub fn visibility_from_ast(
|
||||
db: &dyn DefDatabase,
|
||||
has_resolver: impl HasResolver,
|
||||
ast_vis: InFile<Option<ast::Visibility>>,
|
||||
) -> Visibility {
|
||||
let mut span_map = None;
|
||||
let raw_vis = crate::item_tree::visibility_from_ast(db, ast_vis.value, &mut |range| {
|
||||
span_map.get_or_insert_with(|| db.span_map(ast_vis.file_id)).span_for_range(range).ctx
|
||||
});
|
||||
if raw_vis == RawVisibility::Public {
|
||||
return Visibility::Public;
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve visibility of a const.
|
||||
pub(crate) fn const_visibility_query(db: &dyn DefDatabase, def: ConstId) -> Visibility {
|
||||
let resolver = def.resolver(db);
|
||||
let loc = def.lookup(db);
|
||||
let tree = loc.item_tree_id().item_tree(db);
|
||||
if let ItemContainerId::TraitId(trait_id) = loc.container {
|
||||
trait_vis(db, &resolver, trait_id)
|
||||
} else {
|
||||
Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility])
|
||||
}
|
||||
Visibility::resolve(db, &has_resolver.resolver(db), &raw_vis)
|
||||
}
|
||||
|
||||
/// Resolve visibility of a type alias.
|
||||
pub(crate) fn type_alias_visibility_query(db: &dyn DefDatabase, def: TypeAliasId) -> Visibility {
|
||||
let resolver = def.resolver(db);
|
||||
let loc = def.lookup(db);
|
||||
let tree = loc.item_tree_id().item_tree(db);
|
||||
if let ItemContainerId::TraitId(trait_id) = loc.container {
|
||||
trait_vis(db, &resolver, trait_id)
|
||||
} else {
|
||||
Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility])
|
||||
pub(crate) fn assoc_visibility_query(db: &dyn DefDatabase, def: AssocItemId) -> Visibility {
|
||||
match def {
|
||||
AssocItemId::FunctionId(function_id) => {
|
||||
let loc = function_id.lookup(db);
|
||||
trait_item_visibility(db, loc.container).unwrap_or_else(|| {
|
||||
let source = loc.source(db);
|
||||
visibility_from_ast(db, function_id, source.map(|src| src.visibility()))
|
||||
})
|
||||
}
|
||||
AssocItemId::ConstId(const_id) => {
|
||||
let loc = const_id.lookup(db);
|
||||
trait_item_visibility(db, loc.container).unwrap_or_else(|| {
|
||||
let source = loc.source(db);
|
||||
visibility_from_ast(db, const_id, source.map(|src| src.visibility()))
|
||||
})
|
||||
}
|
||||
AssocItemId::TypeAliasId(type_alias_id) => {
|
||||
let loc = type_alias_id.lookup(db);
|
||||
trait_item_visibility(db, loc.container).unwrap_or_else(|| {
|
||||
let source = loc.source(db);
|
||||
visibility_from_ast(db, type_alias_id, source.map(|src| src.visibility()))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver<'_>, trait_id: TraitId) -> Visibility {
|
||||
let ItemLoc { id: tree_id, .. } = trait_id.lookup(db);
|
||||
let item_tree = tree_id.item_tree(db);
|
||||
let tr_def = &item_tree[tree_id.value];
|
||||
Visibility::resolve(db, resolver, &item_tree[tr_def.visibility])
|
||||
fn trait_item_visibility(db: &dyn DefDatabase, container: ItemContainerId) -> Option<Visibility> {
|
||||
match container {
|
||||
ItemContainerId::TraitId(trait_) => Some(trait_visibility(db, trait_)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn trait_visibility(db: &dyn DefDatabase, def: TraitId) -> Visibility {
|
||||
let loc = def.lookup(db);
|
||||
let source = loc.source(db);
|
||||
visibility_from_ast(db, def, source.map(|src| src.visibility()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,8 +277,8 @@ mod tests {
|
|||
assert_eq!(quoted.to_string(), "hello");
|
||||
let t = format!("{quoted:#?}");
|
||||
expect![[r#"
|
||||
SUBTREE $$ 937550:0@0..0#ROOT2024 937550:0@0..0#ROOT2024
|
||||
IDENT hello 937550:0@0..0#ROOT2024"#]]
|
||||
SUBTREE $$ 937550:Root[0000, 0]@0..0#ROOT2024 937550:Root[0000, 0]@0..0#ROOT2024
|
||||
IDENT hello 937550:Root[0000, 0]@0..0#ROOT2024"#]]
|
||||
.assert_eq(&t);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use crate::{
|
|||
AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo,
|
||||
EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, HirFileId, MacroCallId,
|
||||
MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
|
||||
attrs::{AttrId, collect_attrs},
|
||||
attrs::{AttrId, AttrInput, RawAttrs, collect_attrs},
|
||||
builtin::pseudo_derive_attr_expansion,
|
||||
cfg_process,
|
||||
declarative::DeclarativeMacroExpander,
|
||||
|
|
@ -60,6 +60,7 @@ pub trait ExpandDatabase: RootQueryDb {
|
|||
fn proc_macros_for_crate(&self, krate: Crate) -> Option<Arc<CrateProcMacros>>;
|
||||
|
||||
#[salsa::invoke(ast_id_map)]
|
||||
#[salsa::lru(1024)]
|
||||
fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
|
||||
|
||||
#[salsa::transparent]
|
||||
|
|
@ -241,30 +242,36 @@ pub fn expand_speculative(
|
|||
|
||||
let attr_arg = match loc.kind {
|
||||
MacroCallKind::Attr { invoc_attr_index, .. } => {
|
||||
let attr = if loc.def.is_attribute_derive() {
|
||||
if loc.def.is_attribute_derive() {
|
||||
// for pseudo-derive expansion we actually pass the attribute itself only
|
||||
ast::Attr::cast(speculative_args.clone())
|
||||
ast::Attr::cast(speculative_args.clone()).and_then(|attr| attr.token_tree()).map(
|
||||
|token_tree| {
|
||||
let mut tree = syntax_node_to_token_tree(
|
||||
token_tree.syntax(),
|
||||
span_map,
|
||||
span,
|
||||
DocCommentDesugarMode::ProcMacro,
|
||||
);
|
||||
*tree.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span);
|
||||
tree
|
||||
},
|
||||
)
|
||||
} else {
|
||||
// Attributes may have an input token tree, build the subtree and map for this as well
|
||||
// then try finding a token id for our token if it is inside this input subtree.
|
||||
let item = ast::Item::cast(speculative_args.clone())?;
|
||||
collect_attrs(&item)
|
||||
.nth(invoc_attr_index.ast_index())
|
||||
.and_then(|x| Either::left(x.1))
|
||||
}?;
|
||||
match attr.token_tree() {
|
||||
Some(token_tree) => {
|
||||
let mut tree = syntax_node_to_token_tree(
|
||||
token_tree.syntax(),
|
||||
span_map,
|
||||
span,
|
||||
DocCommentDesugarMode::ProcMacro,
|
||||
);
|
||||
*tree.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span);
|
||||
|
||||
Some(tree)
|
||||
}
|
||||
_ => None,
|
||||
let attrs = RawAttrs::new_expanded(db, &item, span_map, loc.krate.cfg_options(db));
|
||||
attrs.iter().find(|attr| attr.id == invoc_attr_index).and_then(|attr| {
|
||||
match attr.input.as_deref()? {
|
||||
AttrInput::TokenTree(tt) => {
|
||||
let mut attr_arg = tt.clone();
|
||||
attr_arg.top_subtree_delimiter_mut().kind =
|
||||
tt::DelimiterKind::Invisible;
|
||||
Some(attr_arg)
|
||||
}
|
||||
AttrInput::Literal(_) => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ impl FileRange {
|
|||
/// It is stable across reparses, and can be used as salsa key/value.
|
||||
pub type AstId<N> = crate::InFile<FileAstId<N>>;
|
||||
|
||||
impl<N: AstIdNode> AstId<N> {
|
||||
impl<N: AstNode> AstId<N> {
|
||||
pub fn to_node(&self, db: &dyn ExpandDatabase) -> N {
|
||||
self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id))
|
||||
}
|
||||
|
|
@ -122,6 +122,13 @@ impl<N: AstIdNode> AstId<N> {
|
|||
pub fn erase(&self) -> ErasedAstId {
|
||||
crate::InFile::new(self.file_id, self.value.erase())
|
||||
}
|
||||
#[inline]
|
||||
pub fn upcast<M: AstIdNode>(self) -> AstId<M>
|
||||
where
|
||||
N: Into<M>,
|
||||
{
|
||||
self.map(|it| it.upcast())
|
||||
}
|
||||
}
|
||||
|
||||
pub type ErasedAstId = crate::InFile<ErasedFileAstId>;
|
||||
|
|
|
|||
|
|
@ -34,9 +34,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any {
|
|||
current_dir: String,
|
||||
) -> Result<tt::TopSubtree, ProcMacroExpansionError>;
|
||||
|
||||
fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
other.type_id() == self.type_id()
|
||||
}
|
||||
fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool;
|
||||
}
|
||||
|
||||
impl PartialEq for dyn ProcMacroExpander {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ la-arena.workspace = true
|
|||
triomphe.workspace = true
|
||||
typed-arena = "2.0.2"
|
||||
indexmap.workspace = true
|
||||
rustc_apfloat = "0.2.2"
|
||||
rustc_apfloat = "0.2.3"
|
||||
query-group.workspace = true
|
||||
salsa.workspace = true
|
||||
salsa-macros.workspace = true
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
|||
) -> Option<rust_ir::AssociatedTyValueId<Interner>> {
|
||||
let alias_id = from_assoc_type_id(assoc_type_id);
|
||||
let trait_sig = self.db.type_alias_signature(alias_id);
|
||||
self.db.impl_items(hir_def::ImplId::from_chalk(self.db, impl_id)).items.iter().find_map(
|
||||
hir_def::ImplId::from_chalk(self.db, impl_id).impl_items(self.db).items.iter().find_map(
|
||||
|(name, item)| match item {
|
||||
AssocItemId::TypeAliasId(alias) if &trait_sig.name == name => {
|
||||
Some(TypeAliasAsValue(*alias).to_chalk(self.db))
|
||||
|
|
@ -261,10 +261,20 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
|||
&self,
|
||||
well_known_trait: WellKnownTrait,
|
||||
) -> Option<chalk_ir::TraitId<Interner>> {
|
||||
let lang_attr = lang_item_from_well_known_trait(well_known_trait);
|
||||
let trait_ = lang_attr.resolve_trait(self.db, self.krate)?;
|
||||
let lang_item = lang_item_from_well_known_trait(well_known_trait);
|
||||
let trait_ = lang_item.resolve_trait(self.db, self.krate)?;
|
||||
Some(to_chalk_trait_id(trait_))
|
||||
}
|
||||
fn well_known_assoc_type_id(
|
||||
&self,
|
||||
assoc_type: rust_ir::WellKnownAssocType,
|
||||
) -> Option<chalk_ir::AssocTypeId<Interner>> {
|
||||
let lang_item = match assoc_type {
|
||||
rust_ir::WellKnownAssocType::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput,
|
||||
};
|
||||
let alias = lang_item.resolve_type_alias(self.db, self.krate)?;
|
||||
Some(to_assoc_type_id(alias))
|
||||
}
|
||||
|
||||
fn program_clauses_for_env(
|
||||
&self,
|
||||
|
|
@ -813,11 +823,11 @@ pub(crate) fn adt_datum_query(
|
|||
(rust_ir::AdtKind::Struct, vec![variant_id_to_fields(id.into())])
|
||||
}
|
||||
hir_def::AdtId::EnumId(id) => {
|
||||
let variants = db
|
||||
.enum_variants(id)
|
||||
let variants = id
|
||||
.enum_variants(db)
|
||||
.variants
|
||||
.iter()
|
||||
.map(|&(variant_id, _)| variant_id_to_fields(variant_id.into()))
|
||||
.map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into()))
|
||||
.collect();
|
||||
(rust_ir::AdtKind::Enum, variants)
|
||||
}
|
||||
|
|
@ -870,8 +880,8 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
|
|||
|
||||
let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses };
|
||||
let trait_data = db.trait_items(trait_);
|
||||
let associated_ty_value_ids = db
|
||||
.impl_items(impl_id)
|
||||
let associated_ty_value_ids = impl_id
|
||||
.impl_items(db)
|
||||
.items
|
||||
.iter()
|
||||
.filter_map(|(_, item)| match item {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ use crate::{
|
|||
ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy,
|
||||
QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause,
|
||||
db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
|
||||
from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst,
|
||||
from_placeholder_idx, generics::generics, mapping::ToChalk, to_chalk_trait_id,
|
||||
utils::ClosureSubst,
|
||||
};
|
||||
|
||||
pub trait TyExt {
|
||||
|
|
@ -190,10 +191,9 @@ impl TyExt for Ty {
|
|||
fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
|
||||
match *self.kind(Interner) {
|
||||
TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
|
||||
TyKind::FnDef(callable, ..) => Some(GenericDefId::from_callable(
|
||||
db,
|
||||
db.lookup_intern_callable_def(callable.into()),
|
||||
)),
|
||||
TyKind::FnDef(callable, ..) => {
|
||||
Some(GenericDefId::from_callable(db, ToChalk::from_chalk(db, callable)))
|
||||
}
|
||||
TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
|
||||
TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
|
||||
_ => None,
|
||||
|
|
@ -202,7 +202,7 @@ impl TyExt for Ty {
|
|||
|
||||
fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
|
||||
match self.kind(Interner) {
|
||||
&TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())),
|
||||
&TyKind::FnDef(def, ..) => Some(ToChalk::from_chalk(db, def)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ pub(crate) fn const_eval_discriminant_variant(
|
|||
let value = match prev_idx {
|
||||
Some(prev_idx) => {
|
||||
1 + db.const_eval_discriminant(
|
||||
db.enum_variants(loc.parent).variants[prev_idx as usize].0,
|
||||
loc.parent.enum_variants(db).variants[prev_idx as usize].0,
|
||||
)?
|
||||
}
|
||||
_ => 0,
|
||||
|
|
|
|||
|
|
@ -112,16 +112,16 @@ fn size_of_val() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn min_align_of_val() {
|
||||
fn align_of_val() {
|
||||
check_number(
|
||||
r#"
|
||||
//- minicore: coerce_unsized
|
||||
#[rustc_intrinsic]
|
||||
pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
|
||||
pub fn align_of_val<T: ?Sized>(_: *const T) -> usize;
|
||||
|
||||
struct X(i32, u8);
|
||||
|
||||
const GOAL: usize = min_align_of_val(&X(1, 2));
|
||||
const GOAL: usize = align_of_val(&X(1, 2));
|
||||
"#,
|
||||
4,
|
||||
);
|
||||
|
|
@ -129,11 +129,11 @@ fn min_align_of_val() {
|
|||
r#"
|
||||
//- minicore: coerce_unsized
|
||||
#[rustc_intrinsic]
|
||||
pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
|
||||
pub fn align_of_val<T: ?Sized>(_: *const T) -> usize;
|
||||
|
||||
const GOAL: usize = {
|
||||
let x: &[i32] = &[1, 2, 3];
|
||||
min_align_of_val(x)
|
||||
align_of_val(x)
|
||||
};
|
||||
"#,
|
||||
4,
|
||||
|
|
|
|||
|
|
@ -236,9 +236,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
|
|||
fn trait_impls_in_deps(&self, krate: Crate) -> Arc<[Arc<TraitImpls>]>;
|
||||
|
||||
// Interned IDs for Chalk integration
|
||||
#[salsa::interned]
|
||||
fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId;
|
||||
|
||||
#[salsa::interned]
|
||||
fn intern_type_or_const_param_id(
|
||||
&self,
|
||||
|
|
@ -347,7 +344,3 @@ impl_intern_key!(InternedClosureId, InternedClosure);
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId);
|
||||
impl_intern_key!(InternedCoroutineId, InternedCoroutine);
|
||||
|
||||
// This exists just for Chalk, because Chalk just has a single `FnDefId` where
|
||||
// we have different IDs for struct and enum variant constructors.
|
||||
impl_intern_key!(InternedCallableDefId, CallableDefId);
|
||||
|
|
|
|||
|
|
@ -395,9 +395,9 @@ impl<'a> DeclValidator<'a> {
|
|||
|
||||
/// Check incorrect names for enum variants.
|
||||
fn validate_enum_variants(&mut self, enum_id: EnumId) {
|
||||
let data = self.db.enum_variants(enum_id);
|
||||
let data = enum_id.enum_variants(self.db);
|
||||
|
||||
for (variant_id, _) in data.variants.iter() {
|
||||
for (variant_id, _, _) in data.variants.iter() {
|
||||
self.validate_enum_variant_fields(*variant_id);
|
||||
}
|
||||
|
||||
|
|
@ -405,7 +405,7 @@ impl<'a> DeclValidator<'a> {
|
|||
let mut enum_variants_replacements = data
|
||||
.variants
|
||||
.iter()
|
||||
.filter_map(|(_, name)| {
|
||||
.filter_map(|(_, name, _)| {
|
||||
to_camel_case(&name.display_no_db(edition).to_smolstr()).map(|new_name| {
|
||||
Replacement {
|
||||
current_name: name.clone(),
|
||||
|
|
|
|||
|
|
@ -642,7 +642,7 @@ fn missing_match_arms<'p>(
|
|||
}
|
||||
|
||||
let non_empty_enum = match scrut_ty.as_adt() {
|
||||
Some((AdtId::EnumId(e), _)) => !cx.db.enum_variants(e).variants.is_empty(),
|
||||
Some((AdtId::EnumId(e), _)) => !e.enum_variants(cx.db).variants.is_empty(),
|
||||
_ => false,
|
||||
};
|
||||
let display_target = DisplayTarget::from_crate(cx.db, krate);
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ impl HirDisplay for Pat {
|
|||
write!(
|
||||
f,
|
||||
"{}",
|
||||
f.db.enum_variants(loc.parent).variants[loc.index as usize]
|
||||
loc.parent.enum_variants(f.db).variants[loc.index as usize]
|
||||
.1
|
||||
.display(f.db, f.edition())
|
||||
)?;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ impl EnumVariantContiguousIndex {
|
|||
}
|
||||
|
||||
fn to_enum_variant_id(self, db: &dyn HirDatabase, eid: EnumId) -> EnumVariantId {
|
||||
db.enum_variants(eid).variants[self.0].0
|
||||
eid.enum_variants(db).variants[self.0].0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -458,14 +458,14 @@ impl PatCx for MatchCheckCtx<'_> {
|
|||
TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(),
|
||||
TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
|
||||
&TyKind::Adt(AdtId(adt @ hir_def::AdtId::EnumId(enum_id)), ref subst) => {
|
||||
let enum_data = cx.db.enum_variants(enum_id);
|
||||
let enum_data = enum_id.enum_variants(cx.db);
|
||||
let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt);
|
||||
|
||||
if enum_data.variants.is_empty() && !is_declared_nonexhaustive {
|
||||
ConstructorSet::NoConstructors
|
||||
} else {
|
||||
let mut variants = IndexVec::with_capacity(enum_data.variants.len());
|
||||
for &(variant, _) in enum_data.variants.iter() {
|
||||
for &(variant, _, _) in enum_data.variants.iter() {
|
||||
let is_uninhabited = is_enum_variant_uninhabited_from(
|
||||
cx.db,
|
||||
variant,
|
||||
|
|
|
|||
|
|
@ -914,7 +914,7 @@ fn render_const_scalar(
|
|||
write!(
|
||||
f,
|
||||
"{}",
|
||||
f.db.enum_variants(loc.parent).variants[loc.index as usize]
|
||||
loc.parent.enum_variants(f.db).variants[loc.index as usize]
|
||||
.1
|
||||
.display(f.db, f.edition())
|
||||
)?;
|
||||
|
|
@ -1208,7 +1208,7 @@ impl HirDisplay for Ty {
|
|||
write!(
|
||||
f,
|
||||
"{}",
|
||||
db.enum_variants(loc.parent).variants[loc.index as usize]
|
||||
loc.parent.enum_variants(db).variants[loc.index as usize]
|
||||
.1
|
||||
.display(db, f.edition())
|
||||
)?
|
||||
|
|
@ -2082,6 +2082,7 @@ pub fn write_visibility(
|
|||
) -> Result<(), HirDisplayError> {
|
||||
match vis {
|
||||
Visibility::Public => write!(f, "pub "),
|
||||
Visibility::PubCrate(_) => write!(f, "pub(crate) "),
|
||||
Visibility::Module(vis_id, _) => {
|
||||
let def_map = module_id.def_map(f.db);
|
||||
let root_module_id = def_map.module_id(DefMap::ROOT);
|
||||
|
|
|
|||
|
|
@ -67,11 +67,11 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironm
|
|||
}
|
||||
// Unions cannot have fields with destructors.
|
||||
AdtId::UnionId(_) => DropGlue::None,
|
||||
AdtId::EnumId(id) => db
|
||||
.enum_variants(id)
|
||||
AdtId::EnumId(id) => id
|
||||
.enum_variants(db)
|
||||
.variants
|
||||
.iter()
|
||||
.map(|&(variant, _)| {
|
||||
.map(|&(variant, _, _)| {
|
||||
db.field_types(variant.into())
|
||||
.iter()
|
||||
.map(|(_, field_ty)| {
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ pub fn dyn_compatibility_of_trait_query(
|
|||
res
|
||||
}
|
||||
|
||||
fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool {
|
||||
pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool {
|
||||
let krate = def.module(db).krate();
|
||||
let Some(sized) = LangItem::Sized.resolve_trait(db, krate) else {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ impl Generics {
|
|||
}
|
||||
|
||||
/// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
|
||||
pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
|
||||
pub fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
|
||||
Substitution::from_iter(
|
||||
Interner,
|
||||
self.iter_id().map(|id| match id {
|
||||
|
|
|
|||
|
|
@ -1673,7 +1673,7 @@ impl<'db> InferenceContext<'db> {
|
|||
// If we can resolve to an enum variant, it takes priority over associated type
|
||||
// of the same name.
|
||||
if let Some((AdtId::EnumId(id), _)) = ty.as_adt() {
|
||||
let enum_data = self.db.enum_variants(id);
|
||||
let enum_data = id.enum_variants(self.db);
|
||||
if let Some(variant) = enum_data.variant(current_segment.name) {
|
||||
return if remaining_segments.len() == 1 {
|
||||
(ty, Some(variant.into()))
|
||||
|
|
@ -1792,7 +1792,7 @@ impl<'db> InferenceContext<'db> {
|
|||
let segment = path.segments().last().unwrap();
|
||||
// this could be an enum variant or associated type
|
||||
if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
|
||||
let enum_data = self.db.enum_variants(enum_id);
|
||||
let enum_data = enum_id.enum_variants(self.db);
|
||||
if let Some(variant) = enum_data.variant(segment) {
|
||||
return (ty, Some(variant.into()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ impl CastTy {
|
|||
let (AdtId::EnumId(id), _) = t.as_adt()? else {
|
||||
return None;
|
||||
};
|
||||
let enum_data = table.db.enum_variants(id);
|
||||
let enum_data = id.enum_variants(table.db);
|
||||
if enum_data.is_payload_free(table.db) { Some(Self::Int(Int::CEnum)) } else { None }
|
||||
}
|
||||
TyKind::Raw(m, ty) => Some(Self::Ptr(ty.clone(), *m)),
|
||||
|
|
|
|||
|
|
@ -1360,7 +1360,7 @@ impl InferenceContext<'_> {
|
|||
if let Some(variant) = self.result.variant_resolution_for_pat(p) {
|
||||
let adt = variant.adt_id(self.db);
|
||||
let is_multivariant = match adt {
|
||||
hir_def::AdtId::EnumId(e) => self.db.enum_variants(e).variants.len() != 1,
|
||||
hir_def::AdtId::EnumId(e) => e.enum_variants(self.db).variants.len() != 1,
|
||||
_ => false,
|
||||
};
|
||||
if is_multivariant {
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ impl InferenceContext<'_> {
|
|||
Some((AdtId::EnumId(e), subst)) => (e, subst),
|
||||
_ => return None,
|
||||
};
|
||||
let enum_data = self.db.enum_variants(enum_id);
|
||||
let enum_data = enum_id.enum_variants(self.db);
|
||||
let variant = enum_data.variant(name)?;
|
||||
self.write_variant_resolution(id, variant.into());
|
||||
Some((ValueNs::EnumVariantId(variant), subst.clone()))
|
||||
|
|
|
|||
|
|
@ -113,9 +113,9 @@ impl UninhabitedFrom<'_> {
|
|||
AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
|
||||
AdtId::StructId(s) => self.visit_variant(s.into(), subst),
|
||||
AdtId::EnumId(e) => {
|
||||
let enum_data = self.db.enum_variants(e);
|
||||
let enum_data = e.enum_variants(self.db);
|
||||
|
||||
for &(variant, _) in enum_data.variants.iter() {
|
||||
for &(variant, _, _) in enum_data.variants.iter() {
|
||||
let variant_inhabitedness = self.visit_variant(variant.into(), subst);
|
||||
match variant_inhabitedness {
|
||||
Break(VisiblyUninhabited) => (),
|
||||
|
|
|
|||
|
|
@ -56,11 +56,11 @@ pub fn layout_of_adt_query(
|
|||
(r, data.repr.unwrap_or_default(), false)
|
||||
}
|
||||
AdtId::EnumId(e) => {
|
||||
let variants = db.enum_variants(e);
|
||||
let variants = e.enum_variants(db);
|
||||
let r = variants
|
||||
.variants
|
||||
.iter()
|
||||
.map(|&(v, _)| handle_variant(v.into(), &db.variant_fields(v.into())))
|
||||
.map(|&(v, _, _)| handle_variant(v.into(), &db.variant_fields(v.into())))
|
||||
.collect::<Result<SmallVec<_>, _>>()?;
|
||||
(r, db.enum_signature(e).repr.unwrap_or_default(), false)
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ pub fn layout_of_adt_query(
|
|||
|min, max| repr_discr(dl, &repr, min, max).unwrap_or((Integer::I8, false)),
|
||||
variants.iter_enumerated().filter_map(|(id, _)| {
|
||||
let AdtId::EnumId(e) = def else { return None };
|
||||
let d = db.const_eval_discriminant(db.enum_variants(e).variants[id.0].0).ok()?;
|
||||
let d = db.const_eval_discriminant(e.enum_variants(db).variants[id.0].0).ok()?;
|
||||
Some((id, d))
|
||||
}),
|
||||
// FIXME: The current code for niche-filling relies on variant indices
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ pub use lower::{
|
|||
ValueTyDefId, associated_type_shorthand_candidates, diagnostics::*,
|
||||
};
|
||||
pub use mapping::{
|
||||
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
|
||||
ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
|
||||
lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
|
||||
to_foreign_def_id, to_placeholder_idx,
|
||||
};
|
||||
|
|
@ -542,7 +542,7 @@ impl CallableSig {
|
|||
}
|
||||
|
||||
pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig {
|
||||
let callable_def = db.lookup_intern_callable_def(def.into());
|
||||
let callable_def = ToChalk::from_chalk(db, def);
|
||||
let sig = db.callable_item_signature(callable_def);
|
||||
sig.substitute(Interner, substs)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use crate::{
|
|||
PlaceholderIndex, chalk_db, db::HirDatabase,
|
||||
};
|
||||
|
||||
pub(crate) trait ToChalk {
|
||||
pub trait ToChalk {
|
||||
type Chalk;
|
||||
fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk;
|
||||
fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self;
|
||||
|
|
@ -44,12 +44,12 @@ impl ToChalk for hir_def::ImplId {
|
|||
impl ToChalk for CallableDefId {
|
||||
type Chalk = FnDefId;
|
||||
|
||||
fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId {
|
||||
db.intern_callable_def(self).into()
|
||||
fn to_chalk(self, _db: &dyn HirDatabase) -> FnDefId {
|
||||
chalk_ir::FnDefId(salsa::plumbing::AsId::as_id(&self))
|
||||
}
|
||||
|
||||
fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId {
|
||||
db.lookup_intern_callable_def(fn_def_id.into())
|
||||
salsa::plumbing::FromIdWithDb::from_id(fn_def_id.0, db.zalsa())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,18 +70,6 @@ impl ToChalk for TypeAliasAsValue {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<FnDefId> for crate::db::InternedCallableDefId {
|
||||
fn from(fn_def_id: FnDefId) -> Self {
|
||||
Self::from_id(fn_def_id.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::db::InternedCallableDefId> for FnDefId {
|
||||
fn from(callable_def_id: crate::db::InternedCallableDefId) -> Self {
|
||||
chalk_ir::FnDefId(callable_def_id.as_id())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId {
|
||||
fn from(id: OpaqueTyId) -> Self {
|
||||
FromId::from_id(id.0)
|
||||
|
|
|
|||
|
|
@ -790,7 +790,7 @@ fn find_matching_impl(
|
|||
mut impls: impl Iterator<Item = ImplId>,
|
||||
mut table: InferenceTable<'_>,
|
||||
actual_trait_ref: TraitRef,
|
||||
) -> Option<(Arc<ImplItems>, Substitution)> {
|
||||
) -> Option<(&ImplItems, Substitution)> {
|
||||
let db = table.db;
|
||||
impls.find_map(|impl_| {
|
||||
table.run_in_snapshot(|table| {
|
||||
|
|
@ -811,7 +811,7 @@ fn find_matching_impl(
|
|||
let goal = crate::Goal::all(Interner, wcs);
|
||||
table.try_obligation(goal.clone())?;
|
||||
table.register_obligation(goal);
|
||||
Some((db.impl_items(impl_), table.resolve_completely(impl_substs)))
|
||||
Some((impl_.impl_items(db), table.resolve_completely(impl_substs)))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -875,7 +875,7 @@ fn is_inherent_impl_coherent(
|
|||
|
||||
_ => false,
|
||||
};
|
||||
let items = db.impl_items(impl_id);
|
||||
let items = impl_id.impl_items(db);
|
||||
rustc_has_incoherent_inherent_impls
|
||||
&& !items.items.is_empty()
|
||||
&& items.items.iter().all(|&(_, assoc)| match assoc {
|
||||
|
|
@ -1462,7 +1462,7 @@ fn iterate_inherent_methods(
|
|||
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
|
||||
) -> ControlFlow<()> {
|
||||
for &impl_id in impls.for_self_ty(self_ty) {
|
||||
for &(ref item_name, item) in table.db.impl_items(impl_id).items.iter() {
|
||||
for &(ref item_name, item) in impl_id.impl_items(table.db).items.iter() {
|
||||
let visible = match is_valid_impl_method_candidate(
|
||||
table,
|
||||
self_ty,
|
||||
|
|
@ -1550,7 +1550,7 @@ fn is_valid_impl_method_candidate(
|
|||
check_that!(name.is_none_or(|n| n == item_name));
|
||||
|
||||
if let Some(from_module) = visible_from_module {
|
||||
if !db.const_visibility(c).is_visible_from(db, from_module) {
|
||||
if !db.assoc_visibility(c.into()).is_visible_from(db, from_module) {
|
||||
cov_mark::hit!(const_candidate_not_visible);
|
||||
return IsValidCandidate::NotVisible;
|
||||
}
|
||||
|
|
@ -1639,7 +1639,7 @@ fn is_valid_impl_fn_candidate(
|
|||
let data = db.function_signature(fn_id);
|
||||
|
||||
if let Some(from_module) = visible_from_module {
|
||||
if !db.function_visibility(fn_id).is_visible_from(db, from_module) {
|
||||
if !db.assoc_visibility(fn_id.into()).is_visible_from(db, from_module) {
|
||||
cov_mark::hit!(autoderef_candidate_not_visible);
|
||||
return IsValidCandidate::NotVisible;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ use triomphe::Arc;
|
|||
|
||||
use crate::{
|
||||
CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, FnDefId, Interner,
|
||||
MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
|
||||
MemoryMap, Substitution, ToChalk, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
|
||||
consteval::{ConstEvalError, intern_const_scalar, try_const_usize},
|
||||
db::{HirDatabase, InternedClosure},
|
||||
display::{ClosureStyle, DisplayTarget, HirDisplay},
|
||||
|
|
@ -1631,7 +1631,7 @@ impl Evaluator<'_> {
|
|||
Variants::Empty => unreachable!(),
|
||||
Variants::Single { index } => {
|
||||
let r =
|
||||
self.const_eval_discriminant(self.db.enum_variants(e).variants[index.0].0)?;
|
||||
self.const_eval_discriminant(e.enum_variants(self.db).variants[index.0].0)?;
|
||||
Ok(r)
|
||||
}
|
||||
Variants::Multiple { tag, tag_encoding, variants, .. } => {
|
||||
|
|
@ -1656,7 +1656,7 @@ impl Evaluator<'_> {
|
|||
.unwrap_or(*untagged_variant)
|
||||
.0;
|
||||
let result =
|
||||
self.const_eval_discriminant(self.db.enum_variants(e).variants[idx].0)?;
|
||||
self.const_eval_discriminant(e.enum_variants(self.db).variants[idx].0)?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
|
@ -2771,12 +2771,15 @@ impl Evaluator<'_> {
|
|||
Err(e) => {
|
||||
let db = self.db;
|
||||
let loc = variant.lookup(db);
|
||||
let enum_loc = loc.parent.lookup(db);
|
||||
let edition = self.crate_id.data(self.db).edition;
|
||||
let name = format!(
|
||||
"{}::{}",
|
||||
enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition),
|
||||
loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
|
||||
self.db.enum_signature(loc.parent).name.display(db, edition),
|
||||
loc.parent
|
||||
.enum_variants(self.db)
|
||||
.variant_name_by_id(variant)
|
||||
.unwrap()
|
||||
.display(db, edition),
|
||||
);
|
||||
Err(MirEvalError::ConstEvalError(name, Box::new(e)))
|
||||
}
|
||||
|
|
@ -2927,7 +2930,7 @@ pub fn render_const_using_debug_impl(
|
|||
let a2 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size())?;
|
||||
evaluator.write_memory(a2, &data.addr.to_bytes())?;
|
||||
let debug_fmt_fn_ptr = evaluator.vtable_map.id(TyKind::FnDef(
|
||||
db.intern_callable_def(debug_fmt_fn.into()).into(),
|
||||
CallableDefId::FunctionId(debug_fmt_fn).to_chalk(db),
|
||||
Substitution::from1(Interner, c.data(Interner).ty.clone()),
|
||||
)
|
||||
.intern(Interner));
|
||||
|
|
|
|||
|
|
@ -65,9 +65,7 @@ impl Evaluator<'_> {
|
|||
Some(abi) => *abi == sym::rust_dash_intrinsic,
|
||||
None => match def.lookup(self.db).container {
|
||||
hir_def::ItemContainerId::ExternBlockId(block) => {
|
||||
let id = block.lookup(self.db).id;
|
||||
id.item_tree(self.db)[id.value].abi.as_ref()
|
||||
== Some(&sym::rust_dash_intrinsic)
|
||||
block.abi(self.db) == Some(sym::rust_dash_intrinsic)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
|
|
@ -86,10 +84,7 @@ impl Evaluator<'_> {
|
|||
);
|
||||
}
|
||||
let is_extern_c = match def.lookup(self.db).container {
|
||||
hir_def::ItemContainerId::ExternBlockId(block) => {
|
||||
let id = block.lookup(self.db).id;
|
||||
id.item_tree(self.db)[id.value].abi.as_ref() == Some(&sym::C)
|
||||
}
|
||||
hir_def::ItemContainerId::ExternBlockId(block) => block.abi(self.db) == Some(sym::C),
|
||||
_ => false,
|
||||
};
|
||||
if is_extern_c {
|
||||
|
|
@ -764,7 +759,9 @@ impl Evaluator<'_> {
|
|||
let size = self.size_of_sized(ty, locals, "size_of arg")?;
|
||||
destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size])
|
||||
}
|
||||
"min_align_of" | "pref_align_of" => {
|
||||
// FIXME: `min_align_of` was renamed to `align_of` in Rust 1.89
|
||||
// (https://github.com/rust-lang/rust/pull/142410)
|
||||
"min_align_of" | "align_of" => {
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
|
|
@ -796,17 +793,19 @@ impl Evaluator<'_> {
|
|||
destination.write_from_bytes(self, &size.to_le_bytes())
|
||||
}
|
||||
}
|
||||
"min_align_of_val" => {
|
||||
// FIXME: `min_align_of_val` was renamed to `align_of_val` in Rust 1.89
|
||||
// (https://github.com/rust-lang/rust/pull/142410)
|
||||
"min_align_of_val" | "align_of_val" => {
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"min_align_of_val generic arg is not provided".into(),
|
||||
"align_of_val generic arg is not provided".into(),
|
||||
));
|
||||
};
|
||||
let [arg] = args else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"min_align_of_val args are not provided".into(),
|
||||
"align_of_val args are not provided".into(),
|
||||
));
|
||||
};
|
||||
if let Some((_, align)) = self.size_align_of(ty, locals)? {
|
||||
|
|
|
|||
|
|
@ -1922,11 +1922,14 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
let edition = self.edition();
|
||||
let db = self.db;
|
||||
let loc = variant.lookup(db);
|
||||
let enum_loc = loc.parent.lookup(db);
|
||||
let name = format!(
|
||||
"{}::{}",
|
||||
enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition),
|
||||
loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
|
||||
self.db.enum_signature(loc.parent).name.display(db, edition),
|
||||
loc.parent
|
||||
.enum_variants(self.db)
|
||||
.variant_name_by_id(variant)
|
||||
.unwrap()
|
||||
.display(db, edition),
|
||||
);
|
||||
Err(MirLowerError::ConstEvalError(name.into(), Box::new(e)))
|
||||
}
|
||||
|
|
@ -2152,7 +2155,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<Mi
|
|||
.to_string(),
|
||||
DefWithBodyId::VariantId(it) => {
|
||||
let loc = it.lookup(db);
|
||||
db.enum_variants(loc.parent).variants[loc.index as usize]
|
||||
loc.parent.enum_variants(db).variants[loc.index as usize]
|
||||
.1
|
||||
.display(db, edition)
|
||||
.to_string()
|
||||
|
|
|
|||
|
|
@ -297,11 +297,8 @@ impl MirLowerCtx<'_> {
|
|||
let result_ref = TyKind::Ref(mutability, error_lifetime(), result_ty).intern(Interner);
|
||||
let mut result: Place = self.temp(result_ref, current, span)?.into();
|
||||
let index_fn_op = Operand::const_zst(
|
||||
TyKind::FnDef(
|
||||
self.db.intern_callable_def(CallableDefId::FunctionId(index_fn.0)).into(),
|
||||
index_fn.1,
|
||||
)
|
||||
.intern(Interner),
|
||||
TyKind::FnDef(CallableDefId::FunctionId(index_fn.0).to_chalk(self.db), index_fn.1)
|
||||
.intern(Interner),
|
||||
);
|
||||
let Some(current) = self.lower_call(
|
||||
index_fn_op,
|
||||
|
|
@ -357,7 +354,7 @@ impl MirLowerCtx<'_> {
|
|||
.ok_or(MirLowerError::LangItemNotFound(trait_lang_item))?;
|
||||
let deref_fn_op = Operand::const_zst(
|
||||
TyKind::FnDef(
|
||||
self.db.intern_callable_def(CallableDefId::FunctionId(deref_fn)).into(),
|
||||
CallableDefId::FunctionId(deref_fn).to_chalk(self.db),
|
||||
Substitution::from1(Interner, source_ty),
|
||||
)
|
||||
.intern(Interner),
|
||||
|
|
|
|||
|
|
@ -63,16 +63,16 @@ impl MirBody {
|
|||
}
|
||||
hir_def::DefWithBodyId::VariantId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let enum_loc = loc.parent.lookup(db);
|
||||
let edition = this.display_target.edition;
|
||||
w!(
|
||||
this,
|
||||
"enum {}::{} = ",
|
||||
enum_loc.id.item_tree(db)[enum_loc.id.value]
|
||||
.name
|
||||
.display(db, this.display_target.edition),
|
||||
loc.id.item_tree(db)[loc.id.value]
|
||||
.name
|
||||
.display(db, this.display_target.edition),
|
||||
db.enum_signature(loc.parent).name.display(db, edition),
|
||||
loc.parent
|
||||
.enum_variants(db)
|
||||
.variant_name_by_id(id)
|
||||
.unwrap()
|
||||
.display(db, edition),
|
||||
)
|
||||
}
|
||||
});
|
||||
|
|
@ -336,7 +336,7 @@ impl<'a> MirPrettyCtx<'a> {
|
|||
w!(
|
||||
this,
|
||||
" as {}).{}",
|
||||
this.db.enum_variants(loc.parent).variants[loc.index as usize]
|
||||
loc.parent.enum_variants(this.db).variants[loc.index as usize]
|
||||
.1
|
||||
.display(this.db, this.display_target.edition),
|
||||
name.display(this.db, this.display_target.edition)
|
||||
|
|
|
|||
|
|
@ -437,7 +437,7 @@ pub(crate) fn visit_module(
|
|||
) {
|
||||
visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb);
|
||||
for impl_id in crate_def_map[module_id].scope.impls() {
|
||||
let impl_data = db.impl_items(impl_id);
|
||||
let impl_data = impl_id.impl_items(db);
|
||||
for &(_, item) in impl_data.items.iter() {
|
||||
match item {
|
||||
AssocItemId::FunctionId(it) => {
|
||||
|
|
@ -479,7 +479,7 @@ pub(crate) fn visit_module(
|
|||
visit_body(db, &body, cb);
|
||||
}
|
||||
ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => {
|
||||
db.enum_variants(it).variants.iter().for_each(|&(it, _)| {
|
||||
it.enum_variants(db).variants.iter().for_each(|&(it, _, _)| {
|
||||
let body = db.body(it.into());
|
||||
cb(it.into());
|
||||
visit_body(db, &body, cb);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use base_db::SourceDatabase;
|
||||
use hir_def::ModuleDefId;
|
||||
use expect_test::Expect;
|
||||
use hir_def::{DefWithBodyId, ModuleDefId};
|
||||
use test_fixture::WithFixture;
|
||||
|
||||
use crate::{db::HirDatabase, test_db::TestDB};
|
||||
|
|
@ -15,8 +16,9 @@ fn foo() -> i32 {
|
|||
$01 + 1
|
||||
}",
|
||||
);
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let crate_def_map = module.def_map(&db);
|
||||
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
||||
|
|
@ -24,9 +26,31 @@ fn foo() -> i32 {
|
|||
db.infer(it.into());
|
||||
}
|
||||
});
|
||||
});
|
||||
assert!(format!("{events:?}").contains("infer_shim"))
|
||||
}
|
||||
},
|
||||
&[("infer_shim", 1)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"source_root_crates_shim",
|
||||
"crate_local_def_map",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"infer_shim",
|
||||
"function_signature_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"attrs_shim",
|
||||
"body_shim",
|
||||
"body_with_source_map_shim",
|
||||
"trait_environment_shim",
|
||||
"return_type_impl_traits_shim",
|
||||
"expr_scopes_shim",
|
||||
"lang_item",
|
||||
"crate_lang_items",
|
||||
"lang_item",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
|
||||
let new_text = "
|
||||
fn foo() -> i32 {
|
||||
|
|
@ -37,8 +61,9 @@ fn foo() -> i32 {
|
|||
|
||||
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
||||
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let crate_def_map = module.def_map(&db);
|
||||
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
||||
|
|
@ -46,9 +71,22 @@ fn foo() -> i32 {
|
|||
db.infer(it.into());
|
||||
}
|
||||
});
|
||||
});
|
||||
assert!(!format!("{events:?}").contains("infer_shim"), "{events:#?}")
|
||||
}
|
||||
},
|
||||
&[("infer_shim", 0)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"attrs_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"function_signature_shim",
|
||||
"body_with_source_map_shim",
|
||||
"body_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -66,8 +104,9 @@ fn baz() -> i32 {
|
|||
1 + 1
|
||||
}",
|
||||
);
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let crate_def_map = module.def_map(&db);
|
||||
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
||||
|
|
@ -75,9 +114,49 @@ fn baz() -> i32 {
|
|||
db.infer(it.into());
|
||||
}
|
||||
});
|
||||
});
|
||||
assert!(format!("{events:?}").contains("infer_shim"))
|
||||
}
|
||||
},
|
||||
&[("infer_shim", 3)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"source_root_crates_shim",
|
||||
"crate_local_def_map",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"infer_shim",
|
||||
"function_signature_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"attrs_shim",
|
||||
"body_shim",
|
||||
"body_with_source_map_shim",
|
||||
"trait_environment_shim",
|
||||
"return_type_impl_traits_shim",
|
||||
"expr_scopes_shim",
|
||||
"lang_item",
|
||||
"crate_lang_items",
|
||||
"attrs_shim",
|
||||
"attrs_shim",
|
||||
"lang_item",
|
||||
"infer_shim",
|
||||
"function_signature_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"body_shim",
|
||||
"body_with_source_map_shim",
|
||||
"trait_environment_shim",
|
||||
"return_type_impl_traits_shim",
|
||||
"expr_scopes_shim",
|
||||
"infer_shim",
|
||||
"function_signature_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"body_shim",
|
||||
"body_with_source_map_shim",
|
||||
"trait_environment_shim",
|
||||
"return_type_impl_traits_shim",
|
||||
"expr_scopes_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
|
||||
let new_text = "
|
||||
fn foo() -> f32 {
|
||||
|
|
@ -93,8 +172,9 @@ fn baz() -> i32 {
|
|||
|
||||
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
||||
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let crate_def_map = module.def_map(&db);
|
||||
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
||||
|
|
@ -102,9 +182,34 @@ fn baz() -> i32 {
|
|||
db.infer(it.into());
|
||||
}
|
||||
});
|
||||
});
|
||||
assert_eq!(format!("{events:?}").matches("infer_shim").count(), 1, "{events:#?}")
|
||||
}
|
||||
},
|
||||
&[("infer_shim", 1)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"attrs_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"function_signature_shim",
|
||||
"body_with_source_map_shim",
|
||||
"body_shim",
|
||||
"attrs_shim",
|
||||
"attrs_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"function_signature_shim",
|
||||
"body_with_source_map_shim",
|
||||
"body_shim",
|
||||
"infer_shim",
|
||||
"expr_scopes_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"function_signature_shim",
|
||||
"body_with_source_map_shim",
|
||||
"body_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -121,14 +226,26 @@ fn bar() -> f32 {
|
|||
}
|
||||
$0",
|
||||
);
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let _crate_def_map = module.def_map(&db);
|
||||
db.trait_impls_in_crate(module.krate());
|
||||
});
|
||||
assert!(format!("{events:?}").contains("trait_impls_in_crate_shim"))
|
||||
}
|
||||
},
|
||||
&[("trait_impls_in_crate_shim", 1)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"source_root_crates_shim",
|
||||
"crate_local_def_map",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"trait_impls_in_crate_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
|
||||
let new_text = "
|
||||
fn foo() -> i32 {
|
||||
|
|
@ -146,24 +263,25 @@ pub struct NewStruct {
|
|||
|
||||
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
||||
|
||||
{
|
||||
let actual = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let _crate_def_map = module.def_map(&db);
|
||||
db.trait_impls_in_crate(module.krate());
|
||||
});
|
||||
|
||||
let expected = vec![
|
||||
"parse_shim".to_owned(),
|
||||
"ast_id_map_shim".to_owned(),
|
||||
"file_item_tree_shim".to_owned(),
|
||||
"real_span_map_shim".to_owned(),
|
||||
"crate_local_def_map".to_owned(),
|
||||
"trait_impls_in_crate_shim".to_owned(),
|
||||
];
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
},
|
||||
&[("trait_impls_in_crate_shim", 1)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"crate_local_def_map",
|
||||
"trait_impls_in_crate_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -180,14 +298,26 @@ fn bar() -> f32 {
|
|||
}
|
||||
$0",
|
||||
);
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let _crate_def_map = module.def_map(&db);
|
||||
db.trait_impls_in_crate(module.krate());
|
||||
});
|
||||
assert!(format!("{events:?}").contains("trait_impls_in_crate_shim"))
|
||||
}
|
||||
},
|
||||
&[("trait_impls_in_crate_shim", 1)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"source_root_crates_shim",
|
||||
"crate_local_def_map",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"trait_impls_in_crate_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
|
||||
let new_text = "
|
||||
fn foo() -> i32 {
|
||||
|
|
@ -206,24 +336,25 @@ pub enum SomeEnum {
|
|||
|
||||
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
||||
|
||||
{
|
||||
let actual = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let _crate_def_map = module.def_map(&db);
|
||||
db.trait_impls_in_crate(module.krate());
|
||||
});
|
||||
|
||||
let expected = vec![
|
||||
"parse_shim".to_owned(),
|
||||
"ast_id_map_shim".to_owned(),
|
||||
"file_item_tree_shim".to_owned(),
|
||||
"real_span_map_shim".to_owned(),
|
||||
"crate_local_def_map".to_owned(),
|
||||
"trait_impls_in_crate_shim".to_owned(),
|
||||
];
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
},
|
||||
&[("trait_impls_in_crate_shim", 1)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"crate_local_def_map",
|
||||
"trait_impls_in_crate_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -240,14 +371,26 @@ fn bar() -> f32 {
|
|||
}
|
||||
$0",
|
||||
);
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let _crate_def_map = module.def_map(&db);
|
||||
db.trait_impls_in_crate(module.krate());
|
||||
});
|
||||
assert!(format!("{events:?}").contains("trait_impls_in_crate_shim"))
|
||||
}
|
||||
},
|
||||
&[("trait_impls_in_crate_shim", 1)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"source_root_crates_shim",
|
||||
"crate_local_def_map",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"trait_impls_in_crate_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
|
||||
let new_text = "
|
||||
use std::collections::HashMap;
|
||||
|
|
@ -263,24 +406,25 @@ fn bar() -> f32 {
|
|||
|
||||
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
||||
|
||||
{
|
||||
let actual = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let _crate_def_map = module.def_map(&db);
|
||||
db.trait_impls_in_crate(module.krate());
|
||||
});
|
||||
|
||||
let expected = vec![
|
||||
"parse_shim".to_owned(),
|
||||
"ast_id_map_shim".to_owned(),
|
||||
"file_item_tree_shim".to_owned(),
|
||||
"real_span_map_shim".to_owned(),
|
||||
"crate_local_def_map".to_owned(),
|
||||
"trait_impls_in_crate_shim".to_owned(),
|
||||
];
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
},
|
||||
&[("trait_impls_in_crate_shim", 1)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"crate_local_def_map",
|
||||
"trait_impls_in_crate_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -301,14 +445,26 @@ pub struct SomeStruct {
|
|||
}
|
||||
$0",
|
||||
);
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let _crate_def_map = module.def_map(&db);
|
||||
db.trait_impls_in_crate(module.krate());
|
||||
});
|
||||
assert!(format!("{events:?}").contains("trait_impls_in_crate_shim"))
|
||||
}
|
||||
},
|
||||
&[("trait_impls_in_crate_shim", 1)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"source_root_crates_shim",
|
||||
"crate_local_def_map",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"trait_impls_in_crate_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
|
||||
let new_text = "
|
||||
fn foo() -> i32 {
|
||||
|
|
@ -332,30 +488,243 @@ impl SomeStruct {
|
|||
|
||||
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
||||
|
||||
{
|
||||
let actual = db.log_executed(|| {
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let _crate_def_map = module.def_map(&db);
|
||||
db.trait_impls_in_crate(module.krate());
|
||||
});
|
||||
|
||||
let expected = vec![
|
||||
"parse_shim".to_owned(),
|
||||
"ast_id_map_shim".to_owned(),
|
||||
"file_item_tree_shim".to_owned(),
|
||||
"real_span_map_shim".to_owned(),
|
||||
"crate_local_def_map".to_owned(),
|
||||
"trait_impls_in_crate_shim".to_owned(),
|
||||
"attrs_shim".to_owned(),
|
||||
"impl_trait_with_diagnostics_shim".to_owned(),
|
||||
"impl_signature_shim".to_owned(),
|
||||
"impl_signature_with_source_map_shim".to_owned(),
|
||||
"impl_self_ty_with_diagnostics_shim".to_owned(),
|
||||
"struct_signature_shim".to_owned(),
|
||||
"struct_signature_with_source_map_shim".to_owned(),
|
||||
"type_for_adt_tracked".to_owned(),
|
||||
];
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
},
|
||||
&[("trait_impls_in_crate_shim", 1)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"crate_local_def_map",
|
||||
"trait_impls_in_crate_shim",
|
||||
"attrs_shim",
|
||||
"impl_trait_with_diagnostics_shim",
|
||||
"impl_signature_shim",
|
||||
"impl_signature_with_source_map_shim",
|
||||
"impl_self_ty_with_diagnostics_shim",
|
||||
"struct_signature_shim",
|
||||
"struct_signature_with_source_map_shim",
|
||||
"attrs_shim",
|
||||
"type_for_adt_tracked",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_struct_invalidates_trait_solve() {
|
||||
let (mut db, file_id) = TestDB::with_single_file(
|
||||
"
|
||||
//- /main.rs crate:main
|
||||
struct SomeStruct;
|
||||
|
||||
trait Trait<T> {
|
||||
fn method(&self) -> T;
|
||||
}
|
||||
impl Trait<u32> for SomeStruct {}
|
||||
|
||||
fn main() {
|
||||
let s = SomeStruct;
|
||||
s.method();
|
||||
s.$0
|
||||
}",
|
||||
);
|
||||
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(file_id.file_id(&db));
|
||||
let crate_def_map = module.def_map(&db);
|
||||
let mut defs: Vec<DefWithBodyId> = vec![];
|
||||
visit_module(&db, crate_def_map, module.local_id, &mut |it| {
|
||||
let def = match it {
|
||||
ModuleDefId::FunctionId(it) => it.into(),
|
||||
ModuleDefId::EnumVariantId(it) => it.into(),
|
||||
ModuleDefId::ConstId(it) => it.into(),
|
||||
ModuleDefId::StaticId(it) => it.into(),
|
||||
_ => return,
|
||||
};
|
||||
defs.push(def);
|
||||
});
|
||||
|
||||
for def in defs {
|
||||
let _inference_result = db.infer(def);
|
||||
}
|
||||
},
|
||||
&[("trait_solve_shim", 2)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"source_root_crates_shim",
|
||||
"crate_local_def_map",
|
||||
"file_item_tree_query",
|
||||
"ast_id_map_shim",
|
||||
"parse_shim",
|
||||
"real_span_map_shim",
|
||||
"trait_items_with_diagnostics_shim",
|
||||
"body_shim",
|
||||
"body_with_source_map_shim",
|
||||
"attrs_shim",
|
||||
"of_",
|
||||
"infer_shim",
|
||||
"trait_signature_shim",
|
||||
"trait_signature_with_source_map_shim",
|
||||
"attrs_shim",
|
||||
"function_signature_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"attrs_shim",
|
||||
"body_shim",
|
||||
"body_with_source_map_shim",
|
||||
"trait_environment_shim",
|
||||
"lang_item",
|
||||
"crate_lang_items",
|
||||
"attrs_shim",
|
||||
"attrs_shim",
|
||||
"return_type_impl_traits_shim",
|
||||
"infer_shim",
|
||||
"function_signature_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"trait_environment_shim",
|
||||
"expr_scopes_shim",
|
||||
"struct_signature_shim",
|
||||
"struct_signature_with_source_map_shim",
|
||||
"generic_predicates_shim",
|
||||
"value_ty_shim",
|
||||
"variant_fields_shim",
|
||||
"variant_fields_with_source_map_shim",
|
||||
"lang_item",
|
||||
"inherent_impls_in_crate_shim",
|
||||
"impl_signature_shim",
|
||||
"impl_signature_with_source_map_shim",
|
||||
"callable_item_signature_shim",
|
||||
"adt_variance_shim",
|
||||
"variances_of_shim",
|
||||
"trait_solve_shim",
|
||||
"trait_datum_shim",
|
||||
"generic_predicates_shim",
|
||||
"adt_datum_shim",
|
||||
"trait_impls_in_deps_shim",
|
||||
"trait_impls_in_crate_shim",
|
||||
"impl_trait_with_diagnostics_shim",
|
||||
"impl_self_ty_with_diagnostics_shim",
|
||||
"type_for_adt_tracked",
|
||||
"impl_datum_shim",
|
||||
"generic_predicates_shim",
|
||||
"program_clauses_for_chalk_env_shim",
|
||||
"value_ty_shim",
|
||||
"generic_predicates_shim",
|
||||
"trait_solve_shim",
|
||||
"lang_item",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
|
||||
let new_text = "
|
||||
//- /main.rs crate:main
|
||||
struct AnotherStruct;
|
||||
|
||||
struct SomeStruct;
|
||||
|
||||
trait Trait<T> {
|
||||
fn method(&self) -> T;
|
||||
}
|
||||
impl Trait<u32> for SomeStruct {}
|
||||
|
||||
fn main() {
|
||||
let s = SomeStruct;
|
||||
s.method();
|
||||
s.$0
|
||||
}";
|
||||
|
||||
db.set_file_text(file_id.file_id(&db), new_text);
|
||||
|
||||
execute_assert_events(
|
||||
&db,
|
||||
|| {
|
||||
let module = db.module_for_file(file_id.file_id(&db));
|
||||
let crate_def_map = module.def_map(&db);
|
||||
let mut defs: Vec<DefWithBodyId> = vec![];
|
||||
|
||||
visit_module(&db, crate_def_map, module.local_id, &mut |it| {
|
||||
let def = match it {
|
||||
ModuleDefId::FunctionId(it) => it.into(),
|
||||
ModuleDefId::EnumVariantId(it) => it.into(),
|
||||
ModuleDefId::ConstId(it) => it.into(),
|
||||
ModuleDefId::StaticId(it) => it.into(),
|
||||
_ => return,
|
||||
};
|
||||
defs.push(def);
|
||||
});
|
||||
|
||||
for def in defs {
|
||||
let _inference_result = db.infer(def);
|
||||
}
|
||||
},
|
||||
&[("trait_solve_shim", 0)],
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
"parse_shim",
|
||||
"ast_id_map_shim",
|
||||
"file_item_tree_query",
|
||||
"real_span_map_shim",
|
||||
"crate_local_def_map",
|
||||
"trait_items_with_diagnostics_shim",
|
||||
"body_with_source_map_shim",
|
||||
"attrs_shim",
|
||||
"body_shim",
|
||||
"of_",
|
||||
"infer_shim",
|
||||
"attrs_shim",
|
||||
"trait_signature_with_source_map_shim",
|
||||
"attrs_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"function_signature_shim",
|
||||
"body_with_source_map_shim",
|
||||
"body_shim",
|
||||
"trait_environment_shim",
|
||||
"crate_lang_items",
|
||||
"attrs_shim",
|
||||
"attrs_shim",
|
||||
"attrs_shim",
|
||||
"return_type_impl_traits_shim",
|
||||
"infer_shim",
|
||||
"function_signature_with_source_map_shim",
|
||||
"trait_environment_shim",
|
||||
"expr_scopes_shim",
|
||||
"struct_signature_with_source_map_shim",
|
||||
"generic_predicates_shim",
|
||||
"variant_fields_with_source_map_shim",
|
||||
"inherent_impls_in_crate_shim",
|
||||
"impl_signature_with_source_map_shim",
|
||||
"impl_signature_shim",
|
||||
"callable_item_signature_shim",
|
||||
"generic_predicates_shim",
|
||||
"trait_impls_in_crate_shim",
|
||||
"impl_trait_with_diagnostics_shim",
|
||||
"impl_self_ty_with_diagnostics_shim",
|
||||
"generic_predicates_shim",
|
||||
"generic_predicates_shim",
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
fn execute_assert_events(
|
||||
db: &TestDB,
|
||||
f: impl FnOnce(),
|
||||
required: &[(&str, usize)],
|
||||
expect: Expect,
|
||||
) {
|
||||
let events = db.log_executed(f);
|
||||
for (event, count) in required {
|
||||
let n = events.iter().filter(|it| it.contains(event)).count();
|
||||
assert_eq!(n, *count, "Expected {event} to be executed {count} times, but only got {n}");
|
||||
}
|
||||
expect.assert_debug_eq(&events);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ impl DebugContext<'_> {
|
|||
CallableDefId::StructId(s) => self.0.struct_signature(s).name.clone(),
|
||||
CallableDefId::EnumVariantId(e) => {
|
||||
let loc = e.lookup(self.0);
|
||||
self.0.enum_variants(loc.parent).variants[loc.index as usize].1.clone()
|
||||
loc.parent.enum_variants(self.0).variants[loc.index as usize].1.clone()
|
||||
}
|
||||
};
|
||||
match def {
|
||||
|
|
|
|||
|
|
@ -293,9 +293,7 @@ pub fn is_fn_unsafe_to_call(
|
|||
let loc = func.lookup(db);
|
||||
match loc.container {
|
||||
hir_def::ItemContainerId::ExternBlockId(block) => {
|
||||
let id = block.lookup(db).id;
|
||||
let is_intrinsic_block =
|
||||
id.item_tree(db)[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic);
|
||||
let is_intrinsic_block = block.abi(db) == Some(sym::rust_dash_intrinsic);
|
||||
if is_intrinsic_block {
|
||||
// legacy intrinsics
|
||||
// extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
|
||||
|
|
@ -357,7 +355,7 @@ pub(crate) fn detect_variant_from_bytes<'a>(
|
|||
let (var_id, var_layout) = match &layout.variants {
|
||||
hir_def::layout::Variants::Empty => unreachable!(),
|
||||
hir_def::layout::Variants::Single { index } => {
|
||||
(db.enum_variants(e).variants[index.0].0, layout)
|
||||
(e.enum_variants(db).variants[index.0].0, layout)
|
||||
}
|
||||
hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => {
|
||||
let size = tag.size(target_data_layout).bytes_usize();
|
||||
|
|
@ -367,7 +365,7 @@ pub(crate) fn detect_variant_from_bytes<'a>(
|
|||
TagEncoding::Direct => {
|
||||
let (var_idx, layout) =
|
||||
variants.iter_enumerated().find_map(|(var_idx, v)| {
|
||||
let def = db.enum_variants(e).variants[var_idx.0].0;
|
||||
let def = e.enum_variants(db).variants[var_idx.0].0;
|
||||
(db.const_eval_discriminant(def) == Ok(tag)).then_some((def, v))
|
||||
})?;
|
||||
(var_idx, layout)
|
||||
|
|
@ -380,7 +378,7 @@ pub(crate) fn detect_variant_from_bytes<'a>(
|
|||
.filter(|x| x != untagged_variant)
|
||||
.nth(candidate_tag)
|
||||
.unwrap_or(*untagged_variant);
|
||||
(db.enum_variants(e).variants[variant.0].0, &variants[variant])
|
||||
(e.enum_variants(db).variants[variant.0].0, &variants[variant])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ impl Context<'_> {
|
|||
AdtId::StructId(s) => add_constraints_from_variant(VariantId::StructId(s)),
|
||||
AdtId::UnionId(u) => add_constraints_from_variant(VariantId::UnionId(u)),
|
||||
AdtId::EnumId(e) => {
|
||||
db.enum_variants(e).variants.iter().for_each(|&(variant, _)| {
|
||||
e.enum_variants(db).variants.iter().for_each(|&(variant, _, _)| {
|
||||
add_constraints_from_variant(VariantId::EnumVariantId(variant))
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,12 +52,14 @@ use hir_def::{
|
|||
BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat,
|
||||
generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
|
||||
},
|
||||
item_tree::{AttrOwner, FieldParent, ImportAlias, ItemTreeFieldId, ItemTreeNode},
|
||||
item_tree::ImportAlias,
|
||||
layout::{self, ReprOptions, TargetDataLayout},
|
||||
nameres::{self, diagnostics::DefDiagnostic},
|
||||
per_ns::PerNs,
|
||||
resolver::{HasResolver, Resolver},
|
||||
signatures::{ImplFlags, StaticFlags, TraitFlags, VariantFields},
|
||||
src::HasSource as _,
|
||||
visibility::visibility_from_ast,
|
||||
};
|
||||
use hir_expand::{
|
||||
AstId, MacroCallKind, RenderedExpandError, ValueResult, attrs::collect_attrs,
|
||||
|
|
@ -81,11 +83,11 @@ use itertools::Itertools;
|
|||
use nameres::diagnostics::DefDiagnosticKind;
|
||||
use rustc_hash::FxHashSet;
|
||||
use smallvec::SmallVec;
|
||||
use span::{Edition, FileId};
|
||||
use span::{AstIdNode, Edition, FileId};
|
||||
use stdx::{format_to, impl_from, never};
|
||||
use syntax::{
|
||||
AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr,
|
||||
ast::{self, HasAttrs as _, HasName},
|
||||
ast::{self, HasAttrs as _, HasName, HasVisibility as _},
|
||||
format_smolstr,
|
||||
};
|
||||
use triomphe::{Arc, ThinArc};
|
||||
|
|
@ -686,8 +688,8 @@ impl Module {
|
|||
Adt::Enum(e) => {
|
||||
let source_map = db.enum_signature_with_source_map(e.id).1;
|
||||
expr_store_diagnostics(db, acc, &source_map);
|
||||
let (variants, diagnostics) = db.enum_variants_with_diagnostics(e.id);
|
||||
let file = e.id.lookup(db).id.file_id();
|
||||
let (variants, diagnostics) = e.id.enum_variants_with_diagnostics(db);
|
||||
let file = e.id.lookup(db).id.file_id;
|
||||
let ast_id_map = db.ast_id_map(file);
|
||||
if let Some(diagnostics) = &diagnostics {
|
||||
for diag in diagnostics.iter() {
|
||||
|
|
@ -704,7 +706,7 @@ impl Module {
|
|||
);
|
||||
}
|
||||
}
|
||||
for &(v, _) in &variants.variants {
|
||||
for &(v, _, _) in &variants.variants {
|
||||
let source_map = db.variant_fields_with_source_map(v.into()).1;
|
||||
push_ty_diagnostics(
|
||||
db,
|
||||
|
|
@ -742,12 +744,10 @@ impl Module {
|
|||
GenericDef::Impl(impl_def).diagnostics(db, acc);
|
||||
|
||||
let loc = impl_def.id.lookup(db);
|
||||
let tree = loc.id.item_tree(db);
|
||||
let source_map = db.impl_signature_with_source_map(impl_def.id).1;
|
||||
expr_store_diagnostics(db, acc, &source_map);
|
||||
|
||||
let node = &tree[loc.id.value];
|
||||
let file_id = loc.id.file_id();
|
||||
let file_id = loc.id.file_id;
|
||||
if file_id.macro_file().is_some_and(|it| it.kind(db) == MacroKind::DeriveBuiltIn) {
|
||||
// these expansion come from us, diagnosing them is a waste of resources
|
||||
// FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow
|
||||
|
|
@ -760,16 +760,16 @@ impl Module {
|
|||
|
||||
let ast_id_map = db.ast_id_map(file_id);
|
||||
|
||||
for diag in db.impl_items_with_diagnostics(impl_def.id).1.iter() {
|
||||
for diag in impl_def.id.impl_items_with_diagnostics(db).1.iter() {
|
||||
emit_def_diagnostic(db, acc, diag, edition);
|
||||
}
|
||||
|
||||
if inherent_impls.invalid_impls().contains(&impl_def.id) {
|
||||
acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into())
|
||||
acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into())
|
||||
}
|
||||
|
||||
if !impl_def.check_orphan_rules(db) {
|
||||
acc.push(TraitImplOrphan { impl_: ast_id_map.get(node.ast_id()), file_id }.into())
|
||||
acc.push(TraitImplOrphan { impl_: ast_id_map.get(loc.id.value), file_id }.into())
|
||||
}
|
||||
|
||||
let trait_ = impl_def.trait_(db);
|
||||
|
|
@ -808,11 +808,11 @@ impl Module {
|
|||
// unsafe negative impl
|
||||
(true, _, true, _) |
|
||||
// unsafe impl for safe trait
|
||||
(true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: true }.into()),
|
||||
(true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: true }.into()),
|
||||
// safe impl for unsafe trait
|
||||
(false, true, false, _) |
|
||||
// safe impl of dangling drop
|
||||
(false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: false }.into()),
|
||||
(false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: false }.into()),
|
||||
_ => (),
|
||||
};
|
||||
|
||||
|
|
@ -824,7 +824,7 @@ impl Module {
|
|||
AssocItemId::ConstId(id) => !db.const_signature(id).has_body(),
|
||||
AssocItemId::TypeAliasId(it) => db.type_alias_signature(it).ty.is_none(),
|
||||
});
|
||||
impl_assoc_items_scratch.extend(db.impl_items(impl_def.id).items.iter().cloned());
|
||||
impl_assoc_items_scratch.extend(impl_def.id.impl_items(db).items.iter().cloned());
|
||||
|
||||
let redundant = impl_assoc_items_scratch
|
||||
.iter()
|
||||
|
|
@ -839,14 +839,14 @@ impl Module {
|
|||
TraitImplRedundantAssocItems {
|
||||
trait_,
|
||||
file_id,
|
||||
impl_: ast_id_map.get(node.ast_id()),
|
||||
impl_: ast_id_map.get(loc.id.value),
|
||||
assoc_item: (name, assoc_item),
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
let missing: Vec<_> = required_items
|
||||
let mut missing: Vec<_> = required_items
|
||||
.filter(|(name, id)| {
|
||||
!impl_assoc_items_scratch.iter().any(|(impl_name, impl_item)| {
|
||||
discriminant(impl_item) == discriminant(id) && impl_name == name
|
||||
|
|
@ -854,10 +854,42 @@ impl Module {
|
|||
})
|
||||
.map(|(name, item)| (name.clone(), AssocItem::from(*item)))
|
||||
.collect();
|
||||
|
||||
if !missing.is_empty() {
|
||||
let self_ty = db.impl_self_ty(impl_def.id).substitute(
|
||||
Interner,
|
||||
&hir_ty::generics::generics(db, impl_def.id.into()).placeholder_subst(db),
|
||||
);
|
||||
let self_ty = if let TyKind::Alias(AliasTy::Projection(projection)) =
|
||||
self_ty.kind(Interner)
|
||||
{
|
||||
db.normalize_projection(
|
||||
projection.clone(),
|
||||
db.trait_environment(impl_def.id.into()),
|
||||
)
|
||||
} else {
|
||||
self_ty
|
||||
};
|
||||
let self_ty_is_guaranteed_unsized = matches!(
|
||||
self_ty.kind(Interner),
|
||||
TyKind::Dyn(..) | TyKind::Slice(..) | TyKind::Str
|
||||
);
|
||||
if self_ty_is_guaranteed_unsized {
|
||||
missing.retain(|(_, assoc_item)| {
|
||||
let assoc_item = match *assoc_item {
|
||||
AssocItem::Function(it) => it.id.into(),
|
||||
AssocItem::Const(it) => it.id.into(),
|
||||
AssocItem::TypeAlias(it) => it.id.into(),
|
||||
};
|
||||
!hir_ty::dyn_compatibility::generics_require_sized_self(db, assoc_item)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if !missing.is_empty() {
|
||||
acc.push(
|
||||
TraitImplMissingAssocItems {
|
||||
impl_: ast_id_map.get(node.ast_id()),
|
||||
impl_: ast_id_map.get(loc.id.value),
|
||||
file_id,
|
||||
missing,
|
||||
}
|
||||
|
|
@ -880,7 +912,7 @@ impl Module {
|
|||
&source_map,
|
||||
);
|
||||
|
||||
for &(_, item) in db.impl_items(impl_def.id).items.iter() {
|
||||
for &(_, item) in impl_def.id.impl_items(db).items.iter() {
|
||||
AssocItem::from(item).diagnostics(db, acc, style_lints);
|
||||
}
|
||||
}
|
||||
|
|
@ -1044,73 +1076,25 @@ fn emit_def_diagnostic_(
|
|||
)
|
||||
}
|
||||
DefDiagnosticKind::UnresolvedImport { id, index } => {
|
||||
let file_id = id.file_id();
|
||||
let item_tree = id.item_tree(db);
|
||||
let import = &item_tree[id.value];
|
||||
let file_id = id.file_id;
|
||||
|
||||
let use_tree = import.use_tree_to_ast(db, file_id, *index);
|
||||
let use_tree = hir_def::src::use_tree_to_ast(db, *id, *index);
|
||||
acc.push(
|
||||
UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(),
|
||||
);
|
||||
}
|
||||
|
||||
DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts } => {
|
||||
let item_tree = tree.item_tree(db);
|
||||
let ast_id_map = db.ast_id_map(tree.file_id());
|
||||
// FIXME: This parses... We could probably store relative ranges for the children things
|
||||
// here in the item tree?
|
||||
(|| {
|
||||
let process_field_list =
|
||||
|field_list: Option<_>, idx: ItemTreeFieldId| match field_list? {
|
||||
ast::FieldList::RecordFieldList(it) => Some(SyntaxNodePtr::new(
|
||||
it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(),
|
||||
)),
|
||||
ast::FieldList::TupleFieldList(it) => Some(SyntaxNodePtr::new(
|
||||
it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(),
|
||||
)),
|
||||
};
|
||||
let ptr = match *item {
|
||||
AttrOwner::ModItem(it) => {
|
||||
ast_id_map.get(it.ast_id(&item_tree)).syntax_node_ptr()
|
||||
}
|
||||
AttrOwner::TopLevel => ast_id_map.root(),
|
||||
AttrOwner::Variant(it) => {
|
||||
ast_id_map.get(item_tree[it].ast_id).syntax_node_ptr()
|
||||
}
|
||||
AttrOwner::Field(FieldParent::EnumVariant(parent), idx) => process_field_list(
|
||||
ast_id_map
|
||||
.get(item_tree[parent].ast_id)
|
||||
.to_node(&db.parse_or_expand(tree.file_id()))
|
||||
.field_list(),
|
||||
idx,
|
||||
)?,
|
||||
AttrOwner::Field(FieldParent::Struct(parent), idx) => process_field_list(
|
||||
ast_id_map
|
||||
.get(item_tree[parent.index()].ast_id)
|
||||
.to_node(&db.parse_or_expand(tree.file_id()))
|
||||
.field_list(),
|
||||
idx,
|
||||
)?,
|
||||
AttrOwner::Field(FieldParent::Union(parent), idx) => SyntaxNodePtr::new(
|
||||
ast_id_map
|
||||
.get(item_tree[parent.index()].ast_id)
|
||||
.to_node(&db.parse_or_expand(tree.file_id()))
|
||||
.record_field_list()?
|
||||
.fields()
|
||||
.nth(idx.into_raw().into_u32() as usize)?
|
||||
.syntax(),
|
||||
),
|
||||
};
|
||||
acc.push(
|
||||
InactiveCode {
|
||||
node: InFile::new(tree.file_id(), ptr),
|
||||
cfg: cfg.clone(),
|
||||
opts: opts.clone(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
Some(())
|
||||
})();
|
||||
DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts } => {
|
||||
let ast_id_map = db.ast_id_map(ast_id.file_id);
|
||||
let ptr = ast_id_map.get_erased(ast_id.value);
|
||||
acc.push(
|
||||
InactiveCode {
|
||||
node: InFile::new(ast_id.file_id, ptr),
|
||||
cfg: cfg.clone(),
|
||||
opts: opts.clone(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
|
||||
let (node, precise_location) = precise_macro_call_location(ast, db);
|
||||
|
|
@ -1446,12 +1430,8 @@ impl Struct {
|
|||
impl HasVisibility for Struct {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
let loc = self.id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
Visibility::resolve(
|
||||
db,
|
||||
&self.id.resolver(db),
|
||||
&item_tree[item_tree[loc.id.value].visibility],
|
||||
)
|
||||
let source = loc.source(db);
|
||||
visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1504,12 +1484,8 @@ impl Union {
|
|||
impl HasVisibility for Union {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
let loc = self.id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
Visibility::resolve(
|
||||
db,
|
||||
&self.id.resolver(db),
|
||||
&item_tree[item_tree[loc.id.value].visibility],
|
||||
)
|
||||
let source = loc.source(db);
|
||||
visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1528,11 +1504,11 @@ impl Enum {
|
|||
}
|
||||
|
||||
pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> {
|
||||
db.enum_variants(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect()
|
||||
self.id.enum_variants(db).variants.iter().map(|&(id, _, _)| Variant { id }).collect()
|
||||
}
|
||||
|
||||
pub fn num_variants(self, db: &dyn HirDatabase) -> usize {
|
||||
db.enum_variants(self.id).variants.len()
|
||||
self.id.enum_variants(db).variants.len()
|
||||
}
|
||||
|
||||
pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> {
|
||||
|
|
@ -1597,12 +1573,8 @@ impl Enum {
|
|||
impl HasVisibility for Enum {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
let loc = self.id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
Visibility::resolve(
|
||||
db,
|
||||
&self.id.resolver(db),
|
||||
&item_tree[item_tree[loc.id.value].visibility],
|
||||
)
|
||||
let source = loc.source(db);
|
||||
visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1634,7 +1606,7 @@ impl Variant {
|
|||
pub fn name(self, db: &dyn HirDatabase) -> Name {
|
||||
let lookup = self.id.lookup(db);
|
||||
let enum_ = lookup.parent;
|
||||
db.enum_variants(enum_).variants[lookup.index as usize].1.clone()
|
||||
enum_.enum_variants(db).variants[lookup.index as usize].1.clone()
|
||||
}
|
||||
|
||||
pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
|
||||
|
|
@ -2660,7 +2632,7 @@ impl SelfParam {
|
|||
|
||||
impl HasVisibility for Function {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
db.function_visibility(self.id)
|
||||
db.assoc_visibility(self.id.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2676,10 +2648,9 @@ impl ExternCrateDecl {
|
|||
|
||||
pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option<Crate> {
|
||||
let loc = self.id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let krate = loc.container.krate();
|
||||
let name = &item_tree[loc.id.value].name;
|
||||
if *name == sym::self_ {
|
||||
let name = self.name(db);
|
||||
if name == sym::self_ {
|
||||
Some(krate.into())
|
||||
} else {
|
||||
krate.data(db).dependencies.iter().find_map(|dep| {
|
||||
|
|
@ -2690,25 +2661,29 @@ impl ExternCrateDecl {
|
|||
|
||||
pub fn name(self, db: &dyn HirDatabase) -> Name {
|
||||
let loc = self.id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
item_tree[loc.id.value].name.clone()
|
||||
let source = loc.source(db);
|
||||
as_name_opt(source.value.name_ref())
|
||||
}
|
||||
|
||||
pub fn alias(self, db: &dyn HirDatabase) -> Option<ImportAlias> {
|
||||
let loc = self.id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
item_tree[loc.id.value].alias.clone()
|
||||
let source = loc.source(db);
|
||||
let rename = source.value.rename()?;
|
||||
if let Some(name) = rename.name() {
|
||||
Some(ImportAlias::Alias(name.as_name()))
|
||||
} else if rename.underscore_token().is_some() {
|
||||
Some(ImportAlias::Underscore)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the name under which this crate is made accessible, taking `_` into account.
|
||||
pub fn alias_or_name(self, db: &dyn HirDatabase) -> Option<Name> {
|
||||
let loc = self.id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
match &item_tree[loc.id.value].alias {
|
||||
match self.alias(db) {
|
||||
Some(ImportAlias::Underscore) => None,
|
||||
Some(ImportAlias::Alias(alias)) => Some(alias.clone()),
|
||||
None => Some(item_tree[loc.id.value].name.clone()),
|
||||
Some(ImportAlias::Alias(alias)) => Some(alias),
|
||||
None => Some(self.name(db)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2716,12 +2691,8 @@ impl ExternCrateDecl {
|
|||
impl HasVisibility for ExternCrateDecl {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
let loc = self.id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
Visibility::resolve(
|
||||
db,
|
||||
&self.id.resolver(db),
|
||||
&item_tree[item_tree[loc.id.value].visibility],
|
||||
)
|
||||
let source = loc.source(db);
|
||||
visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2756,7 +2727,7 @@ impl Const {
|
|||
|
||||
impl HasVisibility for Const {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
db.const_visibility(self.id)
|
||||
db.assoc_visibility(self.id.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2841,12 +2812,8 @@ impl Static {
|
|||
impl HasVisibility for Static {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
let loc = self.id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
Visibility::resolve(
|
||||
db,
|
||||
&self.id.resolver(db),
|
||||
&item_tree[item_tree[loc.id.value].visibility],
|
||||
)
|
||||
let source = loc.source(db);
|
||||
visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2935,11 +2902,7 @@ impl Trait {
|
|||
}
|
||||
|
||||
fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
|
||||
db.trait_items(self.id)
|
||||
.macro_calls
|
||||
.as_ref()
|
||||
.map(|it| it.as_ref().clone().into_boxed_slice())
|
||||
.unwrap_or_default()
|
||||
db.trait_items(self.id).macro_calls.to_vec().into_boxed_slice()
|
||||
}
|
||||
|
||||
/// `#[rust_analyzer::completions(...)]` mode.
|
||||
|
|
@ -2951,12 +2914,8 @@ impl Trait {
|
|||
impl HasVisibility for Trait {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
let loc = self.id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
Visibility::resolve(
|
||||
db,
|
||||
&self.id.resolver(db),
|
||||
&item_tree[item_tree[loc.id.value].visibility],
|
||||
)
|
||||
let source = loc.source(db);
|
||||
visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2978,12 +2937,8 @@ impl TraitAlias {
|
|||
impl HasVisibility for TraitAlias {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
let loc = self.id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
Visibility::resolve(
|
||||
db,
|
||||
&self.id.resolver(db),
|
||||
&item_tree[item_tree[loc.id.value].visibility],
|
||||
)
|
||||
let source = loc.source(db);
|
||||
visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3021,7 +2976,7 @@ impl TypeAlias {
|
|||
|
||||
impl HasVisibility for TypeAlias {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
db.type_alias_visibility(self.id)
|
||||
db.assoc_visibility(self.id.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3131,25 +3086,23 @@ impl Macro {
|
|||
match self.id {
|
||||
MacroId::Macro2Id(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
item_tree[loc.id.value].name.clone()
|
||||
let source = loc.source(db);
|
||||
as_name_opt(source.value.name())
|
||||
}
|
||||
MacroId::MacroRulesId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
item_tree[loc.id.value].name.clone()
|
||||
let source = loc.source(db);
|
||||
as_name_opt(source.value.name())
|
||||
}
|
||||
MacroId::ProcMacroId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let source = loc.source(db);
|
||||
match loc.kind {
|
||||
ProcMacroKind::CustomDerive => db
|
||||
.attrs(id.into())
|
||||
.parse_proc_macro_derive()
|
||||
.map_or_else(|| item_tree[loc.id.value].name.clone(), |(it, _)| it),
|
||||
ProcMacroKind::Bang | ProcMacroKind::Attr => {
|
||||
item_tree[loc.id.value].name.clone()
|
||||
}
|
||||
.map_or_else(|| as_name_opt(source.value.name()), |(it, _)| it),
|
||||
ProcMacroKind::Bang | ProcMacroKind::Attr => as_name_opt(source.value.name()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3246,12 +3199,8 @@ impl HasVisibility for Macro {
|
|||
match self.id {
|
||||
MacroId::Macro2Id(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
Visibility::resolve(
|
||||
db,
|
||||
&id.resolver(db),
|
||||
&item_tree[item_tree[loc.id.value].visibility],
|
||||
)
|
||||
let source = loc.source(db);
|
||||
visibility_from_ast(db, id, source.map(|src| src.visibility()))
|
||||
}
|
||||
MacroId::MacroRulesId(_) => Visibility::Public,
|
||||
MacroId::ProcMacroId(_) => Visibility::Public,
|
||||
|
|
@ -3405,7 +3354,7 @@ fn as_assoc_item<'db, ID, DEF, LOC>(
|
|||
where
|
||||
ID: Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<LOC>>,
|
||||
DEF: From<ID>,
|
||||
LOC: ItemTreeNode,
|
||||
LOC: AstIdNode,
|
||||
{
|
||||
match id.lookup(db).container {
|
||||
ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
|
||||
|
|
@ -3421,7 +3370,7 @@ fn as_extern_assoc_item<'db, ID, DEF, LOC>(
|
|||
where
|
||||
ID: Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<LOC>>,
|
||||
DEF: From<ID>,
|
||||
LOC: ItemTreeNode,
|
||||
LOC: AstIdNode,
|
||||
{
|
||||
match id.lookup(db).container {
|
||||
ItemContainerId::ExternBlockId(_) => Some(ctor(DEF::from(id))),
|
||||
|
|
@ -4464,7 +4413,7 @@ impl Impl {
|
|||
}
|
||||
|
||||
pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
|
||||
db.impl_items(self.id).items.iter().map(|&(_, it)| it.into()).collect()
|
||||
self.id.impl_items(db).items.iter().map(|&(_, it)| it.into()).collect()
|
||||
}
|
||||
|
||||
pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
|
||||
|
|
@ -4513,11 +4462,7 @@ impl Impl {
|
|||
}
|
||||
|
||||
fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
|
||||
db.impl_items(self.id)
|
||||
.macro_calls
|
||||
.as_ref()
|
||||
.map(|it| it.as_ref().clone().into_boxed_slice())
|
||||
.unwrap_or_default()
|
||||
self.id.impl_items(db).macro_calls.to_vec().into_boxed_slice()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5326,7 +5271,7 @@ impl Type {
|
|||
let impls = db.inherent_impls_in_crate(krate);
|
||||
|
||||
for impl_def in impls.for_self_ty(&self.ty) {
|
||||
for &(_, item) in db.impl_items(*impl_def).items.iter() {
|
||||
for &(_, item) in impl_def.impl_items(db).items.iter() {
|
||||
if callback(item) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -6478,3 +6423,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>(
|
|||
})
|
||||
.flatten()
|
||||
}
|
||||
|
||||
fn as_name_opt(name: Option<impl AsName>) -> Name {
|
||||
name.map_or_else(Name::missing, |name| name.as_name())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ use hir_expand::{
|
|||
builtin::{BuiltinFnLikeExpander, EagerExpander},
|
||||
db::ExpandDatabase,
|
||||
files::{FileRangeWrapper, HirFileRange, InRealFile},
|
||||
inert_attr_macro::find_builtin_attr_idx,
|
||||
mod_path::{ModPath, PathKind},
|
||||
name::AsName,
|
||||
};
|
||||
|
|
@ -159,13 +158,13 @@ pub struct SemanticsImpl<'db> {
|
|||
macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroCallId>>,
|
||||
}
|
||||
|
||||
impl<DB> fmt::Debug for Semantics<'_, DB> {
|
||||
impl<DB: ?Sized> fmt::Debug for Semantics<'_, DB> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Semantics {{ ... }}")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db, DB> ops::Deref for Semantics<'db, DB> {
|
||||
impl<'db, DB: ?Sized> ops::Deref for Semantics<'db, DB> {
|
||||
type Target = SemanticsImpl<'db>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
|
@ -173,12 +172,28 @@ impl<'db, DB> ops::Deref for Semantics<'db, DB> {
|
|||
}
|
||||
}
|
||||
|
||||
// Note: while this variant of `Semantics<'_, _>` might seem unused, as it does not
|
||||
// find actual use within the rust-analyzer project itself, it exists to enable the use
|
||||
// within e.g. tracked salsa functions in third-party crates that build upon `ra_ap_hir`.
|
||||
impl Semantics<'_, dyn HirDatabase> {
|
||||
/// Creates an instance that's weakly coupled to its underlying database type.
|
||||
pub fn new_dyn(db: &'_ dyn HirDatabase) -> Semantics<'_, dyn HirDatabase> {
|
||||
let impl_ = SemanticsImpl::new(db);
|
||||
Semantics { db, imp: impl_ }
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB: HirDatabase> Semantics<'_, DB> {
|
||||
/// Creates an instance that's strongly coupled to its underlying database type.
|
||||
pub fn new(db: &DB) -> Semantics<'_, DB> {
|
||||
let impl_ = SemanticsImpl::new(db);
|
||||
Semantics { db, imp: impl_ }
|
||||
}
|
||||
}
|
||||
|
||||
// Note: We take `DB` as `?Sized` here in order to support type-erased
|
||||
// use of `Semantics` via `Semantics<'_, dyn HirDatabase>`:
|
||||
impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> {
|
||||
pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId {
|
||||
self.imp.find_file(syntax_node).file_id
|
||||
}
|
||||
|
|
@ -229,7 +244,7 @@ impl<DB: HirDatabase> Semantics<'_, DB> {
|
|||
offset: TextSize,
|
||||
) -> impl Iterator<Item = ast::NameLike> + 'slf {
|
||||
node.token_at_offset(offset)
|
||||
.map(move |token| self.descend_into_macros_no_opaque(token))
|
||||
.map(move |token| self.descend_into_macros_no_opaque(token, true))
|
||||
.map(|descendants| descendants.into_iter().filter_map(move |it| it.value.parent()))
|
||||
// re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first
|
||||
// See algo::ancestors_at_offset, which uses the same approach
|
||||
|
|
@ -953,13 +968,6 @@ impl<'db> SemanticsImpl<'db> {
|
|||
let Some(item) = ast::Item::cast(ancestor) else {
|
||||
return false;
|
||||
};
|
||||
// Optimization to skip the semantic check.
|
||||
if item.attrs().all(|attr| {
|
||||
attr.simple_name()
|
||||
.is_some_and(|attr| find_builtin_attr_idx(&Symbol::intern(&attr)).is_some())
|
||||
}) {
|
||||
return false;
|
||||
}
|
||||
self.with_ctx(|ctx| {
|
||||
if ctx.item_to_macro_call(token.with_value(&item)).is_some() {
|
||||
return true;
|
||||
|
|
@ -1001,10 +1009,11 @@ impl<'db> SemanticsImpl<'db> {
|
|||
pub fn descend_into_macros_no_opaque(
|
||||
&self,
|
||||
token: SyntaxToken,
|
||||
always_descend_into_derives: bool,
|
||||
) -> SmallVec<[InFile<SyntaxToken>; 1]> {
|
||||
let mut res = smallvec![];
|
||||
let token = self.wrap_token_infile(token);
|
||||
self.descend_into_macros_all(token.clone(), true, &mut |t, ctx| {
|
||||
self.descend_into_macros_all(token.clone(), always_descend_into_derives, &mut |t, ctx| {
|
||||
if !ctx.is_opaque(self.db) {
|
||||
// Don't descend into opaque contexts
|
||||
res.push(t);
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@
|
|||
|
||||
use either::Either;
|
||||
use hir_expand::{HirFileId, attrs::collect_attrs};
|
||||
use span::AstIdNode;
|
||||
use syntax::{AstPtr, ast};
|
||||
|
||||
use hir_def::{
|
||||
AdtId, AssocItemId, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId, ItemTreeLoc,
|
||||
AdtId, AssocItemId, AstIdLoc, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId,
|
||||
LifetimeParamId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, TypeOrConstParamId,
|
||||
VariantId,
|
||||
db::DefDatabase,
|
||||
|
|
@ -19,7 +20,6 @@ use hir_def::{
|
|||
},
|
||||
hir::generics::GenericParams,
|
||||
item_scope::ItemScope,
|
||||
item_tree::ItemTreeNode,
|
||||
nameres::DefMap,
|
||||
src::{HasChildSource, HasSource},
|
||||
};
|
||||
|
|
@ -61,7 +61,7 @@ impl ChildBySource for TraitId {
|
|||
|
||||
impl ChildBySource for ImplId {
|
||||
fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
|
||||
let data = db.impl_items(*self);
|
||||
let data = self.impl_items(db);
|
||||
data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each(
|
||||
|(ast_id, call_id)| {
|
||||
let ptr = ast_id.to_ptr(db);
|
||||
|
|
@ -113,7 +113,7 @@ impl ChildBySource for ItemScope {
|
|||
ids.iter().for_each(|&id| {
|
||||
if let MacroId::MacroRulesId(id) = id {
|
||||
let loc = id.lookup(db);
|
||||
if loc.id.file_id() == file_id {
|
||||
if loc.id.file_id == file_id {
|
||||
res[keys::MACRO_RULES].insert(loc.ast_ptr(db).value, id);
|
||||
}
|
||||
}
|
||||
|
|
@ -199,16 +199,14 @@ impl ChildBySource for VariantId {
|
|||
impl ChildBySource for EnumId {
|
||||
fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
|
||||
let loc = &self.lookup(db);
|
||||
if file_id != loc.id.file_id() {
|
||||
if file_id != loc.id.file_id {
|
||||
return;
|
||||
}
|
||||
|
||||
let tree = loc.id.item_tree(db);
|
||||
let ast_id_map = db.ast_id_map(loc.id.file_id());
|
||||
let ast_id_map = db.ast_id_map(loc.id.file_id);
|
||||
|
||||
db.enum_variants(*self).variants.iter().for_each(|&(variant, _)| {
|
||||
res[keys::ENUM_VARIANT]
|
||||
.insert(ast_id_map.get(tree[variant.lookup(db).id.value].ast_id), variant);
|
||||
self.enum_variants(db).variants.iter().for_each(|&(variant, _, _)| {
|
||||
res[keys::ENUM_VARIANT].insert(ast_id_map.get(variant.lookup(db).id.value), variant);
|
||||
});
|
||||
let (_, source_map) = db.enum_signature_with_source_map(*self);
|
||||
source_map
|
||||
|
|
@ -287,15 +285,14 @@ fn insert_item_loc<ID, N, Data>(
|
|||
res: &mut DynMap,
|
||||
file_id: HirFileId,
|
||||
id: ID,
|
||||
key: Key<N::Source, ID>,
|
||||
key: Key<N, ID>,
|
||||
) where
|
||||
ID: Lookup<Database = dyn DefDatabase, Data = Data> + 'static,
|
||||
Data: ItemTreeLoc<Id = N>,
|
||||
N: ItemTreeNode,
|
||||
N::Source: 'static,
|
||||
Data: AstIdLoc<Ast = N>,
|
||||
N: AstIdNode + 'static,
|
||||
{
|
||||
let loc = id.lookup(db);
|
||||
if loc.item_tree_id().file_id() == file_id {
|
||||
if loc.ast_id().file_id == file_id {
|
||||
res[key].insert(loc.ast_ptr(db).value, id)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ use hir_expand::{
|
|||
};
|
||||
use hir_ty::{
|
||||
Adjustment, AliasTy, InferenceResult, Interner, LifetimeElisionKind, ProjectionTy,
|
||||
Substitution, TraitEnvironment, Ty, TyExt, TyKind, TyLoweringContext,
|
||||
Substitution, ToChalk, TraitEnvironment, Ty, TyExt, TyKind, TyLoweringContext,
|
||||
diagnostics::{
|
||||
InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields,
|
||||
unsafe_operations,
|
||||
|
|
@ -829,7 +829,7 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
handle_variants(id.into(), subst, &mut container)?
|
||||
}
|
||||
AdtId::EnumId(id) => {
|
||||
let variants = db.enum_variants(id);
|
||||
let variants = id.enum_variants(db);
|
||||
let variant = variants.variant(&field_name.as_name())?;
|
||||
container = Either::Left((variant, subst.clone()));
|
||||
(Either::Left(Variant { id: variant }), id.into(), subst.clone())
|
||||
|
|
@ -1169,8 +1169,7 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
)
|
||||
}
|
||||
TyKind::FnDef(fn_id, subst) => {
|
||||
let fn_id = hir_ty::db::InternedCallableDefId::from(*fn_id);
|
||||
let fn_id = db.lookup_intern_callable_def(fn_id);
|
||||
let fn_id = ToChalk::from_chalk(db, *fn_id);
|
||||
let generic_def_id = match fn_id {
|
||||
CallableDefId::StructId(id) => id.into(),
|
||||
CallableDefId::FunctionId(id) => id.into(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//! File symbol extraction.
|
||||
|
||||
use base_db::FxIndexSet;
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
AdtId, AssocItemId, Complete, DefWithBodyId, ExternCrateId, HasModule, ImplId, Lookup, MacroId,
|
||||
|
|
@ -21,8 +22,6 @@ use syntax::{AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr, ast
|
|||
|
||||
use crate::{HasCrate, Module, ModuleDef, Semantics};
|
||||
|
||||
pub type FxIndexSet<T> = indexmap::IndexSet<T, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
|
||||
|
||||
/// The actual data that is stored in the index. It should be as compact as
|
||||
/// possible.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
|
@ -34,6 +33,7 @@ pub struct FileSymbol {
|
|||
/// Whether this symbol is a doc alias for the original symbol.
|
||||
pub is_alias: bool,
|
||||
pub is_assoc: bool,
|
||||
pub is_import: bool,
|
||||
pub do_not_complete: Complete,
|
||||
}
|
||||
|
||||
|
|
@ -165,6 +165,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
|
||||
let is_explicit_import = |vis| match vis {
|
||||
Visibility::Public => true,
|
||||
Visibility::PubCrate(_) => true,
|
||||
Visibility::Module(_, VisibilityExplicitness::Explicit) => true,
|
||||
Visibility::Module(_, VisibilityExplicitness::Implicit) => false,
|
||||
};
|
||||
|
|
@ -197,6 +198,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
loc: dec_loc,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: true,
|
||||
do_not_complete: Complete::Yes,
|
||||
});
|
||||
};
|
||||
|
|
@ -227,6 +229,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
loc: dec_loc,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Complete::Yes,
|
||||
});
|
||||
};
|
||||
|
|
@ -322,7 +325,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
.to_smolstr(),
|
||||
);
|
||||
self.with_container_name(impl_name, |s| {
|
||||
for &(ref name, assoc_item_id) in &self.db.impl_items(impl_id).items {
|
||||
for &(ref name, assoc_item_id) in &impl_id.impl_items(self.db).items {
|
||||
s.push_assoc_item(assoc_item_id, name, None)
|
||||
}
|
||||
})
|
||||
|
|
@ -398,6 +401,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
container_name: self.current_container_name.clone(),
|
||||
is_alias: true,
|
||||
is_assoc,
|
||||
is_import: false,
|
||||
do_not_complete,
|
||||
});
|
||||
}
|
||||
|
|
@ -410,6 +414,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
loc: dec_loc,
|
||||
is_alias: false,
|
||||
is_assoc,
|
||||
is_import: false,
|
||||
do_not_complete,
|
||||
});
|
||||
|
||||
|
|
@ -442,6 +447,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
container_name: self.current_container_name.clone(),
|
||||
is_alias: true,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete,
|
||||
});
|
||||
}
|
||||
|
|
@ -454,6 +460,7 @@ impl<'a> SymbolCollector<'a> {
|
|||
loc: dec_loc,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ either.workspace = true
|
|||
itertools.workspace = true
|
||||
arrayvec.workspace = true
|
||||
indexmap.workspace = true
|
||||
memchr = "2.7.4"
|
||||
memchr = "2.7.5"
|
||||
salsa.workspace = true
|
||||
salsa-macros.workspace = true
|
||||
query-group.workspace = true
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ pub struct Query {
|
|||
case_sensitive: bool,
|
||||
only_types: bool,
|
||||
libs: bool,
|
||||
exclude_imports: bool,
|
||||
}
|
||||
|
||||
impl Query {
|
||||
|
|
@ -63,6 +64,7 @@ impl Query {
|
|||
mode: SearchMode::Fuzzy,
|
||||
assoc_mode: AssocSearchMode::Include,
|
||||
case_sensitive: false,
|
||||
exclude_imports: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -94,6 +96,10 @@ impl Query {
|
|||
pub fn case_sensitive(&mut self) {
|
||||
self.case_sensitive = true;
|
||||
}
|
||||
|
||||
pub fn exclude_imports(&mut self) {
|
||||
self.exclude_imports = true;
|
||||
}
|
||||
}
|
||||
|
||||
#[query_group::query_group]
|
||||
|
|
@ -362,6 +368,9 @@ impl Query {
|
|||
if ignore_underscore_prefixed && symbol_name.starts_with("__") {
|
||||
continue;
|
||||
}
|
||||
if self.exclude_imports && symbol.is_import {
|
||||
continue;
|
||||
}
|
||||
if self.mode.check(&self.query, self.case_sensitive, symbol_name) {
|
||||
if let Some(b) = cb(symbol).break_value() {
|
||||
return Some(b);
|
||||
|
|
@ -385,7 +394,8 @@ impl Query {
|
|||
mod tests {
|
||||
|
||||
use expect_test::expect_file;
|
||||
use test_fixture::WithFixture;
|
||||
use salsa::Durability;
|
||||
use test_fixture::{WORKSPACE, WithFixture};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -506,4 +516,31 @@ struct Duplicate;
|
|||
|
||||
expect_file!["./test_data/test_doc_alias.txt"].assert_debug_eq(&symbols);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exclude_imports() {
|
||||
let (mut db, _) = RootDatabase::with_many_files(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
mod foo;
|
||||
pub use foo::Foo;
|
||||
|
||||
//- /foo.rs
|
||||
pub struct Foo;
|
||||
"#,
|
||||
);
|
||||
|
||||
let mut local_roots = FxHashSet::default();
|
||||
local_roots.insert(WORKSPACE);
|
||||
db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
|
||||
|
||||
let mut query = Query::new("Foo".to_owned());
|
||||
let mut symbols = world_symbols(&db, query.clone());
|
||||
symbols.sort_by_key(|x| x.is_import);
|
||||
expect_file!["./test_data/test_symbols_with_imports.txt"].assert_debug_eq(&symbols);
|
||||
|
||||
query.exclude_imports();
|
||||
let symbols = world_symbols(&db, query);
|
||||
expect_file!["./test_data/test_symbols_exclude_imports.txt"].assert_debug_eq(&symbols);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -74,6 +75,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -107,6 +109,7 @@
|
|||
container_name: None,
|
||||
is_alias: true,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -140,6 +143,7 @@
|
|||
container_name: None,
|
||||
is_alias: true,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -173,6 +177,7 @@
|
|||
container_name: None,
|
||||
is_alias: true,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -206,6 +211,7 @@
|
|||
container_name: None,
|
||||
is_alias: true,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -239,6 +245,7 @@
|
|||
container_name: None,
|
||||
is_alias: true,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -70,6 +71,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -101,6 +103,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -134,6 +137,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -167,6 +171,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: true,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -200,6 +205,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -231,6 +237,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -264,6 +271,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -297,6 +305,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -332,6 +341,7 @@
|
|||
),
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -367,6 +377,7 @@
|
|||
),
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -400,6 +411,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -433,6 +445,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -464,6 +477,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -497,6 +511,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: true,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -530,6 +545,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -565,6 +581,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -600,6 +617,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -633,6 +651,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -666,6 +685,7 @@
|
|||
),
|
||||
is_alias: false,
|
||||
is_assoc: true,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -699,6 +719,7 @@
|
|||
),
|
||||
is_alias: false,
|
||||
is_assoc: true,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -732,6 +753,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -763,6 +785,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -796,6 +819,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: true,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -829,6 +853,7 @@
|
|||
),
|
||||
is_alias: false,
|
||||
is_assoc: true,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
],
|
||||
|
|
@ -875,6 +900,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
],
|
||||
|
|
@ -919,6 +945,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: true,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -952,6 +979,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: true,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -985,6 +1013,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -1018,6 +1047,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: true,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
|
|
@ -1051,6 +1081,7 @@
|
|||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: true,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
],
|
||||
|
|
|
|||
36
crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
Normal file
36
crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
[
|
||||
FileSymbol {
|
||||
name: "Foo",
|
||||
def: Adt(
|
||||
Struct(
|
||||
Struct {
|
||||
id: StructId(
|
||||
3800,
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
loc: DeclarationLocation {
|
||||
hir_file_id: FileId(
|
||||
EditionedFileId(
|
||||
Id(2001),
|
||||
),
|
||||
),
|
||||
ptr: SyntaxNodePtr {
|
||||
kind: STRUCT,
|
||||
range: 0..15,
|
||||
},
|
||||
name_ptr: AstPtr(
|
||||
SyntaxNodePtr {
|
||||
kind: NAME,
|
||||
range: 11..14,
|
||||
},
|
||||
),
|
||||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
]
|
||||
70
crates/ide-db/src/test_data/test_symbols_with_imports.txt
Normal file
70
crates/ide-db/src/test_data/test_symbols_with_imports.txt
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
[
|
||||
FileSymbol {
|
||||
name: "Foo",
|
||||
def: Adt(
|
||||
Struct(
|
||||
Struct {
|
||||
id: StructId(
|
||||
3800,
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
loc: DeclarationLocation {
|
||||
hir_file_id: FileId(
|
||||
EditionedFileId(
|
||||
Id(2001),
|
||||
),
|
||||
),
|
||||
ptr: SyntaxNodePtr {
|
||||
kind: STRUCT,
|
||||
range: 0..15,
|
||||
},
|
||||
name_ptr: AstPtr(
|
||||
SyntaxNodePtr {
|
||||
kind: NAME,
|
||||
range: 11..14,
|
||||
},
|
||||
),
|
||||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: false,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
FileSymbol {
|
||||
name: "Foo",
|
||||
def: Adt(
|
||||
Struct(
|
||||
Struct {
|
||||
id: StructId(
|
||||
3800,
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
loc: DeclarationLocation {
|
||||
hir_file_id: FileId(
|
||||
EditionedFileId(
|
||||
Id(2000),
|
||||
),
|
||||
),
|
||||
ptr: SyntaxNodePtr {
|
||||
kind: USE_TREE,
|
||||
range: 17..25,
|
||||
},
|
||||
name_ptr: AstPtr(
|
||||
SyntaxNodePtr {
|
||||
kind: NAME_REF,
|
||||
range: 22..25,
|
||||
},
|
||||
),
|
||||
},
|
||||
container_name: None,
|
||||
is_alias: false,
|
||||
is_assoc: false,
|
||||
is_import: true,
|
||||
do_not_complete: Yes,
|
||||
},
|
||||
]
|
||||
|
|
@ -127,4 +127,33 @@ impl !Trait for () {}
|
|||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn impl_sized_for_unsized() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
//- minicore: sized
|
||||
trait Trait {
|
||||
type Item
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn item()
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
trait OtherTrait {}
|
||||
|
||||
impl Trait for () {
|
||||
type Item = ();
|
||||
fn item() {}
|
||||
}
|
||||
|
||||
// Items with Self: Sized bound not required to be implemented for unsized types.
|
||||
impl Trait for str {}
|
||||
impl Trait for dyn OtherTrait {}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ dot.workspace = true
|
|||
smallvec.workspace = true
|
||||
triomphe.workspace = true
|
||||
nohash-hasher.workspace = true
|
||||
rustc_apfloat = "0.2.2"
|
||||
rustc_apfloat = "0.2.3"
|
||||
|
||||
# local deps
|
||||
cfg.workspace = true
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use crate::{
|
|||
NavigationTarget, RunnableKind,
|
||||
annotations::fn_references::find_all_methods,
|
||||
goto_implementation::goto_implementation,
|
||||
navigation_target,
|
||||
references::find_all_refs,
|
||||
runnables::{Runnable, runnables},
|
||||
};
|
||||
|
|
@ -148,15 +149,32 @@ pub(crate) fn annotations(
|
|||
node: InFile<T>,
|
||||
source_file_id: FileId,
|
||||
) -> Option<(TextRange, Option<TextRange>)> {
|
||||
if let Some(InRealFile { file_id, value }) = node.original_ast_node_rooted(db) {
|
||||
if file_id.file_id(db) == source_file_id {
|
||||
return Some((
|
||||
value.syntax().text_range(),
|
||||
value.name().map(|name| name.syntax().text_range()),
|
||||
));
|
||||
if let Some(name) = node.value.name().map(|name| name.syntax().text_range()) {
|
||||
// if we have a name, try mapping that out of the macro expansion as we can put the
|
||||
// annotation on that name token
|
||||
// See `test_no_annotations_macro_struct_def` vs `test_annotations_macro_struct_def_call_site`
|
||||
let res = navigation_target::orig_range_with_focus_r(
|
||||
db,
|
||||
node.file_id,
|
||||
node.value.syntax().text_range(),
|
||||
Some(name),
|
||||
);
|
||||
if res.call_site.0.file_id == source_file_id {
|
||||
if let Some(name_range) = res.call_site.1 {
|
||||
return Some((res.call_site.0.range, Some(name_range)));
|
||||
}
|
||||
}
|
||||
};
|
||||
// otherwise try upmapping the entire node out of attributes
|
||||
let InRealFile { file_id, value } = node.original_ast_node_rooted(db)?;
|
||||
if file_id.file_id(db) == source_file_id {
|
||||
Some((
|
||||
value.syntax().text_range(),
|
||||
value.name().map(|name| name.syntax().text_range()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -913,6 +931,56 @@ m!();
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_annotations_macro_struct_def_call_site() {
|
||||
check(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
macro_rules! m {
|
||||
($name:ident) => {
|
||||
struct $name {}
|
||||
};
|
||||
}
|
||||
|
||||
m! {
|
||||
Name
|
||||
};
|
||||
"#,
|
||||
expect![[r#"
|
||||
[
|
||||
Annotation {
|
||||
range: 83..87,
|
||||
kind: HasImpls {
|
||||
pos: FilePositionWrapper {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
offset: 83,
|
||||
},
|
||||
data: Some(
|
||||
[],
|
||||
),
|
||||
},
|
||||
},
|
||||
Annotation {
|
||||
range: 83..87,
|
||||
kind: HasReferences {
|
||||
pos: FilePositionWrapper {
|
||||
file_id: FileId(
|
||||
0,
|
||||
),
|
||||
offset: 83,
|
||||
},
|
||||
data: Some(
|
||||
[],
|
||||
),
|
||||
},
|
||||
},
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_annotations_appear_above_whole_item_when_configured_to_do_so() {
|
||||
check_with_config(
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ pub(crate) fn goto_declaration(
|
|||
.find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate] | T![Self]))?;
|
||||
let range = original_token.text_range();
|
||||
let info: Vec<NavigationTarget> = sema
|
||||
.descend_into_macros_no_opaque(original_token)
|
||||
.descend_into_macros_no_opaque(original_token, false)
|
||||
.iter()
|
||||
.filter_map(|token| {
|
||||
let parent = token.value.parent()?;
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ pub(crate) fn goto_definition(
|
|||
}
|
||||
|
||||
let navs = sema
|
||||
.descend_into_macros_no_opaque(original_token.clone())
|
||||
.descend_into_macros_no_opaque(original_token.clone(), false)
|
||||
.into_iter()
|
||||
.filter_map(|token| {
|
||||
let parent = token.value.parent()?;
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ pub(crate) fn goto_type_definition(
|
|||
}
|
||||
|
||||
let range = token.text_range();
|
||||
sema.descend_into_macros_no_opaque(token)
|
||||
sema.descend_into_macros_no_opaque(token,false)
|
||||
.into_iter()
|
||||
.filter_map(|token| {
|
||||
sema
|
||||
|
|
|
|||
|
|
@ -22,9 +22,14 @@ pub(super) fn hints(
|
|||
let parent = paren.as_ref().and_then(|it| it.parent()).unwrap_or(parent);
|
||||
if ast::TypeBound::can_cast(parent.kind())
|
||||
|| ast::TypeAnchor::can_cast(parent.kind())
|
||||
|| ast::Impl::cast(parent)
|
||||
.and_then(|it| it.trait_())
|
||||
.is_some_and(|it| it.syntax() == path.syntax())
|
||||
|| ast::Impl::cast(parent).is_some_and(|it| {
|
||||
it.trait_().map_or(
|
||||
// only show it for impl type if the impl is not incomplete, otherwise we
|
||||
// are likely typing a trait impl
|
||||
it.assoc_item_list().is_none_or(|it| it.l_curly_token().is_none()),
|
||||
|trait_| trait_.syntax() == path.syntax(),
|
||||
)
|
||||
})
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
|
@ -85,6 +90,7 @@ impl T {}
|
|||
// ^ dyn
|
||||
impl T for (T) {}
|
||||
// ^^^ dyn
|
||||
impl T
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -867,7 +867,7 @@ pub(crate) fn orig_range_with_focus_r(
|
|||
}
|
||||
|
||||
// def site name
|
||||
// FIXME: This can be de improved
|
||||
// FIXME: This can be improved
|
||||
Some((focus_range, _ctxt)) => {
|
||||
match value_range {
|
||||
// but overall node is in macro input
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ use ast::HasName;
|
|||
use cfg::{CfgAtom, CfgExpr};
|
||||
use hir::{
|
||||
AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate, HasSource, ModPath, Name, PathKind, Semantics,
|
||||
Symbol, db::HirDatabase, sym, symbols::FxIndexSet,
|
||||
Symbol, db::HirDatabase, sym,
|
||||
};
|
||||
use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn};
|
||||
use ide_db::{
|
||||
FilePosition, FxHashMap, FxIndexMap, RootDatabase, SymbolKind,
|
||||
FilePosition, FxHashMap, FxIndexMap, FxIndexSet, RootDatabase, SymbolKind,
|
||||
base_db::RootQueryDb,
|
||||
defs::Definition,
|
||||
documentation::docs_from_attrs,
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ define_symbols! {
|
|||
fn_once_output,
|
||||
fn_once,
|
||||
async_fn_once,
|
||||
async_fn_once_output,
|
||||
async_fn_mut,
|
||||
async_fn,
|
||||
fn_ptr_addr,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
//! for incorporating changes.
|
||||
// Note, don't remove any public api from this. This API is consumed by external tools
|
||||
// to run rust-analyzer as a library.
|
||||
use std::{collections::hash_map::Entry, mem, path::Path, sync};
|
||||
use std::{any::Any, collections::hash_map::Entry, mem, path::Path, sync};
|
||||
|
||||
use crossbeam_channel::{Receiver, unbounded};
|
||||
use hir_expand::proc_macro::{
|
||||
|
|
@ -512,6 +512,10 @@ impl ProcMacroExpander for Expander {
|
|||
Err(err) => Err(ProcMacroExpansionError::System(err.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
(other as &dyn Any).downcast_ref::<Self>() == Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -197,6 +197,10 @@ fn invocation_fixtures(
|
|||
builder.push(tt::Leaf::Punct(*it))
|
||||
}
|
||||
}
|
||||
Separator::Lifetime(punct, ident) => {
|
||||
builder.push(tt::Leaf::Punct(*punct));
|
||||
builder.push(tt::Leaf::Ident(ident.clone()));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -823,7 +823,7 @@ fn match_meta_var<'t>(
|
|||
"expected token tree",
|
||||
)
|
||||
}),
|
||||
MetaVarKind::Lifetime => expect_lifetime(input).map_err(|()| {
|
||||
MetaVarKind::Lifetime => expect_lifetime(input).map(drop).map_err(|()| {
|
||||
ExpandError::binding_error(
|
||||
span.unwrap_or(delim_span.close),
|
||||
"expected lifetime",
|
||||
|
|
@ -963,6 +963,10 @@ fn expect_separator<S: Copy>(iter: &mut TtIter<'_, S>, separator: &Separator) ->
|
|||
}
|
||||
Err(_) => false,
|
||||
},
|
||||
Separator::Lifetime(_punct, ident) => match expect_lifetime(&mut fork) {
|
||||
Ok(lifetime) => lifetime.sym == ident.sym,
|
||||
Err(_) => false,
|
||||
},
|
||||
};
|
||||
if ok {
|
||||
*iter = fork;
|
||||
|
|
@ -983,13 +987,12 @@ fn expect_tt<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn expect_lifetime<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> {
|
||||
fn expect_lifetime<'a, S: Copy>(iter: &mut TtIter<'a, S>) -> Result<&'a tt::Ident<S>, ()> {
|
||||
let punct = iter.expect_single_punct()?;
|
||||
if punct.char != '\'' {
|
||||
return Err(());
|
||||
}
|
||||
iter.expect_ident_or_underscore()?;
|
||||
Ok(())
|
||||
iter.expect_ident_or_underscore()
|
||||
}
|
||||
|
||||
fn eat_char<S: Copy>(iter: &mut TtIter<'_, S>, c: char) {
|
||||
|
|
|
|||
|
|
@ -497,6 +497,10 @@ fn expand_repeat(
|
|||
builder.push(tt::Leaf::from(punct));
|
||||
}
|
||||
}
|
||||
Separator::Lifetime(punct, ident) => {
|
||||
builder.push(tt::Leaf::from(*punct));
|
||||
builder.push(tt::Leaf::from(ident.clone()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ pub(crate) enum Separator {
|
|||
Literal(tt::Literal<Span>),
|
||||
Ident(tt::Ident<Span>),
|
||||
Puncts(ArrayVec<tt::Punct<Span>, MAX_GLUED_PUNCT_LEN>),
|
||||
Lifetime(tt::Punct<Span>, tt::Ident<Span>),
|
||||
}
|
||||
|
||||
// Note that when we compare a Separator, we just care about its textual value.
|
||||
|
|
@ -170,6 +171,7 @@ impl PartialEq for Separator {
|
|||
let b_iter = b.iter().map(|b| b.char);
|
||||
a_iter.eq(b_iter)
|
||||
}
|
||||
(Lifetime(_, a), Lifetime(_, b)) => a.sym == b.sym,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -350,10 +352,19 @@ fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, Repeat
|
|||
_ => true,
|
||||
};
|
||||
match tt {
|
||||
tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => {
|
||||
return Err(ParseError::InvalidRepeat);
|
||||
}
|
||||
tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()),
|
||||
tt::Leaf::Ident(ident) => match separator {
|
||||
Separator::Puncts(puncts) if puncts.is_empty() => {
|
||||
separator = Separator::Ident(ident.clone());
|
||||
}
|
||||
Separator::Puncts(puncts) => match puncts.as_slice() {
|
||||
[tt::Punct { char: '\'', .. }] => {
|
||||
separator = Separator::Lifetime(puncts[0], ident.clone());
|
||||
}
|
||||
_ => return Err(ParseError::InvalidRepeat),
|
||||
},
|
||||
_ => return Err(ParseError::InvalidRepeat),
|
||||
},
|
||||
tt::Leaf::Literal(_) if has_sep => return Err(ParseError::InvalidRepeat),
|
||||
tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()),
|
||||
tt::Leaf::Punct(punct) => {
|
||||
let repeat_kind = match punct.char {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
// FIXME: Move more of the nameres independent tests from
|
||||
// crates\hir-def\src\macro_expansion_tests\mod.rs to this
|
||||
use expect_test::expect;
|
||||
use span::{Edition, EditionedFileId, ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContext};
|
||||
use span::{
|
||||
Edition, EditionedFileId, FileId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext,
|
||||
};
|
||||
use stdx::format_to;
|
||||
use tt::{TextRange, TextSize};
|
||||
|
||||
|
|
@ -24,7 +26,7 @@ fn check_(
|
|||
def_edition,
|
||||
SpanAnchor {
|
||||
file_id: EditionedFileId::new(FileId::from_raw(0), def_edition),
|
||||
ast_id: ErasedFileAstId::from_raw(0),
|
||||
ast_id: ROOT_ERASED_FILE_AST_ID,
|
||||
},
|
||||
SyntaxContext::root(Edition::CURRENT),
|
||||
decl,
|
||||
|
|
@ -37,7 +39,7 @@ fn check_(
|
|||
};
|
||||
let call_anchor = SpanAnchor {
|
||||
file_id: EditionedFileId::new(FileId::from_raw(1), call_edition),
|
||||
ast_id: ErasedFileAstId::from_raw(0),
|
||||
ast_id: ROOT_ERASED_FILE_AST_ID,
|
||||
};
|
||||
let arg_tt = syntax_bridge::parse_to_token_tree(
|
||||
call_edition,
|
||||
|
|
@ -110,8 +112,8 @@ fn unbalanced_brace() {
|
|||
"#,
|
||||
r#""#,
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..0#ROOT2024 1:0@0..0#ROOT2024
|
||||
SUBTREE {} 0:0@9..10#ROOT2024 0:0@11..12#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..0#ROOT2024 1:Root[0000, 0]@0..0#ROOT2024
|
||||
SUBTREE {} 0:Root[0000, 0]@9..10#ROOT2024 0:Root[0000, 0]@11..12#ROOT2024
|
||||
|
||||
{}"#]],
|
||||
);
|
||||
|
|
@ -133,25 +135,25 @@ fn token_mapping_smoke_test() {
|
|||
struct MyTraitMap2
|
||||
"#,
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..20#ROOT2024 1:0@0..20#ROOT2024
|
||||
IDENT struct 0:0@34..40#ROOT2024
|
||||
IDENT MyTraitMap2 1:0@8..19#ROOT2024
|
||||
SUBTREE {} 0:0@48..49#ROOT2024 0:0@100..101#ROOT2024
|
||||
IDENT map 0:0@58..61#ROOT2024
|
||||
PUNCH : [alone] 0:0@61..62#ROOT2024
|
||||
PUNCH : [joint] 0:0@63..64#ROOT2024
|
||||
PUNCH : [alone] 0:0@64..65#ROOT2024
|
||||
IDENT std 0:0@65..68#ROOT2024
|
||||
PUNCH : [joint] 0:0@68..69#ROOT2024
|
||||
PUNCH : [alone] 0:0@69..70#ROOT2024
|
||||
IDENT collections 0:0@70..81#ROOT2024
|
||||
PUNCH : [joint] 0:0@81..82#ROOT2024
|
||||
PUNCH : [alone] 0:0@82..83#ROOT2024
|
||||
IDENT HashSet 0:0@83..90#ROOT2024
|
||||
PUNCH < [alone] 0:0@90..91#ROOT2024
|
||||
SUBTREE () 0:0@91..92#ROOT2024 0:0@92..93#ROOT2024
|
||||
PUNCH > [joint] 0:0@93..94#ROOT2024
|
||||
PUNCH , [alone] 0:0@94..95#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..20#ROOT2024 1:Root[0000, 0]@0..20#ROOT2024
|
||||
IDENT struct 0:Root[0000, 0]@34..40#ROOT2024
|
||||
IDENT MyTraitMap2 1:Root[0000, 0]@8..19#ROOT2024
|
||||
SUBTREE {} 0:Root[0000, 0]@48..49#ROOT2024 0:Root[0000, 0]@100..101#ROOT2024
|
||||
IDENT map 0:Root[0000, 0]@58..61#ROOT2024
|
||||
PUNCH : [alone] 0:Root[0000, 0]@61..62#ROOT2024
|
||||
PUNCH : [joint] 0:Root[0000, 0]@63..64#ROOT2024
|
||||
PUNCH : [alone] 0:Root[0000, 0]@64..65#ROOT2024
|
||||
IDENT std 0:Root[0000, 0]@65..68#ROOT2024
|
||||
PUNCH : [joint] 0:Root[0000, 0]@68..69#ROOT2024
|
||||
PUNCH : [alone] 0:Root[0000, 0]@69..70#ROOT2024
|
||||
IDENT collections 0:Root[0000, 0]@70..81#ROOT2024
|
||||
PUNCH : [joint] 0:Root[0000, 0]@81..82#ROOT2024
|
||||
PUNCH : [alone] 0:Root[0000, 0]@82..83#ROOT2024
|
||||
IDENT HashSet 0:Root[0000, 0]@83..90#ROOT2024
|
||||
PUNCH < [alone] 0:Root[0000, 0]@90..91#ROOT2024
|
||||
SUBTREE () 0:Root[0000, 0]@91..92#ROOT2024 0:Root[0000, 0]@92..93#ROOT2024
|
||||
PUNCH > [joint] 0:Root[0000, 0]@93..94#ROOT2024
|
||||
PUNCH , [alone] 0:Root[0000, 0]@94..95#ROOT2024
|
||||
|
||||
struct MyTraitMap2 {
|
||||
map: ::std::collections::HashSet<()>,
|
||||
|
|
@ -180,28 +182,28 @@ fn main() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..63#ROOT2024 1:0@0..63#ROOT2024
|
||||
IDENT fn 1:0@1..3#ROOT2024
|
||||
IDENT main 1:0@4..8#ROOT2024
|
||||
SUBTREE () 1:0@8..9#ROOT2024 1:0@9..10#ROOT2024
|
||||
SUBTREE {} 1:0@11..12#ROOT2024 1:0@61..62#ROOT2024
|
||||
LITERAL Integer 1 1:0@17..18#ROOT2024
|
||||
PUNCH ; [alone] 1:0@18..19#ROOT2024
|
||||
LITERAL Float 1.0 1:0@24..27#ROOT2024
|
||||
PUNCH ; [alone] 1:0@27..28#ROOT2024
|
||||
SUBTREE () 1:0@33..34#ROOT2024 1:0@39..40#ROOT2024
|
||||
SUBTREE () 1:0@34..35#ROOT2024 1:0@37..38#ROOT2024
|
||||
LITERAL Integer 1 1:0@35..36#ROOT2024
|
||||
PUNCH , [alone] 1:0@36..37#ROOT2024
|
||||
PUNCH , [alone] 1:0@38..39#ROOT2024
|
||||
PUNCH . [alone] 1:0@40..41#ROOT2024
|
||||
LITERAL Float 0.0 1:0@41..44#ROOT2024
|
||||
PUNCH ; [alone] 1:0@44..45#ROOT2024
|
||||
IDENT let 1:0@50..53#ROOT2024
|
||||
IDENT x 1:0@54..55#ROOT2024
|
||||
PUNCH = [alone] 1:0@56..57#ROOT2024
|
||||
LITERAL Integer 1 1:0@58..59#ROOT2024
|
||||
PUNCH ; [alone] 1:0@59..60#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..63#ROOT2024 1:Root[0000, 0]@0..63#ROOT2024
|
||||
IDENT fn 1:Root[0000, 0]@1..3#ROOT2024
|
||||
IDENT main 1:Root[0000, 0]@4..8#ROOT2024
|
||||
SUBTREE () 1:Root[0000, 0]@8..9#ROOT2024 1:Root[0000, 0]@9..10#ROOT2024
|
||||
SUBTREE {} 1:Root[0000, 0]@11..12#ROOT2024 1:Root[0000, 0]@61..62#ROOT2024
|
||||
LITERAL Integer 1 1:Root[0000, 0]@17..18#ROOT2024
|
||||
PUNCH ; [alone] 1:Root[0000, 0]@18..19#ROOT2024
|
||||
LITERAL Float 1.0 1:Root[0000, 0]@24..27#ROOT2024
|
||||
PUNCH ; [alone] 1:Root[0000, 0]@27..28#ROOT2024
|
||||
SUBTREE () 1:Root[0000, 0]@33..34#ROOT2024 1:Root[0000, 0]@39..40#ROOT2024
|
||||
SUBTREE () 1:Root[0000, 0]@34..35#ROOT2024 1:Root[0000, 0]@37..38#ROOT2024
|
||||
LITERAL Integer 1 1:Root[0000, 0]@35..36#ROOT2024
|
||||
PUNCH , [alone] 1:Root[0000, 0]@36..37#ROOT2024
|
||||
PUNCH , [alone] 1:Root[0000, 0]@38..39#ROOT2024
|
||||
PUNCH . [alone] 1:Root[0000, 0]@40..41#ROOT2024
|
||||
LITERAL Float 0.0 1:Root[0000, 0]@41..44#ROOT2024
|
||||
PUNCH ; [alone] 1:Root[0000, 0]@44..45#ROOT2024
|
||||
IDENT let 1:Root[0000, 0]@50..53#ROOT2024
|
||||
IDENT x 1:Root[0000, 0]@54..55#ROOT2024
|
||||
PUNCH = [alone] 1:Root[0000, 0]@56..57#ROOT2024
|
||||
LITERAL Integer 1 1:Root[0000, 0]@58..59#ROOT2024
|
||||
PUNCH ; [alone] 1:Root[0000, 0]@59..60#ROOT2024
|
||||
|
||||
fn main(){
|
||||
1;
|
||||
|
|
@ -227,14 +229,14 @@ fn expr_2021() {
|
|||
const { 1 },
|
||||
"#,
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..25#ROOT2024 1:0@0..25#ROOT2024
|
||||
IDENT _ 1:0@5..6#ROOT2024
|
||||
PUNCH ; [joint] 0:0@36..37#ROOT2024
|
||||
SUBTREE () 0:0@34..35#ROOT2024 0:0@34..35#ROOT2024
|
||||
IDENT const 1:0@12..17#ROOT2024
|
||||
SUBTREE {} 1:0@18..19#ROOT2024 1:0@22..23#ROOT2024
|
||||
LITERAL Integer 1 1:0@20..21#ROOT2024
|
||||
PUNCH ; [alone] 0:0@39..40#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..25#ROOT2024 1:Root[0000, 0]@0..25#ROOT2024
|
||||
IDENT _ 1:Root[0000, 0]@5..6#ROOT2024
|
||||
PUNCH ; [joint] 0:Root[0000, 0]@36..37#ROOT2024
|
||||
SUBTREE () 0:Root[0000, 0]@34..35#ROOT2024 0:Root[0000, 0]@34..35#ROOT2024
|
||||
IDENT const 1:Root[0000, 0]@12..17#ROOT2024
|
||||
SUBTREE {} 1:Root[0000, 0]@18..19#ROOT2024 1:Root[0000, 0]@22..23#ROOT2024
|
||||
LITERAL Integer 1 1:Root[0000, 0]@20..21#ROOT2024
|
||||
PUNCH ; [alone] 0:Root[0000, 0]@39..40#ROOT2024
|
||||
|
||||
_;
|
||||
(const {
|
||||
|
|
@ -255,13 +257,13 @@ fn expr_2021() {
|
|||
expect![[r#"
|
||||
ExpandError {
|
||||
inner: (
|
||||
1:0@5..6#ROOT2024,
|
||||
1:Root[0000, 0]@5..6#ROOT2024,
|
||||
NoMatchingRule,
|
||||
),
|
||||
}
|
||||
|
||||
SUBTREE $$ 1:0@0..8#ROOT2024 1:0@0..8#ROOT2024
|
||||
PUNCH ; [alone] 0:0@39..40#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..8#ROOT2024 1:Root[0000, 0]@0..8#ROOT2024
|
||||
PUNCH ; [alone] 0:Root[0000, 0]@39..40#ROOT2024
|
||||
|
||||
;"#]],
|
||||
);
|
||||
|
|
@ -279,13 +281,13 @@ fn expr_2021() {
|
|||
expect![[r#"
|
||||
ExpandError {
|
||||
inner: (
|
||||
1:0@5..10#ROOT2024,
|
||||
1:Root[0000, 0]@5..10#ROOT2024,
|
||||
NoMatchingRule,
|
||||
),
|
||||
}
|
||||
|
||||
SUBTREE $$ 1:0@0..18#ROOT2024 1:0@0..18#ROOT2024
|
||||
PUNCH ; [alone] 0:0@39..40#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..18#ROOT2024 1:Root[0000, 0]@0..18#ROOT2024
|
||||
PUNCH ; [alone] 0:Root[0000, 0]@39..40#ROOT2024
|
||||
|
||||
;"#]],
|
||||
);
|
||||
|
|
@ -305,26 +307,26 @@ fn expr_2021() {
|
|||
break 'foo bar,
|
||||
"#,
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..76#ROOT2024 1:0@0..76#ROOT2024
|
||||
LITERAL Integer 4 1:0@5..6#ROOT2024
|
||||
PUNCH ; [joint] 0:0@41..42#ROOT2024
|
||||
LITERAL Str literal 1:0@12..21#ROOT2024
|
||||
PUNCH ; [joint] 0:0@41..42#ROOT2024
|
||||
SUBTREE () 0:0@39..40#ROOT2024 0:0@39..40#ROOT2024
|
||||
IDENT funcall 1:0@27..34#ROOT2024
|
||||
SUBTREE () 1:0@34..35#ROOT2024 1:0@35..36#ROOT2024
|
||||
PUNCH ; [joint] 0:0@41..42#ROOT2024
|
||||
SUBTREE () 0:0@39..40#ROOT2024 0:0@39..40#ROOT2024
|
||||
IDENT future 1:0@42..48#ROOT2024
|
||||
PUNCH . [alone] 1:0@48..49#ROOT2024
|
||||
IDENT await 1:0@49..54#ROOT2024
|
||||
PUNCH ; [joint] 0:0@41..42#ROOT2024
|
||||
SUBTREE () 0:0@39..40#ROOT2024 0:0@39..40#ROOT2024
|
||||
IDENT break 1:0@60..65#ROOT2024
|
||||
PUNCH ' [joint] 1:0@66..67#ROOT2024
|
||||
IDENT foo 1:0@67..70#ROOT2024
|
||||
IDENT bar 1:0@71..74#ROOT2024
|
||||
PUNCH ; [alone] 0:0@44..45#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..76#ROOT2024 1:Root[0000, 0]@0..76#ROOT2024
|
||||
LITERAL Integer 4 1:Root[0000, 0]@5..6#ROOT2024
|
||||
PUNCH ; [joint] 0:Root[0000, 0]@41..42#ROOT2024
|
||||
LITERAL Str literal 1:Root[0000, 0]@12..21#ROOT2024
|
||||
PUNCH ; [joint] 0:Root[0000, 0]@41..42#ROOT2024
|
||||
SUBTREE () 0:Root[0000, 0]@39..40#ROOT2024 0:Root[0000, 0]@39..40#ROOT2024
|
||||
IDENT funcall 1:Root[0000, 0]@27..34#ROOT2024
|
||||
SUBTREE () 1:Root[0000, 0]@34..35#ROOT2024 1:Root[0000, 0]@35..36#ROOT2024
|
||||
PUNCH ; [joint] 0:Root[0000, 0]@41..42#ROOT2024
|
||||
SUBTREE () 0:Root[0000, 0]@39..40#ROOT2024 0:Root[0000, 0]@39..40#ROOT2024
|
||||
IDENT future 1:Root[0000, 0]@42..48#ROOT2024
|
||||
PUNCH . [alone] 1:Root[0000, 0]@48..49#ROOT2024
|
||||
IDENT await 1:Root[0000, 0]@49..54#ROOT2024
|
||||
PUNCH ; [joint] 0:Root[0000, 0]@41..42#ROOT2024
|
||||
SUBTREE () 0:Root[0000, 0]@39..40#ROOT2024 0:Root[0000, 0]@39..40#ROOT2024
|
||||
IDENT break 1:Root[0000, 0]@60..65#ROOT2024
|
||||
PUNCH ' [joint] 1:Root[0000, 0]@66..67#ROOT2024
|
||||
IDENT foo 1:Root[0000, 0]@67..70#ROOT2024
|
||||
IDENT bar 1:Root[0000, 0]@71..74#ROOT2024
|
||||
PUNCH ; [alone] 0:Root[0000, 0]@44..45#ROOT2024
|
||||
|
||||
4;
|
||||
"literal";
|
||||
|
|
@ -346,13 +348,13 @@ fn expr_2021() {
|
|||
expect![[r#"
|
||||
ExpandError {
|
||||
inner: (
|
||||
1:0@5..6#ROOT2024,
|
||||
1:Root[0000, 0]@5..6#ROOT2024,
|
||||
NoMatchingRule,
|
||||
),
|
||||
}
|
||||
|
||||
SUBTREE $$ 1:0@0..8#ROOT2024 1:0@0..8#ROOT2024
|
||||
PUNCH ; [alone] 0:0@44..45#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..8#ROOT2024 1:Root[0000, 0]@0..8#ROOT2024
|
||||
PUNCH ; [alone] 0:Root[0000, 0]@44..45#ROOT2024
|
||||
|
||||
;"#]],
|
||||
);
|
||||
|
|
@ -370,88 +372,88 @@ fn minus_belongs_to_literal() {
|
|||
check(
|
||||
"-1",
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024
|
||||
PUNCH - [alone] 0:0@10..11#ROOT2024
|
||||
LITERAL Integer 1 0:0@11..12#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024
|
||||
PUNCH - [alone] 0:Root[0000, 0]@10..11#ROOT2024
|
||||
LITERAL Integer 1 0:Root[0000, 0]@11..12#ROOT2024
|
||||
|
||||
-1"#]],
|
||||
);
|
||||
check(
|
||||
"- 1",
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024
|
||||
PUNCH - [alone] 0:0@10..11#ROOT2024
|
||||
LITERAL Integer 1 0:0@11..12#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..3#ROOT2024 1:Root[0000, 0]@0..3#ROOT2024
|
||||
PUNCH - [alone] 0:Root[0000, 0]@10..11#ROOT2024
|
||||
LITERAL Integer 1 0:Root[0000, 0]@11..12#ROOT2024
|
||||
|
||||
-1"#]],
|
||||
);
|
||||
check(
|
||||
"-2",
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024
|
||||
PUNCH - [alone] 0:0@25..26#ROOT2024
|
||||
LITERAL Integer 2 0:0@27..28#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024
|
||||
PUNCH - [alone] 0:Root[0000, 0]@25..26#ROOT2024
|
||||
LITERAL Integer 2 0:Root[0000, 0]@27..28#ROOT2024
|
||||
|
||||
-2"#]],
|
||||
);
|
||||
check(
|
||||
"- 2",
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024
|
||||
PUNCH - [alone] 0:0@25..26#ROOT2024
|
||||
LITERAL Integer 2 0:0@27..28#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..3#ROOT2024 1:Root[0000, 0]@0..3#ROOT2024
|
||||
PUNCH - [alone] 0:Root[0000, 0]@25..26#ROOT2024
|
||||
LITERAL Integer 2 0:Root[0000, 0]@27..28#ROOT2024
|
||||
|
||||
-2"#]],
|
||||
);
|
||||
check(
|
||||
"-3.0",
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..4#ROOT2024 1:0@0..4#ROOT2024
|
||||
PUNCH - [alone] 0:0@43..44#ROOT2024
|
||||
LITERAL Float 3.0 0:0@45..48#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..4#ROOT2024 1:Root[0000, 0]@0..4#ROOT2024
|
||||
PUNCH - [alone] 0:Root[0000, 0]@43..44#ROOT2024
|
||||
LITERAL Float 3.0 0:Root[0000, 0]@45..48#ROOT2024
|
||||
|
||||
-3.0"#]],
|
||||
);
|
||||
check(
|
||||
"- 3.0",
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..5#ROOT2024 1:0@0..5#ROOT2024
|
||||
PUNCH - [alone] 0:0@43..44#ROOT2024
|
||||
LITERAL Float 3.0 0:0@45..48#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..5#ROOT2024 1:Root[0000, 0]@0..5#ROOT2024
|
||||
PUNCH - [alone] 0:Root[0000, 0]@43..44#ROOT2024
|
||||
LITERAL Float 3.0 0:Root[0000, 0]@45..48#ROOT2024
|
||||
|
||||
-3.0"#]],
|
||||
);
|
||||
check(
|
||||
"@1",
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024
|
||||
LITERAL Integer 1 1:0@1..2#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024
|
||||
LITERAL Integer 1 1:Root[0000, 0]@1..2#ROOT2024
|
||||
|
||||
1"#]],
|
||||
);
|
||||
check(
|
||||
"@-1",
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024
|
||||
PUNCH - [alone] 1:0@1..2#ROOT2024
|
||||
LITERAL Integer 1 1:0@2..3#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..3#ROOT2024 1:Root[0000, 0]@0..3#ROOT2024
|
||||
PUNCH - [alone] 1:Root[0000, 0]@1..2#ROOT2024
|
||||
LITERAL Integer 1 1:Root[0000, 0]@2..3#ROOT2024
|
||||
|
||||
-1"#]],
|
||||
);
|
||||
check(
|
||||
"@1.0",
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..4#ROOT2024 1:0@0..4#ROOT2024
|
||||
LITERAL Float 1.0 1:0@1..4#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..4#ROOT2024 1:Root[0000, 0]@0..4#ROOT2024
|
||||
LITERAL Float 1.0 1:Root[0000, 0]@1..4#ROOT2024
|
||||
|
||||
1.0"#]],
|
||||
);
|
||||
check(
|
||||
"@-1.0",
|
||||
expect![[r#"
|
||||
SUBTREE $$ 1:0@0..5#ROOT2024 1:0@0..5#ROOT2024
|
||||
PUNCH - [alone] 1:0@1..2#ROOT2024
|
||||
LITERAL Float 1.0 1:0@2..5#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..5#ROOT2024 1:Root[0000, 0]@0..5#ROOT2024
|
||||
PUNCH - [alone] 1:Root[0000, 0]@1..2#ROOT2024
|
||||
LITERAL Float 1.0 1:Root[0000, 0]@2..5#ROOT2024
|
||||
|
||||
-1.0"#]],
|
||||
);
|
||||
|
|
@ -460,16 +462,16 @@ fn minus_belongs_to_literal() {
|
|||
expect![[r#"
|
||||
ExpandError {
|
||||
inner: (
|
||||
1:0@1..2#ROOT2024,
|
||||
1:Root[0000, 0]@1..2#ROOT2024,
|
||||
BindingError(
|
||||
"expected literal",
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
SUBTREE $$ 1:0@0..6#ROOT2024 1:0@0..6#ROOT2024
|
||||
PUNCH - [joint] 1:0@1..2#ROOT2024
|
||||
PUNCH - [alone] 1:0@2..3#ROOT2024
|
||||
SUBTREE $$ 1:Root[0000, 0]@0..6#ROOT2024 1:Root[0000, 0]@0..6#ROOT2024
|
||||
PUNCH - [joint] 1:Root[0000, 0]@1..2#ROOT2024
|
||||
PUNCH - [alone] 1:Root[0000, 0]@2..3#ROOT2024
|
||||
|
||||
--"#]],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -22,9 +22,10 @@ pub const HAS_GLOBAL_SPANS: u32 = 3;
|
|||
pub const RUST_ANALYZER_SPAN_SUPPORT: u32 = 4;
|
||||
/// Whether literals encode their kind as an additional u32 field and idents their rawness as a u32 field.
|
||||
pub const EXTENDED_LEAF_DATA: u32 = 5;
|
||||
pub const HASHED_AST_ID: u32 = 6;
|
||||
|
||||
/// Current API version of the proc-macro protocol.
|
||||
pub const CURRENT_API_VERSION: u32 = EXTENDED_LEAF_DATA;
|
||||
pub const CURRENT_API_VERSION: u32 = HASHED_AST_ID;
|
||||
|
||||
/// Represents requests sent from the client to the proc-macro-srv.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
|
|
@ -201,7 +202,9 @@ type ProtocolWrite<W: Write> = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str)
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use intern::{Symbol, sym};
|
||||
use span::{Edition, ErasedFileAstId, Span, SpanAnchor, SyntaxContext, TextRange, TextSize};
|
||||
use span::{
|
||||
Edition, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, TextRange, TextSize,
|
||||
};
|
||||
use tt::{
|
||||
Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, Spacing, TopSubtree,
|
||||
TopSubtreeBuilder,
|
||||
|
|
@ -215,7 +218,7 @@ mod tests {
|
|||
span::FileId::from_raw(0xe4e4e),
|
||||
span::Edition::CURRENT,
|
||||
),
|
||||
ast_id: ErasedFileAstId::from_raw(0),
|
||||
ast_id: ROOT_ERASED_FILE_AST_ID,
|
||||
};
|
||||
|
||||
let mut builder = TopSubtreeBuilder::new(Delimiter {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue