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

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