2144: move struct & enum data to hir_def r=matklad a=matklad



Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2019-10-31 13:41:12 +00:00 committed by GitHub
commit 9421e5be35
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 214 additions and 201 deletions

View file

@ -3,152 +3,16 @@
use std::sync::Arc; use std::sync::Arc;
use hir_def::{type_ref::TypeRef, LocalEnumVariantId}; use hir_def::adt::VariantData;
use hir_expand::name::AsName;
use ra_arena::{impl_arena_id, Arena, RawId};
use ra_syntax::ast::{self, NameOwner, StructKind, TypeAscriptionOwner};
use crate::{ use crate::{
db::{AstDatabase, DefDatabase, HirDatabase}, db::{DefDatabase, HirDatabase},
Enum, EnumVariant, FieldSource, HasSource, Module, Name, Source, Struct, StructField, EnumVariant, Module, Name, Struct, StructField,
}; };
impl Struct { impl Struct {
pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
db.struct_data(self).variant_data.clone() db.struct_data(self.id).variant_data.clone()
}
}
/// Note that we use `StructData` for unions as well!
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructData {
pub(crate) name: Option<Name>,
pub(crate) variant_data: Arc<VariantData>,
}
impl StructData {
fn new(struct_def: &ast::StructDef) -> StructData {
let name = struct_def.name().map(|n| n.as_name());
let variant_data = VariantData::new(struct_def.kind());
let variant_data = Arc::new(variant_data);
StructData { name, variant_data }
}
pub(crate) fn struct_data_query(
db: &(impl DefDatabase + AstDatabase),
struct_: Struct,
) -> Arc<StructData> {
let src = struct_.source(db);
Arc::new(StructData::new(&src.ast))
}
}
fn variants(enum_def: &ast::EnumDef) -> impl Iterator<Item = ast::EnumVariant> {
enum_def.variant_list().into_iter().flat_map(|it| it.variants())
}
impl EnumVariant {
pub(crate) fn source_impl(
self,
db: &(impl DefDatabase + AstDatabase),
) -> Source<ast::EnumVariant> {
let src = self.parent.source(db);
let ast = variants(&src.ast)
.zip(db.enum_data(self.parent).variants.iter())
.find(|(_syntax, (id, _))| *id == self.id)
.unwrap()
.0;
Source { file_id: src.file_id, ast }
}
pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
db.enum_data(self.parent).variants[self.id].variant_data.clone()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumData {
pub(crate) name: Option<Name>,
pub(crate) variants: Arena<LocalEnumVariantId, EnumVariantData>,
}
impl EnumData {
pub(crate) fn enum_data_query(db: &(impl DefDatabase + AstDatabase), e: Enum) -> Arc<EnumData> {
let src = e.source(db);
let name = src.ast.name().map(|n| n.as_name());
let variants = variants(&src.ast)
.map(|var| EnumVariantData {
name: var.name().map(|it| it.as_name()),
variant_data: Arc::new(VariantData::new(var.kind())),
})
.collect();
Arc::new(EnumData { name, variants })
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct EnumVariantData {
pub(crate) name: Option<Name>,
variant_data: Arc<VariantData>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct StructFieldId(RawId);
impl_arena_id!(StructFieldId);
/// A single field of an enum variant or struct
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructFieldData {
pub(crate) name: Name,
pub(crate) type_ref: TypeRef,
}
/// Fields of an enum variant or struct
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct VariantData(VariantDataInner);
#[derive(Debug, Clone, PartialEq, Eq)]
enum VariantDataInner {
Struct(Arena<StructFieldId, StructFieldData>),
Tuple(Arena<StructFieldId, StructFieldData>),
Unit,
}
impl VariantData {
pub(crate) fn fields(&self) -> Option<&Arena<StructFieldId, StructFieldData>> {
match &self.0 {
VariantDataInner::Struct(fields) | VariantDataInner::Tuple(fields) => Some(fields),
_ => None,
}
}
}
impl VariantData {
fn new(flavor: StructKind) -> Self {
let inner = match flavor {
ast::StructKind::Tuple(fl) => {
let fields = fl
.fields()
.enumerate()
.map(|(i, fd)| StructFieldData {
name: Name::new_tuple_field(i),
type_ref: TypeRef::from_ast_opt(fd.type_ref()),
})
.collect();
VariantDataInner::Tuple(fields)
}
ast::StructKind::Named(fl) => {
let fields = fl
.fields()
.map(|fd| StructFieldData {
name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
})
.collect();
VariantDataInner::Struct(fields)
}
ast::StructKind::Unit => VariantDataInner::Unit,
};
VariantData(inner)
} }
} }
@ -188,35 +52,3 @@ impl VariantDef {
} }
} }
} }
impl StructField {
pub(crate) fn source_impl(&self, db: &(impl DefDatabase + AstDatabase)) -> Source<FieldSource> {
let var_data = self.parent.variant_data(db);
let fields = var_data.fields().unwrap();
let ss;
let es;
let (file_id, struct_kind) = match self.parent {
VariantDef::Struct(s) => {
ss = s.source(db);
(ss.file_id, ss.ast.kind())
}
VariantDef::EnumVariant(e) => {
es = e.source(db);
(es.file_id, es.ast.kind())
}
};
let field_sources = match struct_kind {
ast::StructKind::Tuple(fl) => fl.fields().map(|it| FieldSource::Pos(it)).collect(),
ast::StructKind::Named(fl) => fl.fields().map(|it| FieldSource::Named(it)).collect(),
ast::StructKind::Unit => Vec::new(),
};
let ast = field_sources
.into_iter()
.zip(fields.iter())
.find(|(_syntax, (id, _))| *id == self.id)
.unwrap()
.0;
Source { file_id, ast }
}
}

View file

@ -6,16 +6,17 @@ pub(crate) mod docs;
use std::sync::Arc; use std::sync::Arc;
use hir_def::{ use hir_def::{
adt::VariantData,
builtin_type::BuiltinType, builtin_type::BuiltinType,
type_ref::{Mutability, TypeRef}, type_ref::{Mutability, TypeRef},
CrateModuleId, LocalEnumVariantId, ModuleId, CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId,
}; };
use hir_expand::name::{self, AsName}; use hir_expand::name::{self, AsName};
use ra_db::{CrateId, Edition}; use ra_db::{CrateId, Edition};
use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
use crate::{ use crate::{
adt::{StructFieldId, VariantDef}, adt::VariantDef,
db::{AstDatabase, DefDatabase, HirDatabase}, db::{AstDatabase, DefDatabase, HirDatabase},
diagnostics::DiagnosticSink, diagnostics::DiagnosticSink,
expr::{validation::ExprValidator, Body, BodySourceMap}, expr::{validation::ExprValidator, Body, BodySourceMap},
@ -250,7 +251,7 @@ impl Module {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StructField { pub struct StructField {
pub(crate) parent: VariantDef, pub(crate) parent: VariantDef,
pub(crate) id: StructFieldId, pub(crate) id: LocalStructFieldId,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
@ -288,11 +289,11 @@ impl Struct {
} }
pub fn name(self, db: &impl DefDatabase) -> Option<Name> { pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
db.struct_data(self).name.clone() db.struct_data(self.id).name.clone()
} }
pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> { pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
db.struct_data(self) db.struct_data(self.id)
.variant_data .variant_data
.fields() .fields()
.into_iter() .into_iter()
@ -302,7 +303,7 @@ impl Struct {
} }
pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> { pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
db.struct_data(self) db.struct_data(self.id)
.variant_data .variant_data
.fields() .fields()
.into_iter() .into_iter()
@ -338,7 +339,7 @@ pub struct Union {
impl Union { impl Union {
pub fn name(self, db: &impl DefDatabase) -> Option<Name> { pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
db.struct_data(Struct { id: self.id }).name.clone() db.struct_data(self.id).name.clone()
} }
pub fn module(self, db: &impl HirDatabase) -> Module { pub fn module(self, db: &impl HirDatabase) -> Module {
@ -376,15 +377,19 @@ impl Enum {
} }
pub fn name(self, db: &impl DefDatabase) -> Option<Name> { pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
db.enum_data(self).name.clone() db.enum_data(self.id).name.clone()
} }
pub fn variants(self, db: &impl DefDatabase) -> Vec<EnumVariant> { pub fn variants(self, db: &impl DefDatabase) -> Vec<EnumVariant> {
db.enum_data(self).variants.iter().map(|(id, _)| EnumVariant { parent: self, id }).collect() db.enum_data(self.id)
.variants
.iter()
.map(|(id, _)| EnumVariant { parent: self, id })
.collect()
} }
pub fn variant(self, db: &impl DefDatabase, name: &Name) -> Option<EnumVariant> { pub fn variant(self, db: &impl DefDatabase, name: &Name) -> Option<EnumVariant> {
db.enum_data(self) db.enum_data(self.id)
.variants .variants
.iter() .iter()
.find(|(_id, data)| data.name.as_ref() == Some(name)) .find(|(_id, data)| data.name.as_ref() == Some(name))
@ -422,7 +427,7 @@ impl EnumVariant {
} }
pub fn name(self, db: &impl DefDatabase) -> Option<Name> { pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
db.enum_data(self.parent).variants[self.id].name.clone() db.enum_data(self.parent.id).variants[self.id].name.clone()
} }
pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> { pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
@ -442,6 +447,10 @@ impl EnumVariant {
.find(|(_id, data)| data.name == *name) .find(|(_id, data)| data.name == *name)
.map(|(id, _)| StructField { parent: self.into(), id }) .map(|(id, _)| StructField { parent: self.into(), id })
} }
pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
}
} }
/// A Data Type /// A Data Type

View file

@ -3,6 +3,7 @@
use ra_syntax::ast::{self, AstNode}; use ra_syntax::ast::{self, AstNode};
use crate::{ use crate::{
adt::VariantDef,
db::{AstDatabase, DefDatabase, HirDatabase}, db::{AstDatabase, DefDatabase, HirDatabase},
ids::AstItemDef, ids::AstItemDef,
Const, Either, Enum, EnumVariant, FieldSource, Function, HasBody, HirFileId, MacroDef, Module, Const, Either, Enum, EnumVariant, FieldSource, Function, HasBody, HirFileId, MacroDef, Module,
@ -45,7 +46,33 @@ impl Module {
impl HasSource for StructField { impl HasSource for StructField {
type Ast = FieldSource; type Ast = FieldSource;
fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<FieldSource> { fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<FieldSource> {
self.source_impl(db) let var_data = self.parent.variant_data(db);
let fields = var_data.fields().unwrap();
let ss;
let es;
let (file_id, struct_kind) = match self.parent {
VariantDef::Struct(s) => {
ss = s.source(db);
(ss.file_id, ss.ast.kind())
}
VariantDef::EnumVariant(e) => {
es = e.source(db);
(es.file_id, es.ast.kind())
}
};
let field_sources = match struct_kind {
ast::StructKind::Tuple(fl) => fl.fields().map(|it| FieldSource::Pos(it)).collect(),
ast::StructKind::Named(fl) => fl.fields().map(|it| FieldSource::Named(it)).collect(),
ast::StructKind::Unit => Vec::new(),
};
let ast = field_sources
.into_iter()
.zip(fields.iter())
.find(|(_syntax, (id, _))| *id == self.id)
.unwrap()
.0;
Source { file_id, ast }
} }
} }
impl HasSource for Struct { impl HasSource for Struct {
@ -69,7 +96,18 @@ impl HasSource for Enum {
impl HasSource for EnumVariant { impl HasSource for EnumVariant {
type Ast = ast::EnumVariant; type Ast = ast::EnumVariant;
fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::EnumVariant> { fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::EnumVariant> {
self.source_impl(db) let enum_data = db.enum_data(self.parent.id);
let src = self.parent.id.source(db);
let ast = src
.ast
.variant_list()
.into_iter()
.flat_map(|it| it.variants())
.zip(enum_data.variants.iter())
.find(|(_syntax, (id, _))| *id == self.id)
.unwrap()
.0;
Source { file_id: src.file_id, ast }
} }
} }
impl HasSource for Function { impl HasSource for Function {

View file

@ -6,7 +6,6 @@ use ra_db::salsa;
use ra_syntax::SmolStr; use ra_syntax::SmolStr;
use crate::{ use crate::{
adt::{EnumData, StructData},
debug::HirDebugDatabase, debug::HirDebugDatabase,
generics::{GenericDef, GenericParams}, generics::{GenericDef, GenericParams},
ids, ids,
@ -19,13 +18,13 @@ use crate::{
InferenceResult, Substs, Ty, TypableDef, TypeCtor, InferenceResult, Substs, Ty, TypableDef, TypeCtor,
}, },
type_alias::TypeAliasData, type_alias::TypeAliasData,
Const, ConstData, Crate, DefWithBody, Enum, ExprScopes, FnData, Function, Module, Static, Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Static,
Struct, StructField, Trait, TypeAlias, StructField, Trait, TypeAlias,
}; };
pub use hir_def::db::{ pub use hir_def::db::{
DefDatabase2, DefDatabase2Storage, InternDatabase, InternDatabaseStorage, RawItemsQuery, DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase, InternDatabaseStorage,
RawItemsWithSourceMapQuery, RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery,
}; };
pub use hir_expand::db::{ pub use hir_expand::db::{
AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
@ -36,12 +35,6 @@ pub use hir_expand::db::{
#[salsa::query_group(DefDatabaseStorage)] #[salsa::query_group(DefDatabaseStorage)]
#[salsa::requires(AstDatabase)] #[salsa::requires(AstDatabase)]
pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
#[salsa::invoke(crate::adt::StructData::struct_data_query)]
fn struct_data(&self, s: Struct) -> Arc<StructData>;
#[salsa::invoke(crate::adt::EnumData::enum_data_query)]
fn enum_data(&self, e: Enum) -> Arc<EnumData>;
#[salsa::invoke(crate::traits::TraitData::trait_data_query)] #[salsa::invoke(crate::traits::TraitData::trait_data_query)]
fn trait_data(&self, t: Trait) -> Arc<TraitData>; fn trait_data(&self, t: Trait) -> Arc<TraitData>;

View file

@ -655,8 +655,8 @@ fn type_for_builtin(def: BuiltinType) -> Ty {
} }
fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig { fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
let var_data = def.variant_data(db); let struct_data = db.struct_data(def.id);
let fields = match var_data.fields() { let fields = match struct_data.variant_data.fields() {
Some(fields) => fields, Some(fields) => fields,
None => panic!("fn_sig_for_struct_constructor called on unit struct"), None => panic!("fn_sig_for_struct_constructor called on unit struct"),
}; };
@ -671,8 +671,8 @@ fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
/// Build the type of a tuple struct constructor. /// Build the type of a tuple struct constructor.
fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
let var_data = def.variant_data(db); let struct_data = db.struct_data(def.id);
if var_data.fields().is_none() { if struct_data.variant_data.fields().is_none() {
return type_for_adt(db, def); // Unit struct return type_for_adt(db, def); // Unit struct
} }
let generics = def.generic_params(db); let generics = def.generic_params(db);

View file

@ -0,0 +1,114 @@
//! Defines hir-level representation of structs, enums and unions
use std::sync::Arc;
use hir_expand::name::{AsName, Name};
use ra_arena::Arena;
use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
use crate::{
db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId,
LocalStructFieldId, StructId,
};
/// Note that we use `StructData` for unions as well!
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructData {
pub name: Option<Name>,
pub variant_data: Arc<VariantData>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumData {
pub name: Option<Name>,
pub variants: Arena<LocalEnumVariantId, EnumVariantData>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumVariantData {
pub name: Option<Name>,
pub variant_data: Arc<VariantData>,
}
/// Fields of an enum variant or struct
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VariantData(VariantDataInner);
#[derive(Debug, Clone, PartialEq, Eq)]
enum VariantDataInner {
Struct(Arena<LocalStructFieldId, StructFieldData>),
Tuple(Arena<LocalStructFieldId, StructFieldData>),
Unit,
}
/// A single field of an enum variant or struct
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructFieldData {
pub name: Name,
pub type_ref: TypeRef,
}
impl StructData {
pub(crate) fn struct_data_query(db: &impl DefDatabase2, struct_: StructId) -> Arc<StructData> {
let src = struct_.source(db);
let name = src.ast.name().map(|n| n.as_name());
let variant_data = VariantData::new(src.ast.kind());
let variant_data = Arc::new(variant_data);
Arc::new(StructData { name, variant_data })
}
}
impl EnumData {
pub(crate) fn enum_data_query(db: &impl DefDatabase2, e: EnumId) -> Arc<EnumData> {
let src = e.source(db);
let name = src.ast.name().map(|n| n.as_name());
let variants = src
.ast
.variant_list()
.into_iter()
.flat_map(|it| it.variants())
.map(|var| EnumVariantData {
name: var.name().map(|it| it.as_name()),
variant_data: Arc::new(VariantData::new(var.kind())),
})
.collect();
Arc::new(EnumData { name, variants })
}
}
impl VariantData {
fn new(flavor: ast::StructKind) -> Self {
let inner = match flavor {
ast::StructKind::Tuple(fl) => {
let fields = fl
.fields()
.enumerate()
.map(|(i, fd)| StructFieldData {
name: Name::new_tuple_field(i),
type_ref: TypeRef::from_ast_opt(fd.type_ref()),
})
.collect();
VariantDataInner::Tuple(fields)
}
ast::StructKind::Named(fl) => {
let fields = fl
.fields()
.map(|fd| StructFieldData {
name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
})
.collect();
VariantDataInner::Struct(fields)
}
ast::StructKind::Unit => VariantDataInner::Unit,
};
VariantData(inner)
}
pub fn fields(&self) -> Option<&Arena<LocalStructFieldId, StructFieldData>> {
match &self.0 {
VariantDataInner::Struct(fields) | VariantDataInner::Tuple(fields) => Some(fields),
_ => None,
}
}
}

View file

@ -5,7 +5,11 @@ use hir_expand::{db::AstDatabase, HirFileId};
use ra_db::{salsa, SourceDatabase}; use ra_db::{salsa, SourceDatabase};
use ra_syntax::ast; use ra_syntax::ast;
use crate::nameres::raw::{ImportSourceMap, RawItems}; use crate::{
adt::{EnumData, StructData},
nameres::raw::{ImportSourceMap, RawItems},
EnumId, StructId,
};
#[salsa::query_group(InternDatabaseStorage)] #[salsa::query_group(InternDatabaseStorage)]
pub trait InternDatabase: SourceDatabase { pub trait InternDatabase: SourceDatabase {
@ -37,4 +41,10 @@ pub trait DefDatabase2: InternDatabase + AstDatabase {
#[salsa::invoke(RawItems::raw_items_query)] #[salsa::invoke(RawItems::raw_items_query)]
fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;
#[salsa::invoke(StructData::struct_data_query)]
fn struct_data(&self, s: StructId) -> Arc<StructData>;
#[salsa::invoke(EnumData::enum_data_query)]
fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
} }

View file

@ -12,6 +12,7 @@ pub mod attr;
pub mod path; pub mod path;
pub mod type_ref; pub mod type_ref;
pub mod builtin_type; pub mod builtin_type;
pub mod adt;
// FIXME: this should be private // FIXME: this should be private
pub mod nameres; pub mod nameres;
@ -259,6 +260,22 @@ pub struct EnumVariantId {
pub struct LocalEnumVariantId(RawId); pub struct LocalEnumVariantId(RawId);
impl_arena_id!(LocalEnumVariantId); impl_arena_id!(LocalEnumVariantId);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum VariantId {
EnumVariantId(EnumVariantId),
StructId(StructId),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StructFieldId {
parent: VariantId,
local_id: LocalStructFieldId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LocalStructFieldId(RawId);
impl_arena_id!(LocalStructFieldId);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ConstId(salsa::InternId); pub struct ConstId(salsa::InternId);
impl_intern_key!(ConstId); impl_intern_key!(ConstId);