about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2020-12-13 22:13:16 +0100
committerLukas Wirth <lukastw97@gmail.com>2020-12-14 16:04:28 +0100
commitc6172f3f6d3fb0982ae17f48507608609d46d179 (patch)
treefc22462068c549baacaa261cc7243e36791f3c1e
parentdbd0cfba531c21de01af7b1a12ce9eb6b1271a5d (diff)
downloadrust-c6172f3f6d3fb0982ae17f48507608609d46d179.tar.gz
rust-c6172f3f6d3fb0982ae17f48507608609d46d179.zip
Add LifetimeParam resolving to Semantics
-rw-r--r--crates/hir/src/code_model.rs8
-rw-r--r--crates/hir/src/from_id.rs17
-rw-r--r--crates/hir/src/has_source.rs14
-rw-r--r--crates/hir/src/semantics.rs51
-rw-r--r--crates/hir/src/semantics/source_to_def.rs21
-rw-r--r--crates/hir_def/src/generics.rs49
-rw-r--r--crates/hir_def/src/item_tree/lower.rs5
-rw-r--r--crates/hir_def/src/keys.rs5
8 files changed, 131 insertions, 39 deletions
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index fcc42c6bbc4..42dc35b762c 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 265ef6d1f3f..dd3fcfe4ab8 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<GenericDef> for GenericDefId {
     }
 }
 
+impl From<GenericDefId> 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<Adt> 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 c77494152e6..1e64a1614b3 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<ast::Trait, ast::TypeParam>;
     fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
         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<Self::Ast> {
+        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 4bd22ed2769..e4fc21cedf9 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<LifetimeParam> {
+        self.imp.resolve_lifetime_param(lifetime_token)
+    }
+
     pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
         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<LifetimeParam> {
+        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<Type> {
-        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<Type> {
-        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<Type> {
-        self.analyze(param.syntax()).type_of_self(self.db, &param)
+        self.analyze(param.syntax()).type_of_self(self.db, param)
     }
 
     fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
@@ -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 66fc11611b1..badcf0ae807 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<ast::TypeParam>) -> Option<TypeParamId> {
         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<ast::LifetimeParam>,
+    ) -> Option<LifetimeParamId> {
+        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<ast::MacroCall>) -> Option<MacroDefId> {
         let kind = MacroDefKind::Declarative;
@@ -203,7 +216,7 @@ impl SourceToDefCtx<'_, '_> {
         Some(def.into())
     }
 
-    fn find_type_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> {
+    fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> {
         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 5189c7e9f38..81912a4546f 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<LifetimeParamId>, TypeRef)
 }
 
-type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>;
+#[derive(Default)]
+pub struct SourceMaps {
+    pub type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>,
+    pub lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>,
+}
 
 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<SourceMap>) {
+    fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMaps>) {
         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<ast::Trait, ast::TypeParam>;
-    fn child_source(&self, db: &dyn DefDatabase) -> InFile<SourceMap> {
-        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<SourceMaps> {
+        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 f7ce2e26df8..2939c6b1e30 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 40a5d92b507..9c585de2ce1 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<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>;
@@ -28,6 +28,7 @@ pub const VARIANT: Key<ast::Variant, EnumVariantId> = Key::new();
 pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new();
 pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new();
 pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new();
+pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new();
 
 pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new();