mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 04:19:13 +00:00
Use new Resolver API in type inference
This commit is contained in:
parent
758bc72873
commit
6b076f1931
13 changed files with 297 additions and 251 deletions
|
@ -1,30 +1,29 @@
|
|||
#![allow(unused_variables, dead_code)]
|
||||
//! Name resolution.
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{
|
||||
ModuleDef,
|
||||
name::Name,
|
||||
nameres::{PerNs, lower::ImportId, ItemMap},
|
||||
module_tree::ModuleId,
|
||||
ModuleDef, Module,
|
||||
db::HirDatabase,
|
||||
name::{Name, KnownName},
|
||||
nameres::{PerNs, ItemMap},
|
||||
generics::GenericParams,
|
||||
expr::{Body, scope::{ExprScopes, ScopeId}, PatId},
|
||||
expr::{scope::{ExprScopes, ScopeId}, PatId},
|
||||
impl_block::ImplBlock,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Resolver {
|
||||
scopes: Vec<Scope>, // maybe a 'linked list' of scopes? or allow linking a Resolver to a parent Resolver? that's an optimization that might not be necessary, though
|
||||
scopes: Vec<Scope>,
|
||||
}
|
||||
|
||||
// TODO how to store these best
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ModuleItemMap {
|
||||
item_map: Arc<ItemMap>,
|
||||
module_id: ModuleId,
|
||||
module: Module,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -39,8 +38,6 @@ pub(crate) enum Scope {
|
|||
ModuleScope(ModuleItemMap),
|
||||
/// Brings the generic parameters of an item into scope
|
||||
GenericParams(Arc<GenericParams>),
|
||||
/// Brings the function parameters into scope
|
||||
FunctionParams(Arc<Body>),
|
||||
/// Brings `Self` into scope
|
||||
ImplBlockScope(ImplBlock),
|
||||
/// Local bindings
|
||||
|
@ -49,36 +46,64 @@ pub(crate) enum Scope {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Resolution {
|
||||
// FIXME make these tuple variants
|
||||
/// An item
|
||||
Def {
|
||||
def: ModuleDef,
|
||||
import: Option<ImportId>,
|
||||
},
|
||||
/// A local binding (only value namespace)
|
||||
LocalBinding { pat: PatId },
|
||||
LocalBinding {
|
||||
pat: PatId,
|
||||
},
|
||||
/// A generic parameter
|
||||
GenericParam { idx: u32 },
|
||||
// TODO how does `Self` resolve?
|
||||
GenericParam {
|
||||
idx: u32,
|
||||
},
|
||||
SelfType(ImplBlock),
|
||||
}
|
||||
|
||||
impl Resolver {
|
||||
pub fn resolve_name(&self, name: &Name) -> PerNs<Resolution> {
|
||||
let mut resolution = PerNs::none();
|
||||
for scope in self.scopes.iter().rev() {
|
||||
let resolution = scope.resolve_name(name);
|
||||
if !resolution.is_none() {
|
||||
resolution = resolution.combine(scope.resolve_name(name));
|
||||
if resolution.is_both() {
|
||||
return resolution;
|
||||
}
|
||||
}
|
||||
PerNs::none()
|
||||
resolution
|
||||
}
|
||||
|
||||
pub fn resolve_path(&self, path: &Path) -> PerNs<Resolution> {
|
||||
unimplemented!()
|
||||
pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> {
|
||||
if let Some(name) = path.as_ident() {
|
||||
self.resolve_name(name)
|
||||
} else if path.is_self() {
|
||||
self.resolve_name(&Name::self_param())
|
||||
} else {
|
||||
let (item_map, module) = match self.module() {
|
||||
Some(m) => m,
|
||||
_ => return PerNs::none(),
|
||||
};
|
||||
let module_res = item_map.resolve_path(db, module, path);
|
||||
module_res.map(|def| Resolution::Def { def })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_names(&self) -> FxHashMap<Name, Resolution> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn module(&self) -> Option<(&ItemMap, Module)> {
|
||||
for scope in self.scopes.iter().rev() {
|
||||
match scope {
|
||||
Scope::ModuleScope(m) => {
|
||||
return Some((&m.item_map, m.module.clone()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolver {
|
||||
|
@ -95,11 +120,8 @@ impl Resolver {
|
|||
self.push_scope(Scope::ImplBlockScope(impl_block))
|
||||
}
|
||||
|
||||
pub(crate) fn push_module_scope(self, item_map: Arc<ItemMap>, module_id: ModuleId) -> Resolver {
|
||||
self.push_scope(Scope::ModuleScope(ModuleItemMap {
|
||||
item_map,
|
||||
module_id,
|
||||
}))
|
||||
pub(crate) fn push_module_scope(self, item_map: Arc<ItemMap>, module: Module) -> Resolver {
|
||||
self.push_scope(Scope::ModuleScope(ModuleItemMap { item_map, module }))
|
||||
}
|
||||
|
||||
pub(crate) fn push_expr_scope(
|
||||
|
@ -112,19 +134,45 @@ impl Resolver {
|
|||
scope_id,
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn push_function_params(self, body: Arc<Body>) -> Resolver {
|
||||
self.push_scope(Scope::FunctionParams(body))
|
||||
}
|
||||
|
||||
pub(crate) fn pop_scope(mut self) -> Resolver {
|
||||
self.scopes.pop();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
fn resolve_name(&self, name: &Name) -> PerNs<Resolution> {
|
||||
unimplemented!()
|
||||
match self {
|
||||
Scope::ModuleScope(m) => {
|
||||
if let Some(KnownName::SelfParam) = name.as_known_name() {
|
||||
PerNs::types(Resolution::Def {
|
||||
def: m.module.into(),
|
||||
})
|
||||
} else {
|
||||
match m.item_map[m.module.module_id].get(name) {
|
||||
Some(res) => res.def.map(|def| Resolution::Def { def }),
|
||||
None => PerNs::none(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Scope::GenericParams(gp) => match gp.find_by_name(name) {
|
||||
Some(gp) => PerNs::types(Resolution::GenericParam { idx: gp.idx }),
|
||||
None => PerNs::none(),
|
||||
},
|
||||
Scope::ImplBlockScope(i) => {
|
||||
if name.as_known_name() == Some(KnownName::SelfType) {
|
||||
PerNs::types(Resolution::SelfType(i.clone()))
|
||||
} else {
|
||||
PerNs::none()
|
||||
}
|
||||
}
|
||||
Scope::ExprScope(e) => {
|
||||
let entry = e
|
||||
.expr_scopes
|
||||
.entries(e.scope_id)
|
||||
.iter()
|
||||
.find(|entry| entry.name() == name);
|
||||
match entry {
|
||||
Some(e) => PerNs::values(Resolution::LocalBinding { pat: e.pat() }),
|
||||
None => PerNs::none(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue