From 56710f119b7114efac237ac36ea21730b8bd5311 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 12 Dec 2019 15:11:57 +0100 Subject: Move enum&union to new loc --- crates/ra_hir/src/code_model.rs | 10 +++--- crates/ra_hir/src/from_source.rs | 29 ++++++----------- crates/ra_hir/src/has_source.rs | 6 ++-- crates/ra_hir_def/src/adt.rs | 13 ++++---- crates/ra_hir_def/src/attr.rs | 7 ++--- crates/ra_hir_def/src/child_by_source.rs | 10 ++++-- crates/ra_hir_def/src/db.rs | 12 +++---- crates/ra_hir_def/src/docs.rs | 6 ++-- crates/ra_hir_def/src/generics.rs | 6 ++-- crates/ra_hir_def/src/keys.rs | 4 ++- crates/ra_hir_def/src/lib.rs | 50 ++++++++++++++++++++++-------- crates/ra_hir_def/src/nameres/collector.rs | 19 +++++++----- crates/ra_hir_def/src/src.rs | 21 ++++++++++++- crates/ra_hir_ty/src/lower.rs | 9 +++--- 14 files changed, 123 insertions(+), 79 deletions(-) diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 8588aa5a3..c705d1630 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -11,7 +11,7 @@ use hir_def::{ per_ns::PerNs, resolver::HasResolver, type_ref::{Mutability, TypeRef}, - AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, HasModule, ImplId, + AdtId, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, }; @@ -309,11 +309,11 @@ impl Union { } pub fn module(self, db: &impl DefDatabase) -> Module { - Module { id: self.id.module(db) } + Module { id: self.id.lookup(db).container } } pub fn ty(self, db: &impl HirDatabase) -> Type { - Type::from_def(db, self.id.module(db).krate, self.id) + Type::from_def(db, self.id.lookup(db).container.krate, self.id) } pub fn fields(self, db: &impl HirDatabase) -> Vec { @@ -337,7 +337,7 @@ pub struct Enum { impl Enum { pub fn module(self, db: &impl DefDatabase) -> Module { - Module { id: self.id.module(db) } + Module { id: self.id.lookup(db).container } } pub fn krate(self, db: &impl DefDatabase) -> Option { @@ -357,7 +357,7 @@ impl Enum { } pub fn ty(self, db: &impl HirDatabase) -> Type { - Type::from_def(db, self.id.module(db).krate, self.id) + Type::from_def(db, self.id.lookup(db).container.krate, self.id) } } diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 978326c74..f7411c5cf 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -1,7 +1,7 @@ //! FIXME: write short doc here use hir_def::{ - child_by_source::ChildBySource, dyn_map::DynMap, keys, nameres::ModuleSource, AstItemDef, - EnumVariantId, GenericDefId, LocationCtx, ModuleId, VariantId, + child_by_source::ChildBySource, dyn_map::DynMap, keys, nameres::ModuleSource, EnumVariantId, + GenericDefId, ModuleId, VariantId, }; use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; use ra_syntax::{ @@ -32,15 +32,19 @@ impl FromSource for Struct { impl FromSource for Union { type Ast = ast::UnionDef; fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile) -> Option { - let id = from_source(db, src)?; - Some(Union { id }) + analyze_container(db, src.as_ref().map(|it| it.syntax()))[keys::UNION] + .get(&src) + .copied() + .map(Union::from) } } impl FromSource for Enum { type Ast = ast::EnumDef; fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile) -> Option { - let id = from_source(db, src)?; - Some(Enum { id }) + analyze_container(db, src.as_ref().map(|it| it.syntax()))[keys::ENUM] + .get(&src) + .copied() + .map(Enum::from) } } impl FromSource for Trait { @@ -250,19 +254,6 @@ impl Module { } } -fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile) -> Option -where - N: AstNode, - DEF: AstItemDef, -{ - let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); - let module = Module::from_definition(db, InFile::new(src.file_id, module_src))?; - let ctx = LocationCtx::new(db, module.id, src.file_id); - let items = db.ast_id_map(src.file_id); - let item_id = items.ast_id(&src.value); - Some(DEF::from_ast_id(ctx, item_id)) -} - fn analyze_container(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> DynMap { _analyze_container(db, src).unwrap_or_default() } diff --git a/crates/ra_hir/src/has_source.rs b/crates/ra_hir/src/has_source.rs index 8f35a3fbb..72afecf26 100644 --- a/crates/ra_hir/src/has_source.rs +++ b/crates/ra_hir/src/has_source.rs @@ -4,7 +4,7 @@ use either::Either; use hir_def::{ nameres::ModuleSource, src::{HasChildSource, HasSource as _}, - AstItemDef, Lookup, VariantId, + Lookup, VariantId, }; use ra_syntax::ast; @@ -57,13 +57,13 @@ impl HasSource for Struct { impl HasSource for Union { type Ast = ast::UnionDef; fn source(self, db: &impl DefDatabase) -> InFile { - self.id.source(db) + self.id.lookup(db).source(db) } } impl HasSource for Enum { type Ast = ast::EnumDef; fn source(self, db: &impl DefDatabase) -> InFile { - self.id.source(db) + self.id.lookup(db).source(db) } } impl HasSource for EnumVariant { diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index ef2b20f1e..ec3d57d1a 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs @@ -11,9 +11,8 @@ use ra_arena::{map::ArenaMap, Arena}; use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; use crate::{ - db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, type_ref::TypeRef, - AstItemDef, EnumId, LocalEnumVariantId, LocalStructFieldId, Lookup, StructId, UnionId, - VariantId, + db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, type_ref::TypeRef, EnumId, + LocalEnumVariantId, LocalStructFieldId, Lookup, StructId, UnionId, VariantId, }; /// Note that we use `StructData` for unions as well! @@ -58,7 +57,7 @@ impl StructData { Arc::new(StructData { name, variant_data }) } pub(crate) fn union_data_query(db: &impl DefDatabase, id: UnionId) -> Arc { - let src = id.source(db); + let src = id.lookup(db).source(db); let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); let variant_data = VariantData::new( src.value @@ -73,7 +72,7 @@ impl StructData { impl EnumData { pub(crate) fn enum_data_query(db: &impl DefDatabase, e: EnumId) -> Arc { - let src = e.source(db); + let src = e.lookup(db).source(db); let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); let mut trace = Trace::new_for_arena(); lower_enum(&mut trace, &src.value); @@ -90,7 +89,7 @@ impl HasChildSource for EnumId { type ChildId = LocalEnumVariantId; type Value = ast::EnumVariant; fn child_source(&self, db: &impl DefDatabase) -> InFile> { - let src = self.source(db); + let src = self.lookup(db).source(db); let mut trace = Trace::new_for_map(); lower_enum(&mut trace, &src.value); src.with_value(trace.into_map()) @@ -155,7 +154,7 @@ impl HasChildSource for VariantId { src.map(|map| map[it.local_id].kind()) } VariantId::StructId(it) => it.lookup(db).source(db).map(|it| it.kind()), - VariantId::UnionId(it) => it.source(db).map(|it| { + VariantId::UnionId(it) => it.lookup(db).source(db).map(|it| { it.record_field_def_list() .map(ast::StructKind::Record) .unwrap_or(ast::StructKind::Unit) diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index d2aa5ce8f..5bf82e191 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs @@ -12,8 +12,7 @@ use ra_syntax::{ use tt::Subtree; use crate::{ - db::DefDatabase, path::Path, src::HasChildSource, src::HasSource, AdtId, AstItemDef, AttrDefId, - Lookup, + db::DefDatabase, path::Path, src::HasChildSource, src::HasSource, AdtId, AttrDefId, Lookup, }; #[derive(Default, Debug, Clone, PartialEq, Eq)] @@ -57,8 +56,8 @@ impl Attrs { } AttrDefId::AdtId(it) => match it { AdtId::StructId(it) => attrs_from_loc(it.lookup(db), db), - AdtId::EnumId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), - AdtId::UnionId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), + AdtId::EnumId(it) => attrs_from_loc(it.lookup(db), db), + AdtId::UnionId(it) => attrs_from_loc(it.lookup(db), db), }, AttrDefId::TraitId(it) => attrs_from_loc(it.lookup(db), db), AttrDefId::MacroDefId(it) => { diff --git a/crates/ra_hir_def/src/child_by_source.rs b/crates/ra_hir_def/src/child_by_source.rs index eba361578..3c9379b15 100644 --- a/crates/ra_hir_def/src/child_by_source.rs +++ b/crates/ra_hir_def/src/child_by_source.rs @@ -103,8 +103,14 @@ impl ChildBySource for ModuleId { let src = strukt.lookup(db).source(db); res[keys::STRUCT].insert(src, strukt) } - AdtId::UnionId(_) => (), - AdtId::EnumId(_) => (), + AdtId::UnionId(union_) => { + let src = union_.lookup(db).source(db); + res[keys::UNION].insert(src, union_) + } + AdtId::EnumId(enum_) => { + let src = enum_.lookup(db).source(db); + res[keys::ENUM].insert(src, enum_) + } }, _ => (), } diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index e120c7768..98bff6cb7 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use hir_expand::{db::AstDatabase, HirFileId}; use ra_db::{salsa, CrateId, SourceDatabase}; -use ra_syntax::{ast, SmolStr}; +use ra_syntax::SmolStr; use crate::{ adt::{EnumData, StructData}, @@ -17,9 +17,9 @@ use crate::{ raw::{ImportSourceMap, RawItems}, CrateDefMap, }, - AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, FunctionId, FunctionLoc, GenericDefId, - ImplId, ImplLoc, ItemLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, - TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, + AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, + GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, + TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, }; #[salsa::query_group(InternDatabaseStorage)] @@ -29,9 +29,9 @@ pub trait InternDatabase: SourceDatabase { #[salsa::interned] fn intern_struct(&self, loc: StructLoc) -> StructId; #[salsa::interned] - fn intern_union(&self, loc: ItemLoc) -> UnionId; + fn intern_union(&self, loc: UnionLoc) -> UnionId; #[salsa::interned] - fn intern_enum(&self, loc: ItemLoc) -> EnumId; + fn intern_enum(&self, loc: EnumLoc) -> EnumId; #[salsa::interned] fn intern_const(&self, loc: ConstLoc) -> ConstId; #[salsa::interned] diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs index 58143b894..b29f142e3 100644 --- a/crates/ra_hir_def/src/docs.rs +++ b/crates/ra_hir_def/src/docs.rs @@ -11,7 +11,7 @@ use ra_syntax::ast; use crate::{ db::DefDatabase, src::{HasChildSource, HasSource}, - AdtId, AstItemDef, AttrDefId, Lookup, + AdtId, AttrDefId, Lookup, }; /// Holds documentation @@ -52,8 +52,8 @@ impl Documentation { } AttrDefId::AdtId(it) => match it { AdtId::StructId(it) => docs_from_ast(&it.lookup(db).source(db).value), - AdtId::EnumId(it) => docs_from_ast(&it.source(db).value), - AdtId::UnionId(it) => docs_from_ast(&it.source(db).value), + AdtId::EnumId(it) => docs_from_ast(&it.lookup(db).source(db).value), + AdtId::UnionId(it) => docs_from_ast(&it.lookup(db).source(db).value), }, AttrDefId::EnumVariantId(it) => { let src = it.parent.child_source(db); diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index f1ce8d59a..e502dd798 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -21,7 +21,7 @@ use crate::{ src::HasChildSource, src::HasSource, type_ref::{TypeBound, TypeRef}, - AdtId, AstItemDef, GenericDefId, LocalTypeParamId, Lookup, TypeParamId, + AdtId, GenericDefId, LocalTypeParamId, Lookup, TypeParamId, }; /// Data about a generic parameter (to a function, struct, impl, ...). @@ -76,12 +76,12 @@ impl GenericParams { src.file_id } GenericDefId::AdtId(AdtId::UnionId(it)) => { - let src = it.source(db); + let src = it.lookup(db).source(db); generics.fill(&mut sm, &src.value); src.file_id } GenericDefId::AdtId(AdtId::EnumId(it)) => { - let src = it.source(db); + let src = it.lookup(db).source(db); generics.fill(&mut sm, &src.value); src.file_id } diff --git a/crates/ra_hir_def/src/keys.rs b/crates/ra_hir_def/src/keys.rs index 758cf8097..ada145379 100644 --- a/crates/ra_hir_def/src/keys.rs +++ b/crates/ra_hir_def/src/keys.rs @@ -9,7 +9,7 @@ use rustc_hash::FxHashMap; use crate::{ dyn_map::{DynMap, Policy}, ConstId, EnumVariantId, FunctionId, ImplId, StaticId, StructFieldId, StructId, TraitId, - TypeAliasId, TypeParamId, + TypeAliasId, TypeParamId, EnumId, UnionId, }; type Key = crate::dyn_map::Key, V, AstPtrPolicy>; @@ -21,6 +21,8 @@ pub const TYPE_ALIAS: Key = Key::new(); pub const IMPL: Key = Key::new(); pub const TRAIT: Key = Key::new(); pub const STRUCT: Key = Key::new(); +pub const UNION: Key = Key::new(); +pub const ENUM: Key = Key::new(); pub const ENUM_VARIANT: Key = Key::new(); pub const TUPLE_FIELD: Key = Key::new(); diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 1a599706a..c9e4e6a0f 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -173,24 +173,48 @@ impl Lookup for StructId { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct UnionId(salsa::InternId); impl_intern_key!(UnionId); -impl AstItemDef for UnionId { - fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { - db.intern_union(loc) + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct UnionLoc { + pub container: ModuleId, + pub ast_id: AstId, +} + +impl Intern for UnionLoc { + type ID = UnionId; + fn intern(self, db: &impl db::DefDatabase) -> UnionId { + db.intern_union(self) } - fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { - db.lookup_intern_union(self) +} + +impl Lookup for UnionId { + type Data = UnionLoc; + fn lookup(&self, db: &impl db::DefDatabase) -> UnionLoc { + db.lookup_intern_union(*self) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EnumId(salsa::InternId); impl_intern_key!(EnumId); -impl AstItemDef for EnumId { - fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { - db.intern_enum(loc) + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct EnumLoc { + pub container: ModuleId, + pub ast_id: AstId, +} + +impl Intern for EnumLoc { + type ID = EnumId; + fn intern(self, db: &impl db::DefDatabase) -> EnumId { + db.intern_enum(self) } - fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { - db.lookup_intern_enum(self) +} + +impl Lookup for EnumId { + type Data = EnumLoc; + fn lookup(&self, db: &impl db::DefDatabase) -> EnumLoc { + db.lookup_intern_enum(*self) } } @@ -545,8 +569,8 @@ impl HasModule for AdtId { fn module(&self, db: &impl db::DefDatabase) -> ModuleId { match self { AdtId::StructId(it) => it.lookup(db).container, - AdtId::UnionId(it) => it.module(db), - AdtId::EnumId(it) => it.module(db), + AdtId::UnionId(it) => it.lookup(db).container, + AdtId::EnumId(it) => it.lookup(db).container, } } } @@ -569,7 +593,7 @@ impl HasModule for GenericDefId { GenericDefId::TraitId(it) => it.lookup(db).container, GenericDefId::TypeAliasId(it) => it.lookup(db).module(db), GenericDefId::ImplId(it) => it.lookup(db).container, - GenericDefId::EnumVariantId(it) => it.parent.module(db), + GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container, GenericDefId::ConstId(it) => it.lookup(db).module(db), } } diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 602ec0911..04aadead1 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -24,9 +24,9 @@ use crate::{ }, path::{Path, PathKind}, per_ns::PerNs, - AdtId, AstId, AstItemDef, ConstLoc, ContainerId, EnumId, EnumVariantId, FunctionLoc, ImplLoc, - Intern, LocalImportId, LocalModuleId, LocationCtx, ModuleDefId, ModuleId, StaticLoc, StructLoc, - TraitLoc, TypeAliasLoc, UnionId, + AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern, + LocalImportId, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, + TypeAliasLoc, UnionLoc, }; pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { @@ -753,8 +753,6 @@ where fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) { let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; - let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); - // FIXME: check attrs to see if this is an attribute macro invocation; // in which case we don't add the invocation, just a single attribute // macro invocation @@ -778,10 +776,15 @@ where PerNs::both(def.into(), def.into()) } raw::DefKind::Union(ast_id) => { - let id = UnionId::from_ast_id(ctx, ast_id).into(); - PerNs::both(id, id) + let def = UnionLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) } + .intern(self.def_collector.db); + PerNs::both(def.into(), def.into()) + } + raw::DefKind::Enum(ast_id) => { + let def = EnumLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) } + .intern(self.def_collector.db); + PerNs::types(def.into()) } - raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()), raw::DefKind::Const(ast_id) => { let def = ConstLoc { container: ContainerId::ModuleId(module), diff --git a/crates/ra_hir_def/src/src.rs b/crates/ra_hir_def/src/src.rs index 7e212adb1..20200d1db 100644 --- a/crates/ra_hir_def/src/src.rs +++ b/crates/ra_hir_def/src/src.rs @@ -5,7 +5,8 @@ use ra_arena::map::ArenaMap; use ra_syntax::ast; use crate::{ - db::DefDatabase, ConstLoc, FunctionLoc, ImplLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, + db::DefDatabase, ConstLoc, EnumLoc, FunctionLoc, ImplLoc, StaticLoc, StructLoc, TraitLoc, + TypeAliasLoc, UnionLoc, }; pub trait HasSource { @@ -76,6 +77,24 @@ impl HasSource for StructLoc { } } +impl HasSource for UnionLoc { + type Value = ast::UnionDef; + + fn source(&self, db: &impl DefDatabase) -> InFile { + let node = self.ast_id.to_node(db); + InFile::new(self.ast_id.file_id, node) + } +} + +impl HasSource for EnumLoc { + type Value = ast::EnumDef; + + fn source(&self, db: &impl DefDatabase) -> InFile { + let node = self.ast_id.to_node(db); + InFile::new(self.ast_id.file_id, node) + } +} + pub trait HasChildSource { type ChildId; type Value; diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 6af5bf50a..5f795bc02 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -14,7 +14,7 @@ use hir_def::{ path::{GenericArg, Path, PathKind, PathSegment}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, - AdtId, AstItemDef, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, + AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, }; use ra_arena::map::ArenaMap; @@ -698,10 +698,11 @@ impl_froms!(CallableDef: FunctionId, StructId, EnumVariantId); impl CallableDef { pub fn krate(self, db: &impl HirDatabase) -> CrateId { match self { - CallableDef::FunctionId(f) => f.lookup(db).module(db).krate, - CallableDef::StructId(s) => s.lookup(db).container.krate, - CallableDef::EnumVariantId(e) => e.parent.module(db).krate, + CallableDef::FunctionId(f) => f.lookup(db).module(db), + CallableDef::StructId(s) => s.lookup(db).container, + CallableDef::EnumVariantId(e) => e.parent.lookup(db).container, } + .krate } } -- cgit v1.2.3