Avoid referring to the item tree except in the def map

Item tree IDs are very unstable (adding an item of a kind invalidates all following items of the same kind). Instead use ast ids, which, since the previous commit, are pretty stable.
This commit is contained in:
Chayim Refael Friedman 2025-05-21 13:13:34 +03:00
parent 4bcf03e28b
commit ed0b4506dd
37 changed files with 981 additions and 955 deletions

View file

@ -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::AttrOwner,
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,12 +517,12 @@ 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 {
let raw_attrs = match mod_data.origin {
ModuleOrigin::File { definition, declaration_tree_id, .. } => {
let decl_attrs = declaration_tree_id
.item_tree(db)
@ -515,34 +544,33 @@ impl AttrsWithOwner {
let tree = db.block_item_tree(id);
tree.raw_attrs(AttrOwner::TopLevel).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 +578,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 +591,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 +604,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 +812,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(

View file

@ -1,8 +1,11 @@
//! 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 intern::sym;
use hir_expand::{
EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind,
db::ExpandDatabase,
};
use intern::{Symbol, sym};
use la_arena::ArenaMap;
use syntax::{AstPtr, ast};
use thin_vec::ThinVec;
@ -11,8 +14,8 @@ use triomphe::Arc;
use crate::{
AttrDefId, BlockId, BlockLoc, 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},
@ -123,6 +126,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
id: VariantId,
) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>);
// FIXME: Should we make this transparent? The only unstable thing in `enum_variants_with_diagnostics()`
// is ast ids, and ast ids are pretty stable now.
#[salsa::tracked]
fn enum_variants(&self, id: EnumId) -> Arc<EnumVariants> {
self.enum_variants_with_diagnostics(id).0
@ -263,6 +268,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
e: TypeAliasId,
) -> (Arc<TypeAliasSignature>, Arc<ExpressionStoreSourceMap>);
#[salsa::invoke(crate::signatures::extern_block_abi_query)]
fn extern_block_abi(&self, extern_block: ExternBlockId) -> Option<Symbol>;
// endregion:data
#[salsa::invoke(Body::body_with_source_map_query)]
@ -399,10 +407,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 +422,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 +433,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 +446,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,

View file

@ -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)]

View file

@ -10,9 +10,10 @@ use std::mem;
use cfg::CfgOptions;
use either::Either;
use hir_expand::{
HirFileId, InFile, Lookup, MacroDefId,
HirFileId, InFile, MacroDefId,
mod_path::tool_path,
name::{AsName, Name},
span_map::SpanMapRef,
};
use intern::{Symbol, sym};
use rustc_hash::FxHashMap;
@ -30,8 +31,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::{
@ -564,6 +565,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() {
@ -2244,11 +2250,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()))
}

View file

@ -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);
@ -1089,10 +1076,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 {

View file

@ -46,7 +46,7 @@ use std::{
use ast::{AstNode, StructKind};
use base_db::Crate;
use hir_expand::{
ExpandTo, HirFileId, InFile,
ExpandTo, HirFileId,
attrs::RawAttrs,
mod_path::{ModPath, PathKind},
name::Name,
@ -62,6 +62,8 @@ use triomphe::Arc;
use crate::{BlockId, Lookup, attr::Attrs, db::DefDatabase};
pub(crate) use crate::item_tree::lower::{lower_use_tree, visibility_from_ast};
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct RawVisibilityId(u32);
@ -446,6 +448,7 @@ impl TreeId {
}
}
#[inline]
pub fn file_id(self) -> HirFileId {
self.file
}
@ -878,43 +881,6 @@ pub struct Macro2 {
pub ast_id: FileAstId<ast::MacroDef>,
}
impl Use {
/// Maps a `UseTree` contained in this import back to its AST node.
pub fn use_tree_to_ast(
&self,
db: &dyn DefDatabase,
file_id: HirFileId,
index: Idx<ast::UseTree>,
) -> 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 = InFile::new(file_id, self.ast_id).to_node(db);
let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
let (_, source_map) = lower::lower_use_tree(db, ast_use_tree, &mut |range| {
db.span_map(file_id).span_for_range(range).ctx
})
.expect("failed to lower use tree");
source_map[index].clone()
}
/// Maps a `UseTree` contained in this import back to its AST node.
pub fn use_tree_source_map(
&self,
db: &dyn DefDatabase,
file_id: HirFileId,
) -> 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 = InFile::new(file_id, self.ast_id).to_node(db);
let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
lower::lower_use_tree(db, ast_use_tree, &mut |range| {
db.span_map(file_id).span_for_range(range).ctx
})
.expect("failed to lower use tree")
.1
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ImportKind {
/// The `ModPath` is imported normally.

View file

@ -626,7 +626,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,

View file

@ -258,7 +258,7 @@ impl Printer<'_> {
let Enum { name, visibility, variants, ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "enum {}", name.display(self.db, self.edition));
w!(self, "enum {} {{", name.display(self.db, self.edition));
let edition = self.edition;
self.indented(|this| {
for variant in FileItemTreeId::range_iter(variants.clone()) {

View file

@ -147,7 +147,7 @@ enum E {
}
// AstId: Enum[7FF8, 0]
pub(self) enum E
pub(self) enum E {
// AstId: Variant[C717, 0]
#[doc = " comment on Unit"]
Unit,

View file

@ -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, _)| {
db.enum_variants(e).variants.iter().for_each(|&(id, _, _)| {
lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant);
});
}

View file

@ -74,12 +74,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,10 +87,6 @@ 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, block_def_map, crate_def_map, crate_local_def_map},
signatures::VariantFields,
};
@ -113,70 +108,110 @@ 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> {
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 +221,68 @@ 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>;
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>;
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);
#[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 +291,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 +330,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 {
@ -338,6 +367,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,6 +507,13 @@ 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>;
@ -642,15 +690,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(),
)
@ -768,8 +811,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 +978,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 +1020,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 +1046,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)
}

View file

@ -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>,

View file

@ -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,16 +89,15 @@ 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)>,
}
impl ImplItems {
@ -99,18 +111,18 @@ impl ImplItems {
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 ItemLoc { container: module_id, id: ast_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);
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());
(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 +131,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 +241,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 +303,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 +316,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 +325,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 +342,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;
}
}

View file

@ -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, FileItemTreeId, ImportAlias, ImportKind, ItemTree, ItemTreeId,
ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind,
},
macro_call_as_call_id,
nameres::{
@ -141,6 +140,7 @@ struct ImportSource {
id: UseId,
is_prelude: bool,
kind: ImportKind,
item_tree_id: ItemTreeId<item_tree::Use>,
}
#[derive(Debug, Eq, PartialEq)]
@ -166,7 +166,7 @@ impl Import {
path,
alias,
visibility: visibility.clone(),
source: ImportSource { use_tree: idx, id, is_prelude, kind },
source: ImportSource { use_tree: idx, id, is_prelude, kind, item_tree_id },
});
});
}
@ -576,13 +576,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 +592,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,
@ -866,6 +860,7 @@ impl DefCollector<'_> {
kind: kind @ (ImportKind::Plain | ImportKind::TypeOnly),
id,
use_tree,
item_tree_id,
..
} => {
let name = match &import.alias {
@ -887,9 +882,33 @@ 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;
};
let item_tree = item_tree_id.item_tree(self.db);
let use_kind = item_tree[item_tree_id.value].use_tree.kind();
let UseTreeKind::Single { path, .. } = use_kind else {
return false;
};
matches!(path.kind, PathKind::Plain | PathKind::SELF)
&& 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() {
@ -978,7 +997,7 @@ impl DefCollector<'_> {
.enum_variants(e)
.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 +1169,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);
@ -1648,7 +1642,8 @@ impl DefCollector<'_> {
import:
Import {
ref path,
source: ImportSource { use_tree, id, is_prelude: _, kind: _ },
source:
ImportSource { use_tree, id, is_prelude: _, kind: _, item_tree_id: _ },
..
},
..
@ -1730,7 +1725,26 @@ impl ModCollector<'_, '_> {
let attrs = self.item_tree.attrs(db, krate, item.into());
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 = match item {
ModItem::Use(it) => self.item_tree[it].ast_id.erase(),
ModItem::ExternCrate(it) => self.item_tree[it].ast_id.erase(),
ModItem::ExternBlock(it) => self.item_tree[it].ast_id.erase(),
ModItem::Function(it) => self.item_tree[it].ast_id.erase(),
ModItem::Struct(it) => self.item_tree[it].ast_id.erase(),
ModItem::Union(it) => self.item_tree[it].ast_id.erase(),
ModItem::Enum(it) => self.item_tree[it].ast_id.erase(),
ModItem::Const(it) => self.item_tree[it].ast_id.erase(),
ModItem::Static(it) => self.item_tree[it].ast_id.erase(),
ModItem::Trait(it) => self.item_tree[it].ast_id.erase(),
ModItem::TraitAlias(it) => self.item_tree[it].ast_id.erase(),
ModItem::Impl(it) => self.item_tree[it].ast_id.erase(),
ModItem::TypeAlias(it) => self.item_tree[it].ast_id.erase(),
ModItem::Mod(it) => self.item_tree[it].ast_id.erase(),
ModItem::MacroCall(it) => self.item_tree[it].ast_id.erase(),
ModItem::MacroRules(it) => self.item_tree[it].ast_id.erase(),
ModItem::Macro2(it) => self.item_tree[it].ast_id.erase(),
};
self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg);
return;
}
}
@ -1751,7 +1765,7 @@ impl ModCollector<'_, '_> {
ModItem::Use(item_tree_id) => {
let id = UseLoc {
container: module,
id: ItemTreeId::new(self.tree_id, item_tree_id),
id: InFile::new(self.file_id(), self.item_tree[item_tree_id].ast_id),
}
.intern(db);
let is_prelude = attrs.by_key(sym::prelude_import).exists();
@ -1770,16 +1784,16 @@ impl ModCollector<'_, '_> {
)
}
ModItem::ExternCrate(item_tree_id) => {
let item_tree::ExternCrate { name, visibility, alias, ast_id } =
&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(), *ast_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);
@ -1846,7 +1860,7 @@ impl ModCollector<'_, '_> {
ModItem::ExternBlock(block) => {
let extern_block_id = ExternBlockLoc {
container: module,
id: ItemTreeId::new(self.tree_id, block),
id: InFile::new(self.file_id(), self.item_tree[block].ast_id),
}
.intern(db);
self.def_collector.def_map.modules[self.module_id]
@ -1861,15 +1875,20 @@ impl ModCollector<'_, '_> {
ModItem::MacroRules(id) => self.collect_macro_rules(id, module),
ModItem::Macro2(id) => self.collect_macro_def(id, module),
ModItem::Impl(imp) => {
let impl_id =
ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) }
.intern(db);
let impl_id = ImplLoc {
container: module,
id: InFile::new(self.file_id(), self.item_tree[imp].ast_id),
}
.intern(db);
self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
}
ModItem::Function(id) => {
let it = &self.item_tree[id];
let fn_id =
FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
let fn_id = FunctionLoc {
container,
id: InFile::new(self.tree_id.file_id(), it.ast_id),
}
.intern(db);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
@ -1880,7 +1899,6 @@ 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()),
fn_id,
);
@ -1895,7 +1913,7 @@ impl ModCollector<'_, '_> {
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(), it.ast_id) }
.intern(db)
.into(),
&it.name,
@ -1909,7 +1927,7 @@ impl ModCollector<'_, '_> {
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(), it.ast_id) }
.intern(db)
.into(),
&it.name,
@ -1919,9 +1937,11 @@ impl ModCollector<'_, '_> {
}
ModItem::Enum(id) => {
let it = &self.item_tree[id];
let enum_ =
EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
.intern(db);
let enum_ = EnumLoc {
container: module,
id: InFile::new(self.tree_id.file_id(), it.ast_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);
@ -1929,7 +1949,8 @@ impl ModCollector<'_, '_> {
ModItem::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(), it.ast_id) }
.intern(db);
match &it.name {
Some(name) => {
@ -1951,7 +1972,7 @@ impl ModCollector<'_, '_> {
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(), it.ast_id) }
.intern(db)
.into(),
&it.name,
@ -1965,7 +1986,7 @@ impl ModCollector<'_, '_> {
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(), it.ast_id) }
.intern(db)
.into(),
&it.name,
@ -1979,9 +2000,12 @@ impl ModCollector<'_, '_> {
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) }
.intern(db)
.into(),
TraitAliasLoc {
container: module,
id: InFile::new(self.file_id(), it.ast_id),
}
.intern(db)
.into(),
&it.name,
vis,
false,
@ -1993,7 +2017,7 @@ impl ModCollector<'_, '_> {
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(), it.ast_id) }
.intern(db)
.into(),
&it.name,
@ -2110,8 +2134,10 @@ impl ModCollector<'_, '_> {
match is_enabled {
Err(cfg) => {
self.emit_unconfigured_diagnostic(
self.tree_id,
AttrOwner::ModItem(module_id.into()),
InFile::new(
self.file_id(),
self.item_tree[module_id].ast_id.erase(),
),
&cfg,
);
}
@ -2352,7 +2378,7 @@ impl ModCollector<'_, '_> {
let macro_id = MacroRulesLoc {
container: module,
id: ItemTreeId::new(self.tree_id, id),
id: InFile::new(self.file_id(), mac.ast_id),
flags,
expander,
edition: self.def_collector.def_map.data.edition,
@ -2420,7 +2446,7 @@ impl ModCollector<'_, '_> {
let macro_id = Macro2Loc {
container: module,
id: ItemTreeId::new(self.tree_id, id),
id: InFile::new(self.file_id(), mac.ast_id),
expander,
allow_internal_unsafe,
edition: self.def_collector.def_map.data.edition,
@ -2565,16 +2591,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()
}

View file

@ -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 },
}
}

View file

@ -12,7 +12,6 @@
use either::Either;
use hir_expand::{
Lookup,
mod_path::{ModPath, PathKind},
name::Name,
};
@ -529,23 +528,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 = db
.enum_variants(e)
.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) => {

View file

@ -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},
};
@ -627,14 +628,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 +1472,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)
}

View file

@ -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,7 +881,7 @@ pub struct InactiveEnumVariantCode {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumVariants {
pub variants: Box<[(EnumVariantId, Name)]>,
pub variants: Box<[(EnumVariantId, Name, FieldsShape)]>,
}
impl EnumVariants {
@ -914,30 +890,38 @@ impl EnumVariants {
e: EnumId,
) -> (Arc<EnumVariants>, Option<Arc<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 (Arc::new(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();
@ -949,12 +933,18 @@ impl EnumVariants {
}
pub fn variant(&self, name: &Name) -> Option<EnumVariantId> {
self.variants.iter().find_map(|(v, n)| if n == name { Some(*v) } else { None })
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 +963,17 @@ impl EnumVariants {
})
}
}
pub(crate) fn extern_block_abi_query(
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,
}
})
}

View file

@ -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)
}

View file

@ -2,16 +2,18 @@
use std::iter;
use hir_expand::Lookup;
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,
ConstId, FunctionId, HasModule, ItemContainerId, LocalFieldId, LocalModuleId, ModuleId,
TraitId, TypeAliasId, VariantId,
db::DefDatabase,
nameres::DefMap,
resolver::{HasResolver, Resolver},
src::HasSource,
};
pub use crate::item_tree::{RawVisibility, VisibilityExplicitness};
@ -217,49 +219,69 @@ 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)
}
pub fn visibility_from_ast(
db: &dyn DefDatabase,
resolver: &Resolver<'_>,
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
});
Visibility::resolve(db, resolver, &raw_vis)
}
fn trait_item_visibility(
db: &dyn DefDatabase,
resolver: &Resolver<'_>,
container: ItemContainerId,
) -> Option<Visibility> {
match container {
ItemContainerId::TraitId(trait_) => Some(trait_visibility(db, resolver, trait_)),
_ => None,
}
}
/// 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])
}
let resolver = def.resolver(db);
trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| {
let source = loc.source(db);
visibility_from_ast(db, &resolver, source.map(|src| src.visibility()))
})
}
/// 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])
}
let resolver = def.resolver(db);
trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| {
let source = loc.source(db);
visibility_from_ast(db, &resolver, source.map(|src| src.visibility()))
})
}
/// 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])
}
let resolver = def.resolver(db);
trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| {
let source = loc.source(db);
visibility_from_ast(db, &resolver, 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])
pub(crate) fn trait_visibility(
db: &dyn DefDatabase,
resolver: &Resolver<'_>,
def: TraitId,
) -> Visibility {
let loc = def.lookup(db);
let source = loc.source(db);
visibility_from_ast(db, resolver, source.map(|src| src.visibility()))
}

View file

@ -2,7 +2,7 @@
use std::borrow::Borrow;
use either::Either;
use span::{ErasedFileAstId, FileAstId, FileId, SyntaxContext};
use span::{AstIdNode, ErasedFileAstId, FileAstId, FileId, SyntaxContext};
use syntax::{AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize};
use crate::{
@ -122,6 +122,13 @@ impl<N: AstNode> 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>;

View file

@ -817,7 +817,7 @@ pub(crate) fn adt_datum_query(
.enum_variants(id)
.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)
}

View file

@ -397,7 +397,7 @@ impl<'a> DeclValidator<'a> {
fn validate_enum_variants(&mut self, enum_id: EnumId) {
let data = self.db.enum_variants(enum_id);
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(),

View file

@ -465,7 +465,7 @@ impl PatCx for MatchCheckCtx<'_> {
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,

View file

@ -71,7 +71,7 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironm
.enum_variants(id)
.variants
.iter()
.map(|&(variant, _)| {
.map(|&(variant, _, _)| {
db.field_types(variant.into())
.iter()
.map(|(_, field_ty)| {

View file

@ -115,7 +115,7 @@ impl UninhabitedFrom<'_> {
AdtId::EnumId(e) => {
let enum_data = self.db.enum_variants(e);
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) => (),

View file

@ -60,7 +60,7 @@ pub fn layout_of_adt_query(
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)
}

View file

@ -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),
self.db
.enum_variants(loc.parent)
.variant_name_by_id(variant)
.unwrap()
.display(db, edition),
);
Err(MirEvalError::ConstEvalError(name, Box::new(e)))
}

View file

@ -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)
self.db.extern_block_abi(block) == Some(sym::rust_dash_intrinsic)
}
_ => false,
},
@ -87,8 +85,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)
self.db.extern_block_abi(block) == Some(sym::C)
}
_ => false,
};

View file

@ -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),
self.db
.enum_variants(loc.parent)
.variant_name_by_id(variant)
.unwrap()
.display(db, edition),
);
Err(MirLowerError::ConstEvalError(name.into(), Box::new(e)))
}

View file

@ -63,16 +63,15 @@ 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),
db.enum_variants(loc.parent)
.variant_name_by_id(id)
.unwrap()
.display(db, edition),
)
}
});

View file

@ -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, _)| {
db.enum_variants(it).variants.iter().for_each(|&(it, _, _)| {
let body = db.body(it.into());
cb(it.into());
visit_body(db, &body, cb);

View file

@ -353,6 +353,7 @@ impl SomeStruct {
"impl_self_ty_with_diagnostics_shim".to_owned(),
"struct_signature_shim".to_owned(),
"struct_signature_with_source_map_shim".to_owned(),
"attrs_shim".to_owned(),
"type_for_adt_tracked".to_owned(),
];
@ -442,6 +443,6 @@ fn main() {
let _inference_result = db.infer(def);
}
});
assert!(format!("{events:?}").contains("trait_solve_shim"))
assert!(!format!("{events:?}").contains("trait_solve_shim"))
}
}

View file

@ -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 = db.extern_block_abi(block) == 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

View file

@ -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, _)| {
db.enum_variants(e).variants.iter().for_each(|&(variant, _, _)| {
add_constraints_from_variant(VariantId::EnumVariantId(variant))
});
}

View file

@ -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};
@ -687,7 +689,7 @@ impl Module {
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 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
@ -765,11 +765,11 @@ impl Module {
}
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()),
_ => (),
};
@ -839,7 +839,7 @@ 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(),
@ -889,7 +889,7 @@ impl Module {
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,
}
@ -1076,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);
@ -1478,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.resolver(db), source.map(|src| src.visibility()))
}
}
@ -1536,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.resolver(db), source.map(|src| src.visibility()))
}
}
@ -1560,7 +1504,7 @@ impl Enum {
}
pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> {
db.enum_variants(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect()
db.enum_variants(self.id).variants.iter().map(|&(id, _, _)| Variant { id }).collect()
}
pub fn num_variants(self, db: &dyn HirDatabase) -> usize {
@ -1629,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.resolver(db), source.map(|src| src.visibility()))
}
}
@ -2708,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| {
@ -2722,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)),
}
}
}
@ -2748,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.resolver(db), source.map(|src| src.visibility()))
}
}
@ -2873,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.resolver(db), source.map(|src| src.visibility()))
}
}
@ -2967,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.
@ -2983,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.resolver(db), source.map(|src| src.visibility()))
}
}
@ -3010,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.resolver(db), source.map(|src| src.visibility()))
}
}
@ -3163,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()),
}
}
}
@ -3278,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.resolver(db), source.map(|src| src.visibility()))
}
MacroId::MacroRulesId(_) => Visibility::Public,
MacroId::ProcMacroId(_) => Visibility::Public,
@ -3437,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))),
@ -3453,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))),
@ -4545,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()
db.impl_items(self.id).macro_calls.to_vec().into_boxed_slice()
}
}
@ -6510,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())
}

View file

@ -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},
};
@ -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);
db.enum_variants(*self).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)
}
}