From c6172f3f6d3fb0982ae17f48507608609d46d179 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 13 Dec 2020 22:13:16 +0100 Subject: Add LifetimeParam resolving to Semantics --- crates/hir/src/code_model.rs | 8 +++++ crates/hir/src/from_id.rs | 17 +++++++++++ crates/hir/src/has_source.rs | 14 +++++++-- crates/hir/src/semantics.rs | 51 +++++++++++++++++++++++++++---- crates/hir/src/semantics/source_to_def.rs | 21 ++++++++++--- crates/hir_def/src/generics.rs | 49 ++++++++++++++++------------- crates/hir_def/src/item_tree/lower.rs | 5 ++- crates/hir_def/src/keys.rs | 5 +-- 8 files changed, 131 insertions(+), 39 deletions(-) (limited to 'crates') diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index fcc42c6bb..42dc35b76 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs @@ -1250,6 +1250,14 @@ impl LifetimeParam { let params = db.generic_params(self.id.parent); params.lifetimes[self.id.local_id].name.clone() } + + pub fn module(self, db: &dyn HirDatabase) -> Module { + self.id.parent.module(db.upcast()).into() + } + + pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { + self.id.parent.into() + } } // FIXME: rename from `ImplDef` to `Impl` diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index 265ef6d1f..dd3fcfe4a 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs @@ -41,6 +41,7 @@ from_id![ (hir_def::FunctionId, crate::Function), (hir_def::ImplId, crate::ImplDef), (hir_def::TypeParamId, crate::TypeParam), + (hir_def::LifetimeParamId, crate::LifetimeParam), (hir_expand::MacroDefId, crate::MacroDef) ]; @@ -154,6 +155,22 @@ impl From for GenericDefId { } } +impl From for GenericDef { + fn from(def: GenericDefId) -> Self { + match def { + GenericDefId::FunctionId(it) => GenericDef::Function(it.into()), + GenericDefId::AdtId(it) => GenericDef::Adt(it.into()), + GenericDefId::TraitId(it) => GenericDef::Trait(it.into()), + GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()), + GenericDefId::ImplId(it) => GenericDef::ImplDef(it.into()), + GenericDefId::EnumVariantId(it) => { + GenericDef::EnumVariant(EnumVariant { parent: it.parent.into(), id: it.local_id }) + } + GenericDefId::ConstId(it) => GenericDef::Const(it.into()), + } + } +} + impl From for GenericDefId { fn from(id: Adt) -> Self { match id { diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index c77494152..1e64a1614 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs @@ -10,8 +10,8 @@ use hir_expand::InFile; use syntax::ast; use crate::{ - db::HirDatabase, Const, Enum, EnumVariant, Field, FieldSource, Function, ImplDef, MacroDef, - Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, + db::HirDatabase, Const, Enum, EnumVariant, Field, FieldSource, Function, ImplDef, + LifetimeParam, MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, }; pub trait HasSource { @@ -129,6 +129,14 @@ impl HasSource for TypeParam { type Ast = Either; fn source(self, db: &dyn HirDatabase) -> InFile { let child_source = self.id.parent.child_source(db.upcast()); - child_source.map(|it| it[self.id.local_id].clone()) + child_source.map(|it| it.type_params[self.id.local_id].clone()) + } +} + +impl HasSource for LifetimeParam { + type Ast = ast::LifetimeParam; + fn source(self, db: &dyn HirDatabase) -> InFile { + let child_source = self.id.parent.child_source(db.upcast()); + child_source.map(|it| it.lifetime_params[self.id.local_id].clone()) } } diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 4bd22ed27..e4fc21ced 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -13,7 +13,11 @@ use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo}; use hir_ty::associated_type_shorthand_candidates; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; -use syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode, SyntaxToken, TextSize}; +use syntax::{ + algo::find_node_at_offset, + ast::{self, GenericParamsOwner}, + match_ast, AstNode, SyntaxNode, SyntaxToken, TextSize, +}; use crate::{ code_model::Access, @@ -21,8 +25,9 @@ use crate::{ diagnostics::Diagnostic, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{resolve_hir_path, SourceAnalyzer}, - AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, - Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, + AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, LifetimeParam, Local, + MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, + VariantDef, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -173,6 +178,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.descend_node_at_offset(node, offset).find_map(N::cast) } + // FIXME: Replace the SyntaxToken with a typed ast Node/Token + pub fn resolve_lifetime_param(&self, lifetime_token: &SyntaxToken) -> Option { + self.imp.resolve_lifetime_param(lifetime_token) + } + pub fn type_of_expr(&self, expr: &ast::Expr) -> Option { self.imp.type_of_expr(expr) } @@ -392,16 +402,44 @@ impl<'db> SemanticsImpl<'db> { .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) } + // FIXME: Replace the SyntaxToken with a typed ast Node/Token + fn resolve_lifetime_param(&self, lifetime_token: &SyntaxToken) -> Option { + if lifetime_token.kind() != syntax::SyntaxKind::LIFETIME { + return None; + } + let lifetime_text = lifetime_token.text(); + let lifetime_param = lifetime_token.parent().ancestors().find_map(|syn| { + let gpl = match_ast! { + match syn { + ast::Fn(it) => it.generic_param_list()?, + ast::TypeAlias(it) => it.generic_param_list()?, + ast::Struct(it) => it.generic_param_list()?, + ast::Enum(it) => it.generic_param_list()?, + ast::Union(it) => it.generic_param_list()?, + ast::Trait(it) => it.generic_param_list()?, + ast::Impl(it) => it.generic_param_list()?, + ast::WherePred(it) => it.generic_param_list()?, + ast::ForType(it) => it.generic_param_list()?, + _ => return None, + } + }; + gpl.lifetime_params() + .find(|tp| tp.lifetime_token().as_ref().map(|lt| lt.text()) == Some(lifetime_text)) + })?; + let src = self.find_file(lifetime_param.syntax().clone()).with_value(lifetime_param); + ToDef::to_def(self, src) + } + fn type_of_expr(&self, expr: &ast::Expr) -> Option { - self.analyze(expr.syntax()).type_of_expr(self.db, &expr) + self.analyze(expr.syntax()).type_of_expr(self.db, expr) } fn type_of_pat(&self, pat: &ast::Pat) -> Option { - self.analyze(pat.syntax()).type_of_pat(self.db, &pat) + self.analyze(pat.syntax()).type_of_pat(self.db, pat) } fn type_of_self(&self, param: &ast::SelfParam) -> Option { - self.analyze(param.syntax()).type_of_self(self.db, ¶m) + self.analyze(param.syntax()).type_of_self(self.db, param) } fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { @@ -684,6 +722,7 @@ to_def_impls![ (crate::Field, ast::TupleField, tuple_field_to_def), (crate::EnumVariant, ast::Variant, enum_variant_to_def), (crate::TypeParam, ast::TypeParam, type_param_to_def), + (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), (crate::MacroDef, ast::MacroCall, macro_call_to_def), // this one is dubious, not all calls are macros (crate::Local, ast::IdentPat, bind_pat_to_def), ]; diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 66fc11611..badcf0ae8 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -7,7 +7,8 @@ use hir_def::{ expr::PatId, keys::{self, Key}, ConstId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, ImplId, - ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, + LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, + VariantId, }; use hir_expand::{name::AsName, AstId, MacroDefKind}; use rustc_hash::FxHashMap; @@ -128,13 +129,25 @@ impl SourceToDefCtx<'_, '_> { pub(super) fn type_param_to_def(&mut self, src: InFile) -> Option { let container: ChildContainer = - self.find_type_param_container(src.as_ref().map(|it| it.syntax()))?.into(); + self.find_generic_param_container(src.as_ref().map(|it| it.syntax()))?.into(); let db = self.db; let dyn_map = &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db)); dyn_map[keys::TYPE_PARAM].get(&src).copied() } + pub(super) fn lifetime_param_to_def( + &mut self, + src: InFile, + ) -> Option { + let container: ChildContainer = + self.find_generic_param_container(src.as_ref().map(|it| it.syntax()))?.into(); + let db = self.db; + let dyn_map = + &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db)); + dyn_map[keys::LIFETIME_PARAM].get(&src).copied() + } + // FIXME: use DynMap as well? pub(super) fn macro_call_to_def(&mut self, src: InFile) -> Option { let kind = MacroDefKind::Declarative; @@ -203,7 +216,7 @@ impl SourceToDefCtx<'_, '_> { Some(def.into()) } - fn find_type_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option { + fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option { for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { let res: GenericDefId = match_ast! { match (container.value) { @@ -247,7 +260,7 @@ pub(crate) enum ChildContainer { VariantId(VariantId), TypeAliasId(TypeAliasId), /// XXX: this might be the same def as, for example an `EnumId`. However, - /// here the children generic parameters, and not, eg enum variants. + /// here the children are generic parameters, and not, eg enum variants. GenericDefId(GenericDefId), } impl_from! { diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 5189c7e9f..81912a454 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs @@ -19,10 +19,10 @@ use crate::{ db::DefDatabase, dyn_map::DynMap, keys, - src::HasChildSource, src::HasSource, type_ref::{LifetimeRef, TypeBound, TypeRef}, - AdtId, GenericDefId, LocalTypeParamId, Lookup, TypeParamId, + AdtId, GenericDefId, LifetimeParamId, LocalLifetimeParamId, LocalTypeParamId, Lookup, + TypeParamId, }; /// Data about a generic parameter (to a function, struct, impl, ...). @@ -72,7 +72,11 @@ pub enum WherePredicateTypeTarget { // FIXME: ForLifetime(Vec, TypeRef) } -type SourceMap = ArenaMap>; +#[derive(Default)] +pub struct SourceMaps { + pub type_params: ArenaMap>, + pub lifetime_params: ArenaMap, +} impl GenericParams { pub(crate) fn generic_params_query( @@ -129,9 +133,9 @@ impl GenericParams { Arc::new(generics) } - fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile) { + fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile) { let mut generics = GenericParams::default(); - let mut sm = ArenaMap::default(); + let mut sm = SourceMaps::default(); // FIXME: add `: Sized` bound for everything except for `Self` in traits let file_id = match def { @@ -174,7 +178,7 @@ impl GenericParams { default: None, provenance: TypeParamProvenance::TraitSelf, }); - sm.insert(self_param_id, Either::Left(src.value.clone())); + sm.type_params.insert(self_param_id, Either::Left(src.value.clone())); // add super traits as bounds on Self // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar let self_param = TypeRef::Path(name![Self].into()); @@ -210,7 +214,7 @@ impl GenericParams { pub(crate) fn fill( &mut self, lower_ctx: &LowerCtx, - sm: &mut SourceMap, + sm: &mut SourceMaps, node: &dyn GenericParamsOwner, ) { if let Some(params) = node.generic_param_list() { @@ -237,7 +241,7 @@ impl GenericParams { fn fill_params( &mut self, lower_ctx: &LowerCtx, - sm: &mut SourceMap, + sm: &mut SourceMaps, params: ast::GenericParamList, ) { for type_param in params.type_params() { @@ -250,7 +254,7 @@ impl GenericParams { provenance: TypeParamProvenance::TypeParamList, }; let param_id = self.types.alloc(param); - sm.insert(param_id, Either::Right(type_param.clone())); + sm.type_params.insert(param_id, Either::Right(type_param.clone())); let type_ref = TypeRef::Path(name.into()); self.fill_bounds(&lower_ctx, &type_param, Either::Left(type_ref)); @@ -260,7 +264,8 @@ impl GenericParams { .lifetime_token() .map_or_else(Name::missing, |tok| Name::new_lifetime(&tok)); let param = LifetimeParamData { name: name.clone() }; - let _param_id = self.lifetimes.alloc(param); + let param_id = self.lifetimes.alloc(param); + sm.lifetime_params.insert(param_id, lifetime_param.clone()); let lifetime_ref = LifetimeRef::new_name(name); self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); } @@ -340,27 +345,29 @@ impl GenericParams { }) } } - -impl HasChildSource for GenericDefId { - type ChildId = LocalTypeParamId; - type Value = Either; - fn child_source(&self, db: &dyn DefDatabase) -> InFile { - let (_, sm) = GenericParams::new(db, *self); - sm +impl GenericDefId { + // FIXME: Change HasChildSource's ChildId AssocItem to be a generic parameter instead + pub fn child_source(&self, db: &dyn DefDatabase) -> InFile { + GenericParams::new(db, *self).1 } } impl ChildBySource for GenericDefId { fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { let mut res = DynMap::default(); - let arena_map = self.child_source(db); - let arena_map = arena_map.as_ref(); - for (local_id, src) in arena_map.value.iter() { + let (_, sm) = GenericParams::new(db, *self); + + let sm = sm.as_ref(); + for (local_id, src) in sm.value.type_params.iter() { let id = TypeParamId { parent: *self, local_id }; if let Either::Right(type_param) = src { - res[keys::TYPE_PARAM].insert(arena_map.with_value(type_param.clone()), id) + res[keys::TYPE_PARAM].insert(sm.with_value(type_param.clone()), id) } } + for (local_id, src) in sm.value.lifetime_params.iter() { + let id = LifetimeParamId { parent: *self, local_id }; + res[keys::LIFETIME_PARAM].insert(sm.with_value(src.clone()), id); + } res } } diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index f7ce2e26d..2939c6b1e 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs @@ -2,7 +2,6 @@ use std::{collections::hash_map::Entry, mem, sync::Arc}; -use arena::map::ArenaMap; use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId}; use smallvec::SmallVec; use syntax::{ @@ -607,7 +606,7 @@ impl Ctx { owner: GenericsOwner<'_>, node: &impl ast::GenericParamsOwner, ) -> GenericParamsId { - let mut sm = &mut ArenaMap::default(); + let mut sm = &mut Default::default(); let mut generics = GenericParams::default(); match owner { GenericsOwner::Function(func) => { @@ -630,7 +629,7 @@ impl Ctx { default: None, provenance: TypeParamProvenance::TraitSelf, }); - sm.insert(self_param_id, Either::Left(trait_def.clone())); + sm.type_params.insert(self_param_id, Either::Left(trait_def.clone())); // add super traits as bounds on Self // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar let self_param = TypeRef::Path(name![Self].into()); diff --git a/crates/hir_def/src/keys.rs b/crates/hir_def/src/keys.rs index 40a5d92b5..9c585de2c 100644 --- a/crates/hir_def/src/keys.rs +++ b/crates/hir_def/src/keys.rs @@ -8,8 +8,8 @@ use syntax::{ast, AstNode, AstPtr}; use crate::{ dyn_map::{DynMap, Policy}, - ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, StaticId, StructId, TraitId, - TypeAliasId, TypeParamId, UnionId, + ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, StaticId, + StructId, TraitId, TypeAliasId, TypeParamId, UnionId, }; pub type Key = crate::dyn_map::Key, V, AstPtrPolicy>; @@ -28,6 +28,7 @@ pub const VARIANT: Key = Key::new(); pub const TUPLE_FIELD: Key = Key::new(); pub const RECORD_FIELD: Key = Key::new(); pub const TYPE_PARAM: Key = Key::new(); +pub const LIFETIME_PARAM: Key = Key::new(); pub const MACRO: Key = Key::new(); -- cgit v1.2.3