mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-19 10:24:16 +00:00
Merge #6862
6862: Add LifetimeParam resolving to Semantics r=matklad a=Veykril This is stuff required for the lifetime references/definitions PR. I pulled this out to make it easier to review as well as because there is one thing that still has to be addressed which can be found in the review comments. Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
commit
817fbebbb5
@ -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`
|
||||
|
@ -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 {
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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, ¶m)
|
||||
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),
|
||||
];
|
||||
|
@ -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! {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user