Add hir::Local

This commit is contained in:
Aleksey Kladov 2019-11-10 00:32:00 +03:00
parent 5ac4ffbc12
commit 8b7f853cc1
14 changed files with 171 additions and 173 deletions

View file

@ -22,7 +22,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
use crate::{
adt::VariantDef,
db::{AstDatabase, DefDatabase, HirDatabase},
expr::{validation::ExprValidator, Body, BodySourceMap},
expr::{validation::ExprValidator, BindingAnnotation, Body, BodySourceMap, Pat, PatId},
generics::HasGenericParams,
ids::{
AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId,
@ -32,7 +32,7 @@ use crate::{
resolve::{Resolver, Scope, TypeNs},
traits::TraitData,
ty::{InferenceResult, Namespace, TraitRef},
Either, HasSource, ImportId, Name, ScopeDef, Ty,
Either, HasSource, ImportId, Name, ScopeDef, Source, Ty,
};
/// hir::Crate describes a single crate. It's the main interface with which
@ -1070,3 +1070,54 @@ impl AssocItem {
.expect("AssocItem without container")
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Local {
pub(crate) parent: DefWithBody,
pub(crate) pat_id: PatId,
}
impl Local {
pub fn name(self, db: &impl HirDatabase) -> Option<Name> {
let body = db.body_hir(self.parent);
match &body[self.pat_id] {
Pat::Bind { name, .. } => Some(name.clone()),
_ => None,
}
}
pub fn is_self(self, db: &impl HirDatabase) -> bool {
self.name(db) == Some(name::SELF_PARAM)
}
pub fn is_mut(self, db: &impl HirDatabase) -> bool {
let body = db.body_hir(self.parent);
match &body[self.pat_id] {
Pat::Bind { mode, .. } => match mode {
BindingAnnotation::Mutable | BindingAnnotation::RefMut => true,
_ => false,
},
_ => false,
}
}
pub fn parent(self, _db: &impl HirDatabase) -> DefWithBody {
self.parent
}
pub fn module(self, db: &impl HirDatabase) -> Module {
self.parent.module(db)
}
pub fn ty(self, db: &impl HirDatabase) -> Ty {
let infer = db.infer(self.parent);
infer[self.pat_id].clone()
}
pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> {
let (_body, source_map) = db.body_with_source_map(self.parent);
let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
let root = src.file_syntax(db);
src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root)))
}
}

View file

@ -17,7 +17,7 @@ impl_arena_id!(ScopeId);
#[derive(Debug, PartialEq, Eq)]
pub struct ExprScopes {
body: Arc<Body>,
pub(crate) body: Arc<Body>,
scopes: Arena<ScopeId, ScopeData>,
scope_by_expr: FxHashMap<ExprId, ScopeId>,
}

View file

@ -2,13 +2,17 @@
use hir_def::{StructId, StructOrUnionId, UnionId};
use hir_expand::name::AsName;
use ra_syntax::ast::{self, AstNode, NameOwner};
use ra_syntax::{
ast::{self, AstNode, NameOwner},
match_ast,
};
use crate::{
db::{AstDatabase, DefDatabase, HirDatabase},
ids::{AstItemDef, LocationCtx},
AstId, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module,
ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef,
AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource,
ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias,
Union, VariantDef,
};
pub trait FromSource: Sized {
@ -126,6 +130,26 @@ impl FromSource for StructField {
}
}
impl Local {
pub fn from_source(db: &impl HirDatabase, src: Source<ast::BindPat>) -> Option<Self> {
let file_id = src.file_id;
let parent: DefWithBody = src.ast.syntax().ancestors().find_map(|it| {
let res = match_ast! {
match it {
ast::ConstDef(ast) => { Const::from_source(db, Source { ast, file_id})?.into() },
ast::StaticDef(ast) => { Static::from_source(db, Source { ast, file_id})?.into() },
ast::FnDef(ast) => { Function::from_source(db, Source { ast, file_id})?.into() },
_ => return None,
}
};
Some(res)
})?;
let (_body, source_map) = db.body_with_source_map(parent);
let pat_id = source_map.node_pat(&src.ast.into())?;
Some(Local { parent, pat_id })
}
}
impl Module {
pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> {
let src_parent = Source {

View file

@ -65,7 +65,7 @@ pub use crate::{
docs::{DocDef, Docs, Documentation},
src::{HasBodySource, HasSource},
Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum,
EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef,
EnumVariant, FieldSource, FnData, Function, HasBody, Local, MacroDef, Module, ModuleDef,
ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
},
expr::ExprScopes,

View file

@ -28,7 +28,7 @@ use crate::{
ids::LocationCtx,
resolve::{ScopeDef, TypeNs, ValueNs},
ty::method_resolution::{self, implements_trait},
AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId,
AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, Local,
MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty,
};
@ -94,6 +94,7 @@ fn def_with_body_from_child_node(
#[derive(Debug)]
pub struct SourceAnalyzer {
resolver: Resolver,
body_owner: Option<DefWithBody>,
body_source_map: Option<Arc<BodySourceMap>>,
infer: Option<Arc<crate::ty::InferenceResult>>,
scopes: Option<Arc<crate::expr::ExprScopes>>,
@ -104,7 +105,7 @@ pub enum PathResolution {
/// An item
Def(crate::ModuleDef),
/// A local binding (only value namespace)
LocalBinding(Either<AstPtr<ast::BindPat>, AstPtr<ast::SelfParam>>),
Local(Local),
/// A generic parameter
GenericParam(u32),
SelfType(crate::ImplBlock),
@ -152,6 +153,7 @@ impl SourceAnalyzer {
let resolver = expr::resolver_for_scope(def.body(db), db, scope);
SourceAnalyzer {
resolver,
body_owner: Some(def),
body_source_map: Some(source_map),
infer: Some(def.infer(db)),
scopes: Some(scopes),
@ -162,6 +164,7 @@ impl SourceAnalyzer {
.ancestors()
.find_map(|node| try_get_resolver_for_node(db, file_id, &node))
.unwrap_or_default(),
body_owner: None,
body_source_map: None,
infer: None,
scopes: None,
@ -233,16 +236,9 @@ impl SourceAnalyzer {
});
let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| {
let res = match val {
ValueNs::LocalBinding(it) => {
// We get a `PatId` from resolver, but it actually can only
// point at `BindPat`, and not at the arbitrary pattern.
let pat_ptr = self
.body_source_map
.as_ref()?
.pat_syntax(it)?
.ast // FIXME: ignoring file_id here is definitelly wrong
.map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap());
PathResolution::LocalBinding(pat_ptr)
ValueNs::LocalBinding(pat_id) => {
let var = Local { parent: self.body_owner?, pat_id };
PathResolution::Local(var)
}
ValueNs::Function(it) => PathResolution::Def(it.into()),
ValueNs::Const(it) => PathResolution::Def(it.into()),