10960: fix: fix handling of macros in `extern` blocks r=jonas-schievink a=jonas-schievink

- Removes knowledge of what's in an extern block from `ItemTree`.
- Treats extern blocks as `AssocContainerId` and renames the latter to `ItemContainerId`.
- Threads the container through name resolution (which is a bit messy).
- Considers statics to be associated items, since they can be in an extern block. (it might be better to further distinguish potentially-associated-items from potentially-in-an-extern-block-items, but currently I don't expect much of a benefit)
- Adds a test for the incorrect-case diagnostic demonstrating the impact of this change.

Fixes https://github.com/rust-analyzer/rust-analyzer/issues/8913

bors r+

Co-authored-by: Jonas Schievink <jonas.schievink@ferrous-systems.com>
This commit is contained in:
bors[bot] 2021-12-07 16:52:21 +00:00 committed by GitHub
commit 755b668ae4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 216 additions and 164 deletions

View File

@ -137,6 +137,7 @@ fn resolve_doc_path(
AttrDefId::TraitId(it) => it.resolver(db.upcast()),
AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()),
AttrDefId::ImplId(it) => it.resolver(db.upcast()),
AttrDefId::ExternBlockId(it) => it.resolver(db.upcast()),
AttrDefId::GenericParamId(it) => match it {
GenericParamId::TypeParamId(it) => it.parent,
GenericParamId::LifetimeParamId(it) => it.parent,

View File

@ -114,11 +114,11 @@
type_ref::{Mutability, TypeRef},
visibility::Visibility,
AdtId,
AssocContainerId,
AssocItemId,
AssocItemLoc,
DefWithBodyId,
ImplId,
ItemContainerId,
ItemLoc,
Lookup,
ModuleDefId,
@ -1550,7 +1550,7 @@ pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
pub fn ty(self, db: &dyn HirDatabase) -> Type {
let data = db.static_data(self.id);
let resolver = self.id.resolver(db.upcast());
let krate = self.id.lookup(db.upcast()).container.krate();
let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
let ty = ctx.lower_ty(&data.type_ref);
Type::new_with_resolver_inner(db, krate, &resolver, ty)
@ -1820,8 +1820,8 @@ fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -
AST: ItemTreeNode,
{
match id.lookup(db.upcast()).container {
AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
AssocContainerId::ModuleId(_) => None,
ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
}
}
@ -1847,9 +1847,11 @@ pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer {
AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container,
};
match container {
AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
AssocContainerId::ModuleId(_) => panic!("invalid AssocItem"),
ItemContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
ItemContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
panic!("invalid AssocItem")
}
}
}

View File

@ -362,6 +362,7 @@ pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Self {
RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
}
},
AttrDefId::ExternBlockId(it) => attrs_from_item_tree(it.lookup(db).id, db),
};
let attrs = raw_attrs.filter(db, def.krate(db));
@ -443,6 +444,7 @@ pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap {
.child_source(db)
.map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())),
},
AttrDefId::ExternBlockId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
};
AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs))

View File

@ -13,8 +13,8 @@
item_tree::{self, AssocItem, FnFlags, ItemTreeId, ModItem, Param},
type_ref::{TraitRef, TypeBound, TypeRef},
visibility::RawVisibility,
AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, Intern,
ItemContainerId, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
};
#[derive(Debug, Clone, PartialEq, Eq)]
@ -54,6 +54,10 @@ pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<Funct
flags.bits |= FnFlags::IS_VARARGS;
}
if matches!(loc.container, ItemContainerId::ExternBlockId(_)) {
flags.bits |= FnFlags::IS_IN_EXTERN_BLOCK;
}
Arc::new(FunctionData {
name: func.name.clone(),
params: enabled_params
@ -130,7 +134,7 @@ pub(crate) fn type_alias_data_query(
name: typ.name.clone(),
type_ref: typ.type_ref.clone(),
visibility: item_tree[typ.visibility].clone(),
is_extern: typ.is_extern,
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
bounds: typ.bounds.to_vec(),
})
}
@ -162,7 +166,7 @@ pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitDa
let is_auto = tr_def.is_auto;
let is_unsafe = tr_def.is_unsafe;
let module_id = tr_loc.container;
let container = AssocContainerId::TraitId(tr);
let container = ItemContainerId::TraitId(tr);
let visibility = item_tree[tr_def.visibility].clone();
let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
let skip_array_during_method_dispatch = item_tree
@ -231,7 +235,7 @@ pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData>
let self_ty = impl_def.self_ty.clone();
let is_negative = impl_def.is_negative;
let module_id = impl_loc.container;
let container = AssocContainerId::ImplId(id);
let container = ItemContainerId::ImplId(id);
let mut expander = Expander::new(db, impl_loc.id.file_id(), module_id);
let items = collect_items(
@ -282,16 +286,16 @@ pub struct StaticData {
impl StaticData {
pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> {
let node = konst.lookup(db);
let item_tree = node.id.item_tree(db);
let statik = &item_tree[node.id.value];
let loc = konst.lookup(db);
let item_tree = loc.id.item_tree(db);
let statik = &item_tree[loc.id.value];
Arc::new(StaticData {
name: statik.name.clone(),
type_ref: statik.type_ref.clone(),
visibility: item_tree[statik.visibility].clone(),
mutable: statik.mutable,
is_extern: statik.is_extern,
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
})
}
}
@ -302,7 +306,7 @@ fn collect_items(
expander: &mut Expander,
assoc_items: impl Iterator<Item = AssocItem>,
tree_id: item_tree::TreeId,
container: AssocContainerId,
container: ItemContainerId,
limit: usize,
) -> Vec<(Name, AssocItemId)> {
if limit == 0 {

View File

@ -19,10 +19,10 @@
lang_item::{LangItemTarget, LangItems},
nameres::DefMap,
visibility::{self, Visibility},
AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId,
FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId,
StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId,
UnionLoc, VariantId,
AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId,
ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId,
LocalFieldId, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId,
TypeAliasLoc, UnionId, UnionLoc, VariantId,
};
#[salsa::query_group(InternDatabaseStorage)]
@ -46,6 +46,8 @@ pub trait InternDatabase: SourceDatabase {
#[salsa::interned]
fn intern_impl(&self, loc: ImplLoc) -> ImplId;
#[salsa::interned]
fn intern_extern_block(&self, loc: ExternBlockLoc) -> ExternBlockId;
#[salsa::interned]
fn intern_block(&self, loc: BlockLoc) -> BlockId;
}

View File

@ -468,7 +468,7 @@ mod tests {
use base_db::{fixture::WithFixture, SourceDatabase, Upcast};
use expect_test::{expect, Expect};
use crate::{test_db::TestDB, AssocContainerId, Lookup};
use crate::{test_db::TestDB, ItemContainerId, Lookup};
use super::*;
@ -563,7 +563,7 @@ fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> Option<ItemInNs> {
};
match container {
AssocContainerId::TraitId(it) => Some(ItemInNs::Types(it.into())),
ItemContainerId::TraitId(it) => Some(ItemInNs::Types(it.into())),
_ => None,
}
}

View File

@ -660,8 +660,6 @@ pub struct Static {
pub name: Name,
pub visibility: RawVisibilityId,
pub mutable: bool,
/// Whether the static is in an `extern` block.
pub is_extern: bool,
pub type_ref: Interned<TypeRef>,
pub ast_id: FileAstId<ast::Static>,
}
@ -695,7 +693,6 @@ pub struct TypeAlias {
pub bounds: Box<[Interned<TypeBound>]>,
pub generic_params: Interned<GenericParams>,
pub type_ref: Option<Interned<TypeRef>>,
pub is_extern: bool,
pub ast_id: FileAstId<ast::TypeAlias>,
}

View File

@ -360,7 +360,6 @@ fn lower_type_alias(
generic_params,
type_ref,
ast_id,
is_extern: false,
};
Some(id(self.data().type_aliases.alloc(res)))
}
@ -371,7 +370,7 @@ fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Stati
let visibility = self.lower_visibility(static_);
let mutable = static_.mut_token().is_some();
let ast_id = self.source_ast_id_map.ast_id(static_);
let res = Static { name, visibility, mutable, type_ref, ast_id, is_extern: false };
let res = Static { name, visibility, mutable, type_ref, ast_id };
Some(id(self.data().statics.alloc(res)))
}
@ -525,27 +524,23 @@ fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> FileItemTreeId<Ext
let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| {
list.extern_items()
.filter_map(|item| {
// Note: All items in an `extern` block need to be lowered as if they're outside of one
// (in other words, the knowledge that they're in an extern block must not be used).
// This is because an extern block can contain macros whose ItemTree's top-level items
// should be considered to be in an extern block too.
let attrs = RawAttrs::new(self.db, &item, &self.hygiene);
let id: ModItem = match item {
ast::ExternItem::Fn(ast) => {
let func_id = self.lower_function(&ast)?;
let func = &mut self.data().functions[func_id.index];
if is_intrinsic_fn_unsafe(&func.name) {
// FIXME: this breaks in macros
func.flags.bits |= FnFlags::IS_UNSAFE;
}
func.flags.bits |= FnFlags::IS_IN_EXTERN_BLOCK;
func_id.into()
}
ast::ExternItem::Static(ast) => {
let statik = self.lower_static(&ast)?;
self.data().statics[statik.index].is_extern = true;
statik.into()
}
ast::ExternItem::TypeAlias(ty) => {
let foreign_ty = self.lower_type_alias(&ty)?;
self.data().type_aliases[foreign_ty.index].is_extern = true;
foreign_ty.into()
}
ast::ExternItem::Static(ast) => self.lower_static(&ast)?.into(),
ast::ExternItem::TypeAlias(ty) => self.lower_type_alias(&ty)?.into(),
ast::ExternItem::MacroCall(call) => {
// FIXME: we need some way of tracking that the macro call is in an
// extern block

View File

@ -328,8 +328,7 @@ fn print_mod_item(&mut self, item: ModItem) {
wln!(self, " = _;");
}
ModItem::Static(it) => {
let Static { name, visibility, mutable, is_extern, type_ref, ast_id: _ } =
&self.tree[it];
let Static { name, visibility, mutable, type_ref, ast_id: _ } = &self.tree[it];
self.print_visibility(*visibility);
w!(self, "static ");
if *mutable {
@ -338,9 +337,6 @@ fn print_mod_item(&mut self, item: ModItem) {
w!(self, "{}: ", name);
self.print_type_ref(type_ref);
w!(self, " = _;");
if *is_extern {
w!(self, " // extern");
}
wln!(self);
}
ModItem::Trait(it) => {
@ -393,15 +389,8 @@ fn print_mod_item(&mut self, item: ModItem) {
wln!(self, "}}");
}
ModItem::TypeAlias(it) => {
let TypeAlias {
name,
visibility,
bounds,
type_ref,
is_extern,
generic_params,
ast_id: _,
} = &self.tree[it];
let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id: _ } =
&self.tree[it];
self.print_visibility(*visibility);
w!(self, "type {}", name);
self.print_generic_params(generic_params);
@ -415,9 +404,6 @@ fn print_mod_item(&mut self, item: ModItem) {
}
self.print_where_clause(generic_params);
w!(self, ";");
if *is_extern {
w!(self, " // extern");
}
wln!(self);
}
ModItem::Mod(it) => {

View File

@ -70,13 +70,13 @@ fn extern_blocks() {
#[on_extern_block] // AttrId { is_doc_comment: false, ast_index: 0 }
extern "C" {
#[on_extern_type] // AttrId { is_doc_comment: false, ast_index: 0 }
pub(self) type ExType; // extern
pub(self) type ExType;
#[on_extern_static] // AttrId { is_doc_comment: false, ast_index: 0 }
pub(self) static EX_STATIC: u8 = _; // extern
pub(self) static EX_STATIC: u8 = _;
#[on_extern_fn] // AttrId { is_doc_comment: false, ast_index: 0 }
// flags = 0x60
// flags = 0x20
pub(self) fn ex_fn() -> ();
}
"##]],

View File

@ -65,6 +65,7 @@ macro_rules! eprintln {
hygiene::Hygiene,
AstId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
};
use item_tree::ExternBlock;
use la_arena::Idx;
use nameres::DefMap;
use path::ModPath;
@ -153,7 +154,7 @@ fn hash<H: Hasher>(&self, state: &mut H) {
#[derive(Debug)]
pub struct AssocItemLoc<N: ItemTreeNode> {
pub container: AssocContainerId,
pub container: ItemContainerId,
pub id: ItemTreeId<N>,
}
@ -244,7 +245,7 @@ pub struct FieldId {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StaticId(salsa::InternId);
pub type StaticLoc = ItemLoc<Static>;
pub type StaticLoc = AssocItemLoc<Static>;
impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -262,6 +263,11 @@ pub struct FieldId {
type ImplLoc = ItemLoc<Impl>;
impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct ExternBlockId(salsa::InternId);
type ExternBlockLoc = ItemLoc<ExternBlock>;
impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct BlockId(salsa::InternId);
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
@ -295,12 +301,13 @@ pub struct ConstParamId {
pub type LocalConstParamId = Idx<generics::ConstParamData>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AssocContainerId {
pub enum ItemContainerId {
ExternBlockId(ExternBlockId),
ModuleId(ModuleId),
ImplId(ImplId),
TraitId(TraitId),
}
impl_from!(ModuleId for AssocContainerId);
impl_from!(ModuleId for ItemContainerId);
/// A Data Type
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
@ -427,6 +434,7 @@ pub enum AttrDefId {
MacroDefId(MacroDefId),
ImplId(ImplId),
GenericParamId(GenericParamId),
ExternBlockId(ExternBlockId),
}
impl_from!(
@ -445,12 +453,13 @@ pub enum AttrDefId {
for AttrDefId
);
impl From<AssocContainerId> for AttrDefId {
fn from(acid: AssocContainerId) -> Self {
impl From<ItemContainerId> for AttrDefId {
fn from(acid: ItemContainerId) -> Self {
match acid {
AssocContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
AssocContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
AssocContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
ItemContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
ItemContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
ItemContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
ItemContainerId::ExternBlockId(id) => AttrDefId::ExternBlockId(id),
}
}
}
@ -505,12 +514,13 @@ pub trait HasModule {
fn module(&self, db: &dyn db::DefDatabase) -> ModuleId;
}
impl HasModule for AssocContainerId {
impl HasModule for ItemContainerId {
fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
match *self {
AssocContainerId::ModuleId(it) => it,
AssocContainerId::ImplId(it) => it.lookup(db).container,
AssocContainerId::TraitId(it) => it.lookup(db).container,
ItemContainerId::ModuleId(it) => it,
ItemContainerId::ImplId(it) => it.lookup(db).container,
ItemContainerId::TraitId(it) => it.lookup(db).container,
ItemContainerId::ExternBlockId(it) => it.lookup(db).container,
}
}
}
@ -587,12 +597,6 @@ fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
}
}
impl HasModule for StaticLoc {
fn module(&self, _db: &dyn db::DefDatabase) -> ModuleId {
self.container
}
}
impl ModuleDefId {
/// Returns the module containing `self` (or `self`, if `self` is itself a module).
///
@ -604,7 +608,7 @@ pub fn module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
ModuleDefId::AdtId(id) => id.module(db),
ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container,
ModuleDefId::ConstId(id) => id.lookup(db).container.module(db),
ModuleDefId::StaticId(id) => id.lookup(db).container,
ModuleDefId::StaticId(id) => id.lookup(db).module(db),
ModuleDefId::TraitId(id) => id.lookup(db).container,
ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db),
ModuleDefId::BuiltinType(_) => return None,
@ -625,6 +629,7 @@ pub fn krate(&self, db: &dyn db::DefDatabase) -> CrateId {
AttrDefId::TraitId(it) => it.lookup(db).container.krate,
AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate,
AttrDefId::ImplId(it) => it.lookup(db).container.krate,
AttrDefId::ExternBlockId(it) => it.lookup(db).container.krate,
AttrDefId::GenericParamId(it) => {
match it {
GenericParamId::TypeParamId(it) => it.parent,

View File

@ -44,9 +44,9 @@
path::{ImportAlias, ModPath, PathKind},
per_ns::PerNs,
visibility::{RawVisibility, Visibility},
AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
UnresolvedMacro,
AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionLoc,
ImplLoc, Intern, ItemContainerId, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc,
TypeAliasLoc, UnionLoc, UnresolvedMacro,
};
static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
@ -213,6 +213,7 @@ struct MacroDirective {
module_id: LocalModuleId,
depth: usize,
kind: MacroDirectiveKind,
container: ItemContainerId,
}
#[derive(Clone, Debug, Eq, PartialEq)]
@ -306,7 +307,7 @@ fn seed_with_top_level(&mut self) {
item_tree: &item_tree,
mod_dir: ModDir::root(),
}
.collect(item_tree.top_level_items());
.collect_in_top_module(item_tree.top_level_items());
}
}
@ -327,7 +328,7 @@ fn seed_with_inner(&mut self, tree_id: TreeId) {
item_tree: &item_tree,
mod_dir: ModDir::root(),
}
.collect(item_tree.top_level_items());
.collect_in_top_module(item_tree.top_level_items());
}
}
@ -433,7 +434,7 @@ fn reseed_with_unresolved_attribute(&mut self) -> ReachedFixedPoint {
item_tree: &item_tree,
mod_dir,
}
.collect(&[*mod_item]);
.collect(&[*mod_item], directive.container);
true
} else {
false
@ -1053,7 +1054,12 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
&mut |_err| (),
);
if let Ok(Ok(call_id)) = call_id {
resolved.push((directive.module_id, call_id, directive.depth));
resolved.push((
directive.module_id,
call_id,
directive.depth,
directive.container,
));
res = ReachedFixedPoint::No;
return false;
}
@ -1073,7 +1079,12 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
*derive_attr,
);
resolved.push((directive.module_id, call_id, directive.depth));
resolved.push((
directive.module_id,
call_id,
directive.depth,
directive.container,
));
res = ReachedFixedPoint::No;
return false;
}
@ -1096,7 +1107,7 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
item_tree: &item_tree,
mod_dir,
}
.collect(&[*mod_item]);
.collect(&[*mod_item], directive.container);
res = ReachedFixedPoint::No;
false
};
@ -1144,6 +1155,7 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
ast_id,
derive_attr: attr.id,
},
container: directive.container,
});
}
}
@ -1199,7 +1211,12 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
.scope
.add_attr_macro_invoc(ast_id, call_id);
resolved.push((directive.module_id, call_id, directive.depth));
resolved.push((
directive.module_id,
call_id,
directive.depth,
directive.container,
));
res = ReachedFixedPoint::No;
return false;
}
@ -1213,8 +1230,8 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
// Attribute resolution can add unresolved macro invocations, so concatenate the lists.
self.unresolved_macros.extend(macros);
for (module_id, macro_call_id, depth) in resolved {
self.collect_macro_expansion(module_id, macro_call_id, depth);
for (module_id, macro_call_id, depth, container) in resolved {
self.collect_macro_expansion(module_id, macro_call_id, depth, container);
}
res
@ -1225,6 +1242,7 @@ fn collect_macro_expansion(
module_id: LocalModuleId,
macro_call_id: MacroCallId,
depth: usize,
container: ItemContainerId,
) {
if EXPANSION_DEPTH_LIMIT.check(depth).is_err() {
cov_mark::hit!(macro_expansion_overflow);
@ -1276,7 +1294,7 @@ fn collect_macro_expansion(
item_tree: &item_tree,
mod_dir,
}
.collect(item_tree.top_level_items());
.collect(item_tree.top_level_items(), container);
}
fn finish(mut self) -> DefMap {
@ -1372,7 +1390,12 @@ struct ModCollector<'a, 'b> {
}
impl ModCollector<'_, '_> {
fn collect(&mut self, items: &[ModItem]) {
fn collect_in_top_module(&mut self, items: &[ModItem]) {
let module = self.def_collector.def_map.module_id(self.module_id);
self.collect(items, module.into())
}
fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
struct DefData<'a> {
id: ModuleDefId,
name: &'a Name,
@ -1423,7 +1446,7 @@ struct DefData<'a> {
}
}
if let Err(()) = self.resolve_attributes(&attrs, item) {
if let Err(()) = self.resolve_attributes(&attrs, item, container) {
// Do not process the item. It has at least one non-builtin attribute, so the
// fixed-point algorithm is required to resolve the rest of them.
continue;
@ -1462,8 +1485,17 @@ struct DefData<'a> {
status: PartialResolvedImport::Unresolved,
})
}
ModItem::ExternBlock(block) => self.collect(&self.item_tree[block].children),
ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
ModItem::ExternBlock(block) => self.collect(
&self.item_tree[block].children,
ItemContainerId::ExternBlockId(
ExternBlockLoc {
container: module,
id: ItemTreeId::new(self.tree_id, block),
}
.intern(self.def_collector.db),
),
),
ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container),
ModItem::MacroRules(id) => self.collect_macro_rules(id),
ModItem::MacroDef(id) => self.collect_macro_def(id),
ModItem::Impl(imp) => {
@ -1480,12 +1512,9 @@ struct DefData<'a> {
self.collect_proc_macro_def(&func.name, ast_id, &attrs);
def = Some(DefData {
id: FunctionLoc {
container: module.into(),
id: ItemTreeId::new(self.tree_id, id),
}
.intern(self.def_collector.db)
.into(),
id: FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }
.intern(self.def_collector.db)
.into(),
name: &func.name,
visibility: &self.item_tree[func.visibility],
has_constructor: false,
@ -1529,11 +1558,8 @@ struct DefData<'a> {
}
ModItem::Const(id) => {
let it = &self.item_tree[id];
let const_id = ConstLoc {
container: module.into(),
id: ItemTreeId::new(self.tree_id, id),
}
.intern(self.def_collector.db);
let const_id = ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }
.intern(self.def_collector.db);
match &it.name {
Some(name) => {
@ -1556,7 +1582,7 @@ struct DefData<'a> {
let it = &self.item_tree[id];
def = Some(DefData {
id: StaticLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
id: StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
.intern(self.def_collector.db)
.into(),
name: &it.name,
@ -1580,12 +1606,9 @@ struct DefData<'a> {
let it = &self.item_tree[id];
def = Some(DefData {
id: TypeAliasLoc {
container: module.into(),
id: ItemTreeId::new(self.tree_id, id),
}
.intern(self.def_collector.db)
.into(),
id: TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
.intern(self.def_collector.db)
.into(),
name: &it.name,
visibility: &self.item_tree[it.visibility],
has_constructor: false,
@ -1633,7 +1656,7 @@ fn collect_module(&mut self, module: &Mod, attrs: &Attrs) {
item_tree: self.item_tree,
mod_dir,
}
.collect(&*items);
.collect_in_top_module(&*items);
if is_macro_use {
self.import_all_legacy_macros(module_id);
}
@ -1666,7 +1689,7 @@ fn collect_module(&mut self, module: &Mod, attrs: &Attrs) {
item_tree: &item_tree,
mod_dir,
}
.collect(item_tree.top_level_items());
.collect_in_top_module(item_tree.top_level_items());
let is_macro_use = is_macro_use
|| item_tree
.top_level_attrs(db, self.def_collector.def_map.krate)
@ -1734,7 +1757,12 @@ fn push_child_module(
///
/// If `ignore_up_to` is `Some`, attributes preceding and including that attribute will be
/// assumed to be resolved already.
fn resolve_attributes(&mut self, attrs: &Attrs, mod_item: ModItem) -> Result<(), ()> {
fn resolve_attributes(
&mut self,
attrs: &Attrs,
mod_item: ModItem,
container: ItemContainerId,
) -> Result<(), ()> {
let mut ignore_up_to =
self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied();
let iter = attrs
@ -1777,6 +1805,7 @@ fn resolve_attributes(&mut self, attrs: &Attrs, mod_item: ModItem) -> Result<(),
mod_item,
tree: self.tree_id,
},
container,
});
return Err(());
@ -1951,7 +1980,7 @@ fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>) {
);
}
fn collect_macro_call(&mut self, mac: &MacroCall) {
fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) {
let ast_id = AstIdWithPath::new(self.file_id(), mac.ast_id, ModPath::clone(&mac.path));
// Case 1: try to resolve in legacy scope and expand macro_rules
@ -1981,6 +2010,7 @@ fn collect_macro_call(&mut self, mac: &MacroCall) {
self.module_id,
macro_call_id,
self.macro_depth + 1,
container,
);
if let Some(err) = error {
@ -2011,6 +2041,7 @@ fn collect_macro_call(&mut self, mac: &MacroCall) {
module_id: self.module_id,
depth: self.macro_depth + 1,
kind: MacroDirectiveKind::FnLike { ast_id, expand_to: mac.expand_to },
container,
});
}

View File

@ -22,8 +22,8 @@
path::{ModPath, PathKind},
per_ns::PerNs,
visibility::{RawVisibility, Visibility},
AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId,
EnumVariantId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, LifetimeParamId,
AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
TypeParamId, VariantId,
};
@ -802,6 +802,13 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
}
}
impl HasResolver for ExternBlockId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
// Same as parent's
self.lookup(db).container.resolver(db)
}
}
impl HasResolver for DefWithBodyId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
match self {
@ -812,12 +819,13 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
}
}
impl HasResolver for AssocContainerId {
impl HasResolver for ItemContainerId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
match self {
AssocContainerId::ModuleId(it) => it.resolver(db),
AssocContainerId::TraitId(it) => it.resolver(db),
AssocContainerId::ImplId(it) => it.resolver(db),
ItemContainerId::ModuleId(it) => it.resolver(db),
ItemContainerId::TraitId(it) => it.resolver(db),
ItemContainerId::ImplId(it) => it.resolver(db),
ItemContainerId::ExternBlockId(it) => it.resolver(db),
}
}
}

View File

@ -11,7 +11,7 @@
use base_db::CrateId;
use hir_def::{
lang_item::{lang_attr, LangItemTarget},
AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, ModuleId, TypeAliasId,
AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
};
use hir_expand::name::name;
@ -396,7 +396,7 @@ pub(crate) fn associated_ty_data_query(
debug!("associated_ty_data {:?}", id);
let type_alias: TypeAliasId = from_assoc_type_id(id);
let trait_ = match type_alias.lookup(db.upcast()).container {
AssocContainerId::TraitId(t) => t,
ItemContainerId::TraitId(t) => t,
_ => panic!("associated type not in trait"),
};
@ -634,7 +634,7 @@ fn type_alias_associated_ty_value(
) -> Arc<AssociatedTyValue> {
let type_alias_data = db.type_alias_data(type_alias);
let impl_id = match type_alias.lookup(db.upcast()).container {
AssocContainerId::ImplId(it) => it,
ItemContainerId::ImplId(it) => it,
_ => panic!("assoc ty value should be in impl"),
};

View File

@ -4,7 +4,7 @@
use hir_def::{
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint},
type_ref::Rawness,
AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup, TraitId,
FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
};
use crate::{
@ -268,7 +268,7 @@ fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>
match self.kind(&Interner) {
TyKind::AssociatedType(id, ..) => {
match from_assoc_type_id(*id).lookup(db.upcast()).container {
AssocContainerId::TraitId(trait_id) => Some(trait_id),
ItemContainerId::TraitId(trait_id) => Some(trait_id),
_ => None,
}
}
@ -277,7 +277,7 @@ fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>
.lookup(db.upcast())
.container
{
AssocContainerId::TraitId(trait_id) => Some(trait_id),
ItemContainerId::TraitId(trait_id) => Some(trait_id),
_ => None,
}
}
@ -331,7 +331,7 @@ fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container {
AssocContainerId::TraitId(it) => it,
ItemContainerId::TraitId(it) => it,
_ => panic!("projection ty without parent trait"),
}
}

View File

@ -178,6 +178,7 @@ fn allowed(&self, id: AttrDefId, allow_name: &str, recursing: bool) -> bool {
AttrDefId::ConstId(cid) => Some(cid.lookup(self.db.upcast()).container.into()),
AttrDefId::TraitId(tid) => Some(tid.lookup(self.db.upcast()).container.into()),
AttrDefId::ImplId(iid) => Some(iid.lookup(self.db.upcast()).container.into()),
AttrDefId::ExternBlockId(id) => Some(id.lookup(self.db.upcast()).container.into()),
// These warnings should not explore macro definitions at all
AttrDefId::MacroDefId(_) => None,
// Will never occur under an enum/struct/union/type alias

View File

@ -16,7 +16,7 @@
path::{Path, PathKind},
type_ref::{TraitBoundModifier, TypeBound, TypeRef},
visibility::Visibility,
AssocContainerId, HasModule, Lookup, ModuleId, TraitId,
HasModule, ItemContainerId, Lookup, ModuleId, TraitId,
};
use hir_expand::{hygiene::Hygiene, name::Name};
use itertools::Itertools;
@ -576,7 +576,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
TyKind::AssociatedType(assoc_type_id, parameters) => {
let type_alias = from_assoc_type_id(*assoc_type_id);
let trait_ = match type_alias.lookup(f.db.upcast()).container {
AssocContainerId::TraitId(it) => it,
ItemContainerId::TraitId(it) => it,
_ => panic!("not an associated type"),
};
let trait_ = f.db.trait_data(trait_);

View File

@ -521,7 +521,7 @@ fn resolve_associated_type_with_params(
match assoc_ty {
Some(res_assoc_ty) => {
let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container {
hir_def::AssocContainerId::TraitId(trait_) => trait_,
hir_def::ItemContainerId::TraitId(trait_) => trait_,
_ => panic!("resolve_associated_type called with non-associated type"),
};
let ty = self.table.new_type_var();

View File

@ -14,7 +14,7 @@
},
path::{GenericArg, GenericArgs},
resolver::resolver_for_expr,
AssocContainerId, FieldId, FunctionId, Lookup,
FieldId, FunctionId, ItemContainerId, Lookup,
};
use hir_expand::name::{name, Name};
use stdx::always;
@ -1167,8 +1167,7 @@ fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
// add obligation for trait implementation, if this is a trait method
match def {
CallableDefId::FunctionId(f) => {
if let AssocContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container
{
if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
// construct a TraitRef
let substs = crate::subst_prefix(
&*parameters,

View File

@ -6,7 +6,7 @@
use hir_def::{
path::{Path, PathSegment},
resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs},
AdtId, AssocContainerId, AssocItemId, EnumVariantId, Lookup,
AdtId, AssocItemId, EnumVariantId, ItemContainerId, Lookup,
};
use hir_expand::name::Name;
@ -241,7 +241,7 @@ fn resolve_ty_assoc_item(
AssocItemId::TypeAliasId(_) => unreachable!(),
};
let substs = match container {
AssocContainerId::ImplId(impl_id) => {
ItemContainerId::ImplId(impl_id) => {
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
.fill(iter::repeat_with(|| self.table.new_type_var()))
.build();
@ -250,7 +250,7 @@ fn resolve_ty_assoc_item(
self.unify(&impl_self_ty, &ty);
Some(impl_substs)
}
AssocContainerId::TraitId(trait_) => {
ItemContainerId::TraitId(trait_) => {
// we're picking this method
let trait_ref = TyBuilder::trait_ref(self.db, trait_)
.push(ty.clone())
@ -259,7 +259,7 @@ fn resolve_ty_assoc_item(
self.push_obligation(trait_ref.clone().cast(&Interner));
Some(trait_ref.substitution)
}
AssocContainerId::ModuleId(_) => None,
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
};
self.write_assoc_resolution(id, item);

View File

@ -19,8 +19,8 @@
path::{GenericArg, Path, PathSegment, PathSegments},
resolver::{HasResolver, Resolver, TypeNs},
type_ref::{TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
TypeAliasId, TypeParamId, UnionId, VariantId,
};
use hir_expand::{name::Name, ExpandResult};
@ -1125,7 +1125,7 @@ pub(crate) fn trait_environment_query(
}
}
let container: Option<AssocContainerId> = match def {
let container: Option<ItemContainerId> = match def {
// FIXME: is there a function for this?
GenericDefId::FunctionId(f) => Some(f.lookup(db.upcast()).container),
GenericDefId::AdtId(_) => None,
@ -1135,7 +1135,7 @@ pub(crate) fn trait_environment_query(
GenericDefId::EnumVariantId(_) => None,
GenericDefId::ConstId(c) => Some(c.lookup(db.upcast()).container),
};
if let Some(AssocContainerId::TraitId(trait_id)) = container {
if let Some(ItemContainerId::TraitId(trait_id)) = container {
// add `Self: Trait<T1, T2, ...>` to the environment in trait
// function default implementations (and speculative code
// inside consts or type aliases)

View File

@ -8,8 +8,8 @@
use base_db::{CrateId, Edition};
use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
use hir_def::{
lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, BlockId, FunctionId,
GenericDefId, HasModule, ImplId, Lookup, ModuleId, TraitId,
lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId, FunctionId, GenericDefId,
HasModule, ImplId, ItemContainerId, Lookup, ModuleId, TraitId,
};
use hir_expand::name::Name;
use rustc_hash::{FxHashMap, FxHashSet};
@ -979,18 +979,19 @@ fn transform_receiver_ty(
self_ty: &Canonical<Ty>,
) -> Option<Ty> {
let substs = match function_id.lookup(db.upcast()).container {
AssocContainerId::TraitId(_) => TyBuilder::subst_for_def(db, function_id)
ItemContainerId::TraitId(_) => TyBuilder::subst_for_def(db, function_id)
.push(self_ty.value.clone())
.fill_with_unknown()
.build(),
AssocContainerId::ImplId(impl_id) => {
ItemContainerId::ImplId(impl_id) => {
let impl_substs = inherent_impl_substs(db, env, impl_id, self_ty)?;
TyBuilder::subst_for_def(db, function_id)
.use_parent_substs(&impl_substs)
.fill_with_unknown()
.build()
}
AssocContainerId::ModuleId(_) => unreachable!(),
// No receiver
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => unreachable!(),
};
let sig = db.callable_item_signature(function_id.into());
Some(sig.map(|s| s.params()[0].clone()).substitute(&Interner, &substs))

View File

@ -7,7 +7,7 @@
chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk,
CallableDefId, Interner,
};
use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId};
use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId};
pub(crate) use unsafe_tls::{set_current_program, with_current_program};
@ -45,7 +45,7 @@ pub(crate) fn debug_assoc_type_id(
let type_alias: TypeAliasId = from_assoc_type_id(id);
let type_alias_data = self.0.type_alias_data(type_alias);
let trait_ = match type_alias.lookup(self.0.upcast()).container {
AssocContainerId::TraitId(t) => t,
ItemContainerId::TraitId(t) => t,
_ => panic!("associated type not in trait"),
};
let trait_data = self.0.trait_data(trait_);
@ -60,7 +60,7 @@ pub(crate) fn debug_projection_ty(
let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
let type_alias_data = self.0.type_alias_data(type_alias);
let trait_ = match type_alias.lookup(self.0.upcast()).container {
AssocContainerId::TraitId(t) => t,
ItemContainerId::TraitId(t) => t,
_ => panic!("associated type not in trait"),
};
let trait_data = self.0.trait_data(trait_);

View File

@ -14,7 +14,7 @@
path::Path,
resolver::{HasResolver, TypeNs},
type_ref::{TraitBoundModifier, TypeRef},
AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId,
GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeParamId,
};
use hir_expand::name::{name, Name};
use rustc_hash::FxHashSet;
@ -296,8 +296,8 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<Generic
};
match container {
AssocContainerId::ImplId(it) => Some(it.into()),
AssocContainerId::TraitId(it) => Some(it.into()),
AssocContainerId::ModuleId(_) => None,
ItemContainerId::ImplId(it) => Some(it.into()),
ItemContainerId::TraitId(it) => Some(it.into()),
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
}
}

View File

@ -36,8 +36,8 @@
use fst::{self, Streamer};
use hir::{
db::{DefDatabase, HirDatabase},
AdtId, AssocContainerId, AssocItemId, AssocItemLoc, DefHasSource, DefWithBodyId, HasSource,
HirFileId, ImplId, InFile, ItemLoc, ItemTreeNode, Lookup, MacroDef, Module, ModuleDefId,
AdtId, AssocItemId, AssocItemLoc, DefHasSource, DefWithBodyId, HasSource, HirFileId, ImplId,
InFile, ItemContainerId, ItemLoc, ItemTreeNode, Lookup, MacroDef, Module, ModuleDefId,
ModuleId, Semantics, TraitId,
};
use rayon::prelude::*;
@ -508,7 +508,7 @@ fn collect_from_module(&mut self, module_id: ModuleId) {
self.collect_from_body(id);
}
ModuleDefId::StaticId(id) => {
self.push_decl(id, FileSymbolKind::Static);
self.push_decl_assoc(id, FileSymbolKind::Static);
self.collect_from_body(id);
}
ModuleDefId::TraitId(id) => {
@ -610,17 +610,17 @@ fn push_decl_assoc<L, T>(&mut self, id: L, kind: FileSymbolKind)
T: ItemTreeNode,
<T as ItemTreeNode>::Source: HasName,
{
fn container_name(db: &dyn HirDatabase, container: AssocContainerId) -> Option<SmolStr> {
fn container_name(db: &dyn HirDatabase, container: ItemContainerId) -> Option<SmolStr> {
match container {
AssocContainerId::ModuleId(module_id) => {
ItemContainerId::ModuleId(module_id) => {
let module = Module::from(module_id);
module.name(db).and_then(|name| name.as_text())
}
AssocContainerId::TraitId(trait_id) => {
ItemContainerId::TraitId(trait_id) => {
let trait_data = db.trait_data(trait_id);
trait_data.name.as_text()
}
AssocContainerId::ImplId(_) => None,
ItemContainerId::ImplId(_) | ItemContainerId::ExternBlockId(_) => None,
}
}

View File

@ -397,6 +397,24 @@ fn ignores_extern_items() {
);
}
#[test]
fn ignores_extern_items_from_macro() {
check_diagnostics(
r#"
macro_rules! m {
() => {
fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
pub static SomeStatic: u8 = 10;
}
}
extern {
m!();
}
"#,
);
}
#[test]
fn bug_traits_arent_checked() {
// FIXME: Traits and functions in traits aren't currently checked by