mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-04 04:39:16 +00:00
Use new Resolver API in type inference
This commit is contained in:
parent
758bc72873
commit
6b076f1931
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ crates/*/target
|
||||
*.log
|
||||
*.iml
|
||||
.vscode/settings.json
|
||||
**/*.snap.new
|
||||
|
@ -5,7 +5,7 @@ use ra_db::{CrateId, FileId};
|
||||
use ra_syntax::{ast::self, TreeArc, SyntaxNode};
|
||||
|
||||
use crate::{
|
||||
Name, Path, PerNs, ScopesWithSyntaxMapping, Ty, HirFileId,
|
||||
Name, ScopesWithSyntaxMapping, Ty, HirFileId,
|
||||
type_ref::TypeRef,
|
||||
nameres::{ModuleScope, lower::ImportId},
|
||||
HirDatabase, PersistentHirDatabase,
|
||||
@ -175,18 +175,13 @@ impl Module {
|
||||
db.item_map(self.krate)[self.module_id].clone()
|
||||
}
|
||||
|
||||
pub fn resolve_path(&self, db: &impl PersistentHirDatabase, path: &Path) -> PerNs<ModuleDef> {
|
||||
// TODO replace by Resolver::resolve_path
|
||||
db.item_map(self.krate).resolve_path(db, *self, path)
|
||||
}
|
||||
|
||||
pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
|
||||
self.problems_impl(db)
|
||||
}
|
||||
|
||||
pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
|
||||
let item_map = db.item_map(self.krate);
|
||||
Resolver::default().push_module_scope(item_map, self.module_id)
|
||||
Resolver::default().push_module_scope(item_map, *self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,6 +284,21 @@ impl Struct {
|
||||
pub fn ty(&self, db: &impl HirDatabase) -> Ty {
|
||||
db.type_for_def((*self).into())
|
||||
}
|
||||
|
||||
// TODO move to a more general type
|
||||
/// Builds a resolver for type references inside this struct.
|
||||
pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
|
||||
// take the outer scope...
|
||||
let r = self.module(db).resolver(db);
|
||||
// ...and add generic params, if present
|
||||
let p = self.generic_params(db);
|
||||
let r = if !p.params.is_empty() {
|
||||
r.push_generic_params_scope(p)
|
||||
} else {
|
||||
r
|
||||
};
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
impl Docs for Struct {
|
||||
@ -338,6 +348,21 @@ impl Enum {
|
||||
pub fn ty(&self, db: &impl HirDatabase) -> Ty {
|
||||
db.type_for_def((*self).into())
|
||||
}
|
||||
|
||||
// TODO move to a more general type
|
||||
/// Builds a resolver for type references inside this struct.
|
||||
pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
|
||||
// take the outer scope...
|
||||
let r = self.module(db).resolver(db);
|
||||
// ...and add generic params, if present
|
||||
let p = self.generic_params(db);
|
||||
let r = if !p.params.is_empty() {
|
||||
r.push_generic_params_scope(p)
|
||||
} else {
|
||||
r
|
||||
};
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
impl Docs for Enum {
|
||||
|
@ -75,9 +75,6 @@ impl Body {
|
||||
#[allow(dead_code)]
|
||||
pub fn resolver_for_expr(body: Arc<Body>, db: &impl HirDatabase, expr_id: ExprId) -> Resolver {
|
||||
let mut r = body.owner.resolver(db);
|
||||
if !body.params.is_empty() {
|
||||
r = r.push_function_params(Arc::clone(&body));
|
||||
}
|
||||
let scopes = db.expr_scopes(body.owner);
|
||||
let scope_chain = scopes.scope_chain_for(expr_id).collect::<Vec<_>>();
|
||||
for scope in scope_chain.into_iter().rev() {
|
||||
|
@ -7,13 +7,13 @@ use ra_syntax::{
|
||||
ast::{self, AstNode}};
|
||||
|
||||
use crate::{
|
||||
Const, Type,
|
||||
Function, HirFileId,
|
||||
HirDatabase,
|
||||
PersistentHirDatabase,
|
||||
Const, Type, Function, HirFileId,
|
||||
HirDatabase, PersistentHirDatabase,
|
||||
ModuleDef, Trait, Resolution,
|
||||
type_ref::TypeRef,
|
||||
ids::LocationCtx,
|
||||
resolve::Resolver,
|
||||
ty::Ty,
|
||||
};
|
||||
|
||||
use crate::code_model_api::{Module, ModuleSource};
|
||||
@ -75,7 +75,7 @@ impl ImplBlock {
|
||||
self.module_impl_blocks.module.clone()
|
||||
}
|
||||
|
||||
pub fn target_trait(&self) -> Option<&TypeRef> {
|
||||
pub fn target_trait_ref(&self) -> Option<&TypeRef> {
|
||||
self.impl_data().target_trait()
|
||||
}
|
||||
|
||||
@ -83,6 +83,23 @@ impl ImplBlock {
|
||||
self.impl_data().target_type()
|
||||
}
|
||||
|
||||
pub fn target_ty(&self, db: &impl HirDatabase) -> Ty {
|
||||
Ty::from_hir(db, &self.resolver(db), self.target_type())
|
||||
}
|
||||
|
||||
pub fn target_trait(&self, db: &impl HirDatabase) -> Option<Trait> {
|
||||
if let Some(TypeRef::Path(path)) = self.target_trait_ref() {
|
||||
let resolver = self.resolver(db);
|
||||
if let Some(Resolution::Def {
|
||||
def: ModuleDef::Trait(tr),
|
||||
}) = resolver.resolve_path(db, path).take_types()
|
||||
{
|
||||
return Some(tr);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn items(&self) -> &[ImplItem] {
|
||||
self.impl_data().items()
|
||||
}
|
||||
|
@ -55,13 +55,13 @@ pub use self::{
|
||||
name::Name,
|
||||
ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner},
|
||||
macros::{MacroDef, MacroInput, MacroExpansion},
|
||||
nameres::{ItemMap, PerNs, Namespace, Resolution},
|
||||
nameres::{ItemMap, PerNs, Namespace},
|
||||
ty::Ty,
|
||||
impl_block::{ImplBlock, ImplItem},
|
||||
docs::{Docs, Documentation},
|
||||
adt::AdtDef,
|
||||
expr::{ExprScopes, ScopesWithSyntaxMapping},
|
||||
resolve::Resolver,
|
||||
resolve::{Resolver, Resolution},
|
||||
};
|
||||
|
||||
pub use self::code_model_api::{
|
||||
|
@ -24,8 +24,9 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use crate::{
|
||||
Module, ModuleDef,
|
||||
Path, PathKind, Crate,
|
||||
Name, PersistentHirDatabase,
|
||||
Path, PathKind, PersistentHirDatabase,
|
||||
Crate,
|
||||
Name,
|
||||
module_tree::{ModuleId, ModuleTree},
|
||||
nameres::lower::{ImportId, LoweredModule, ImportData},
|
||||
};
|
||||
@ -46,7 +47,7 @@ impl std::ops::Index<ModuleId> for ItemMap {
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, Clone)]
|
||||
pub struct ModuleScope {
|
||||
items: FxHashMap<Name, Resolution>,
|
||||
pub(crate) items: FxHashMap<Name, Resolution>,
|
||||
}
|
||||
|
||||
impl ModuleScope {
|
||||
@ -113,6 +114,10 @@ impl<T> PerNs<T> {
|
||||
self.types.is_none() && self.values.is_none()
|
||||
}
|
||||
|
||||
pub fn is_both(&self) -> bool {
|
||||
self.types.is_some() && self.values.is_some()
|
||||
}
|
||||
|
||||
pub fn take(self, namespace: Namespace) -> Option<T> {
|
||||
match namespace {
|
||||
Namespace::Types => self.types,
|
||||
@ -139,6 +144,13 @@ impl<T> PerNs<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn combine(self, other: PerNs<T>) -> PerNs<T> {
|
||||
PerNs {
|
||||
types: self.types.or(other.types),
|
||||
values: self.values.or(other.values),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
|
||||
PerNs {
|
||||
types: self.types.and_then(&f),
|
||||
@ -402,10 +414,11 @@ impl ItemMap {
|
||||
if module.krate != original_module.krate {
|
||||
let path = Path {
|
||||
segments: path.segments[i..].iter().cloned().collect(),
|
||||
kind: PathKind::Crate,
|
||||
kind: PathKind::Self_,
|
||||
};
|
||||
log::debug!("resolving {:?} in other crate", path);
|
||||
let def = module.resolve_path(db, &path);
|
||||
let item_map = db.item_map(module.krate);
|
||||
let def = item_map.resolve_path(db, *module, &path);
|
||||
return (def, ReachedFixedPoint::Yes);
|
||||
}
|
||||
|
||||
|
@ -5,11 +5,12 @@ use relative_path::RelativePath;
|
||||
use test_utils::{assert_eq_text, covers};
|
||||
|
||||
use crate::{
|
||||
ItemMap, Resolution,
|
||||
ItemMap,
|
||||
PersistentHirDatabase,
|
||||
mock::MockDatabase,
|
||||
module_tree::ModuleId,
|
||||
};
|
||||
use super::Resolution;
|
||||
|
||||
fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) {
|
||||
let (db, pos) = MockDatabase::with_position(fixture);
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,15 +33,16 @@ use rustc_hash::FxHashMap;
|
||||
use test_utils::tested_by;
|
||||
|
||||
use crate::{
|
||||
Module, Function, Struct, StructField, Enum, EnumVariant, Path, Name, ImplBlock,
|
||||
FnSignature, ExprScopes, ModuleDef, AdtDef,
|
||||
Function, Struct, StructField, Enum, EnumVariant, Path, Name,
|
||||
FnSignature, ModuleDef, AdtDef,
|
||||
HirDatabase,
|
||||
type_ref::{TypeRef, Mutability},
|
||||
name::KnownName,
|
||||
expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat},
|
||||
expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self},
|
||||
generics::GenericParams,
|
||||
path::GenericArg,
|
||||
adt::VariantDef,
|
||||
resolve::{Resolver, Resolution},
|
||||
};
|
||||
|
||||
/// The ID of a type variable.
|
||||
@ -300,47 +301,38 @@ pub struct FnSig {
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
pub(crate) fn from_hir(
|
||||
db: &impl HirDatabase,
|
||||
// TODO: the next three parameters basically describe the scope for name
|
||||
// resolution; this should be refactored into something like a general
|
||||
// resolver architecture
|
||||
module: &Module,
|
||||
impl_block: Option<&ImplBlock>,
|
||||
generics: &GenericParams,
|
||||
type_ref: &TypeRef,
|
||||
) -> Self {
|
||||
pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self {
|
||||
match type_ref {
|
||||
TypeRef::Never => Ty::Never,
|
||||
TypeRef::Tuple(inner) => {
|
||||
let inner_tys = inner
|
||||
.iter()
|
||||
.map(|tr| Ty::from_hir(db, module, impl_block, generics, tr))
|
||||
.map(|tr| Ty::from_hir(db, resolver, tr))
|
||||
.collect::<Vec<_>>();
|
||||
Ty::Tuple(inner_tys.into())
|
||||
}
|
||||
TypeRef::Path(path) => Ty::from_hir_path(db, module, impl_block, generics, path),
|
||||
TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path),
|
||||
TypeRef::RawPtr(inner, mutability) => {
|
||||
let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner);
|
||||
let inner_ty = Ty::from_hir(db, resolver, inner);
|
||||
Ty::RawPtr(Arc::new(inner_ty), *mutability)
|
||||
}
|
||||
TypeRef::Array(inner) => {
|
||||
let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner);
|
||||
let inner_ty = Ty::from_hir(db, resolver, inner);
|
||||
Ty::Array(Arc::new(inner_ty))
|
||||
}
|
||||
TypeRef::Slice(inner) => {
|
||||
let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner);
|
||||
let inner_ty = Ty::from_hir(db, resolver, inner);
|
||||
Ty::Slice(Arc::new(inner_ty))
|
||||
}
|
||||
TypeRef::Reference(inner, mutability) => {
|
||||
let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner);
|
||||
let inner_ty = Ty::from_hir(db, resolver, inner);
|
||||
Ty::Ref(Arc::new(inner_ty), *mutability)
|
||||
}
|
||||
TypeRef::Placeholder => Ty::Unknown,
|
||||
TypeRef::Fn(params) => {
|
||||
let mut inner_tys = params
|
||||
.iter()
|
||||
.map(|tr| Ty::from_hir(db, module, impl_block, generics, tr))
|
||||
.map(|tr| Ty::from_hir(db, resolver, tr))
|
||||
.collect::<Vec<_>>();
|
||||
let return_ty = inner_tys
|
||||
.pop()
|
||||
@ -355,40 +347,13 @@ impl Ty {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_hir_opt(
|
||||
db: &impl HirDatabase,
|
||||
module: &Module,
|
||||
impl_block: Option<&ImplBlock>,
|
||||
generics: &GenericParams,
|
||||
type_ref: Option<&TypeRef>,
|
||||
) -> Self {
|
||||
type_ref.map_or(Ty::Unknown, |t| {
|
||||
Ty::from_hir(db, module, impl_block, generics, t)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn from_hir_path(
|
||||
db: &impl HirDatabase,
|
||||
module: &Module,
|
||||
impl_block: Option<&ImplBlock>,
|
||||
generics: &GenericParams,
|
||||
path: &Path,
|
||||
) -> Self {
|
||||
pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self {
|
||||
if let Some(name) = path.as_ident() {
|
||||
// TODO handle primitive type names in resolver as well?
|
||||
if let Some(int_ty) = primitive::UncertainIntTy::from_name(name) {
|
||||
return Ty::Int(int_ty);
|
||||
} else if let Some(float_ty) = primitive::UncertainFloatTy::from_name(name) {
|
||||
return Ty::Float(float_ty);
|
||||
} else if name.as_known_name() == Some(KnownName::SelfType) {
|
||||
// TODO pass the impl block's generics?
|
||||
let generics = &GenericParams::default();
|
||||
return Ty::from_hir_opt(
|
||||
db,
|
||||
module,
|
||||
None,
|
||||
generics,
|
||||
impl_block.map(|i| i.target_type()),
|
||||
);
|
||||
} else if let Some(known) = name.as_known_name() {
|
||||
match known {
|
||||
KnownName::Bool => return Ty::Bool,
|
||||
@ -396,25 +361,40 @@ impl Ty {
|
||||
KnownName::Str => return Ty::Str,
|
||||
_ => {}
|
||||
}
|
||||
} else if let Some(generic_param) = generics.find_by_name(&name) {
|
||||
return Ty::Param {
|
||||
idx: generic_param.idx,
|
||||
name: generic_param.name.clone(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve in module (in type namespace)
|
||||
let typable: TypableDef = match module
|
||||
.resolve_path(db, path)
|
||||
.take_types()
|
||||
.and_then(|it| it.into())
|
||||
{
|
||||
// Resolve the path (in type namespace)
|
||||
let resolution = resolver.resolve_path(db, path).take_types();
|
||||
|
||||
let def = match resolution {
|
||||
Some(Resolution::Def { def, .. }) => def,
|
||||
Some(Resolution::LocalBinding { .. }) => {
|
||||
// this should never happen
|
||||
panic!("path resolved to local binding in type ns");
|
||||
}
|
||||
Some(Resolution::GenericParam { idx }) => {
|
||||
return Ty::Param {
|
||||
idx,
|
||||
// TODO: maybe return name in resolution?
|
||||
name: path
|
||||
.as_ident()
|
||||
.expect("generic param should be single-segment path")
|
||||
.clone(),
|
||||
};
|
||||
}
|
||||
Some(Resolution::SelfType(impl_block)) => {
|
||||
return impl_block.target_ty(db);
|
||||
}
|
||||
None => return Ty::Unknown,
|
||||
};
|
||||
|
||||
let typable: TypableDef = match def.into() {
|
||||
None => return Ty::Unknown,
|
||||
Some(it) => it,
|
||||
};
|
||||
let ty = db.type_for_def(typable);
|
||||
let substs = Ty::substs_from_path(db, module, impl_block, generics, path, typable);
|
||||
let substs = Ty::substs_from_path(db, resolver, path, typable);
|
||||
ty.apply_substs(substs)
|
||||
}
|
||||
|
||||
@ -422,10 +402,7 @@ impl Ty {
|
||||
/// `create_substs_for_ast_path` and `def_to_ty` in rustc.
|
||||
fn substs_from_path(
|
||||
db: &impl HirDatabase,
|
||||
// the scope of the segment...
|
||||
module: &Module,
|
||||
impl_block: Option<&ImplBlock>,
|
||||
outer_generics: &GenericParams,
|
||||
resolver: &Resolver,
|
||||
path: &Path,
|
||||
resolved: TypableDef,
|
||||
) -> Substs {
|
||||
@ -462,7 +439,7 @@ impl Ty {
|
||||
for arg in generic_args.args.iter().take(param_count) {
|
||||
match arg {
|
||||
GenericArg::Type(type_ref) => {
|
||||
let ty = Ty::from_hir(db, module, impl_block, outer_generics, type_ref);
|
||||
let ty = Ty::from_hir(db, resolver, type_ref);
|
||||
substs.push(ty);
|
||||
}
|
||||
}
|
||||
@ -666,24 +643,17 @@ impl fmt::Display for Ty {
|
||||
/// function body.
|
||||
fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
|
||||
let signature = def.signature(db);
|
||||
let module = def.module(db);
|
||||
let impl_block = def.impl_block(db);
|
||||
let resolver = def.resolver(db);
|
||||
let generics = def.generic_params(db);
|
||||
let name = def.name(db);
|
||||
let input = signature
|
||||
.params()
|
||||
.iter()
|
||||
.map(|tr| Ty::from_hir(db, &module, impl_block.as_ref(), &generics, tr))
|
||||
.map(|tr| Ty::from_hir(db, &resolver, tr))
|
||||
.collect::<Vec<_>>();
|
||||
let output = Ty::from_hir(
|
||||
db,
|
||||
&module,
|
||||
impl_block.as_ref(),
|
||||
&generics,
|
||||
signature.ret_type(),
|
||||
);
|
||||
let output = Ty::from_hir(db, &resolver, signature.ret_type());
|
||||
let sig = Arc::new(FnSig { input, output });
|
||||
let substs = make_substs(&generics);
|
||||
let name = def.name(db);
|
||||
Ty::FnDef {
|
||||
def,
|
||||
sig,
|
||||
@ -764,13 +734,13 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty {
|
||||
|
||||
pub(super) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
|
||||
let parent_def = field.parent_def(db);
|
||||
let (generics, module) = match parent_def {
|
||||
VariantDef::Struct(it) => (it.generic_params(db), it.module(db)),
|
||||
VariantDef::EnumVariant(it) => (it.parent_enum(db).generic_params(db), it.module(db)),
|
||||
let resolver = match parent_def {
|
||||
VariantDef::Struct(it) => it.resolver(db),
|
||||
VariantDef::EnumVariant(it) => it.parent_enum(db).resolver(db),
|
||||
};
|
||||
let var_data = parent_def.variant_data(db);
|
||||
let type_ref = &var_data.fields().unwrap()[field.id].type_ref;
|
||||
Ty::from_hir(db, &module, None, &generics, type_ref)
|
||||
Ty::from_hir(db, &resolver, type_ref)
|
||||
}
|
||||
|
||||
/// The result of type inference: A mapping from expressions and patterns to types.
|
||||
@ -814,9 +784,7 @@ impl Index<PatId> for InferenceResult {
|
||||
struct InferenceContext<'a, D: HirDatabase> {
|
||||
db: &'a D,
|
||||
body: Arc<Body>,
|
||||
scopes: Arc<ExprScopes>,
|
||||
module: Module,
|
||||
impl_block: Option<ImplBlock>,
|
||||
resolver: Resolver,
|
||||
var_unification_table: InPlaceUnificationTable<TypeVarId>,
|
||||
method_resolutions: FxHashMap<ExprId, Function>,
|
||||
field_resolutions: FxHashMap<ExprId, StructField>,
|
||||
@ -905,13 +873,7 @@ fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
|
||||
}
|
||||
|
||||
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
fn new(
|
||||
db: &'a D,
|
||||
body: Arc<Body>,
|
||||
scopes: Arc<ExprScopes>,
|
||||
module: Module,
|
||||
impl_block: Option<ImplBlock>,
|
||||
) -> Self {
|
||||
fn new(db: &'a D, body: Arc<Body>, resolver: Resolver) -> Self {
|
||||
InferenceContext {
|
||||
method_resolutions: FxHashMap::default(),
|
||||
field_resolutions: FxHashMap::default(),
|
||||
@ -921,9 +883,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
return_ty: Ty::Unknown, // set in collect_fn_signature
|
||||
db,
|
||||
body,
|
||||
scopes,
|
||||
module,
|
||||
impl_block,
|
||||
resolver,
|
||||
}
|
||||
}
|
||||
|
||||
@ -940,8 +900,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
*ty = resolved;
|
||||
}
|
||||
InferenceResult {
|
||||
method_resolutions: mem::replace(&mut self.method_resolutions, Default::default()),
|
||||
field_resolutions: mem::replace(&mut self.field_resolutions, Default::default()),
|
||||
method_resolutions: self.method_resolutions,
|
||||
field_resolutions: self.field_resolutions,
|
||||
type_of_expr: expr_types,
|
||||
type_of_pat: pat_types,
|
||||
}
|
||||
@ -964,13 +924,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
}
|
||||
|
||||
fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
|
||||
// TODO provide generics of function
|
||||
let generics = GenericParams::default();
|
||||
let ty = Ty::from_hir(
|
||||
self.db,
|
||||
&self.module,
|
||||
self.impl_block.as_ref(),
|
||||
&generics,
|
||||
// TODO use right resolver for block
|
||||
&self.resolver,
|
||||
type_ref,
|
||||
);
|
||||
let ty = self.insert_type_vars(ty);
|
||||
@ -1147,38 +1104,31 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
})
|
||||
}
|
||||
|
||||
fn infer_path_expr(&mut self, expr: ExprId, path: &Path) -> Option<Ty> {
|
||||
if path.is_ident() || path.is_self() {
|
||||
// resolve locally
|
||||
let name = path.as_ident().cloned().unwrap_or_else(Name::self_param);
|
||||
if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) {
|
||||
let ty = self.type_of_pat.get(scope_entry.pat())?;
|
||||
fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> {
|
||||
let resolved = resolver.resolve_path(self.db, &path).take_values()?;
|
||||
match resolved {
|
||||
Resolution::Def { def, .. } => {
|
||||
let typable: Option<TypableDef> = def.into();
|
||||
let typable = typable?;
|
||||
let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
|
||||
let ty = self.db.type_for_def(typable).apply_substs(substs);
|
||||
let ty = self.insert_type_vars(ty);
|
||||
Some(ty)
|
||||
}
|
||||
Resolution::LocalBinding { pat } => {
|
||||
let ty = self.type_of_pat.get(pat)?;
|
||||
let ty = self.resolve_ty_as_possible(&mut vec![], ty.clone());
|
||||
return Some(ty);
|
||||
};
|
||||
};
|
||||
|
||||
// resolve in module
|
||||
let typable: Option<TypableDef> = self
|
||||
.module
|
||||
.resolve_path(self.db, &path)
|
||||
.take_values()?
|
||||
.into();
|
||||
let typable = typable?;
|
||||
let ty = self.db.type_for_def(typable);
|
||||
let generics = GenericParams::default();
|
||||
let substs = Ty::substs_from_path(
|
||||
self.db,
|
||||
&self.module,
|
||||
self.impl_block.as_ref(),
|
||||
&generics,
|
||||
path,
|
||||
typable,
|
||||
);
|
||||
let ty = ty.apply_substs(substs);
|
||||
let ty = self.insert_type_vars(ty);
|
||||
|
||||
Some(ty)
|
||||
Some(ty)
|
||||
}
|
||||
Resolution::GenericParam { .. } => {
|
||||
// generic params can't refer to values... yet
|
||||
None
|
||||
}
|
||||
Resolution::SelfType(_) => {
|
||||
log::error!("path expr {:?} resolved to Self type in values ns", path);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) {
|
||||
@ -1186,26 +1136,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
Some(path) => path,
|
||||
None => return (Ty::Unknown, None),
|
||||
};
|
||||
let typable: Option<TypableDef> = self
|
||||
.module
|
||||
.resolve_path(self.db, &path)
|
||||
.take_types()
|
||||
.and_then(|it| it.into());
|
||||
let resolver = &self.resolver;
|
||||
let typable: Option<TypableDef> = match resolver.resolve_path(self.db, &path).take_types() {
|
||||
Some(Resolution::Def { def, .. }) => def.into(),
|
||||
Some(Resolution::LocalBinding { .. }) => {
|
||||
// this cannot happen
|
||||
log::error!("path resolved to local binding in type ns");
|
||||
return (Ty::Unknown, None);
|
||||
}
|
||||
Some(Resolution::GenericParam { .. }) => {
|
||||
// generic params can't be used in struct literals
|
||||
return (Ty::Unknown, None);
|
||||
}
|
||||
Some(Resolution::SelfType(..)) => {
|
||||
// TODO this is allowed in an impl for a struct, handle this
|
||||
return (Ty::Unknown, None);
|
||||
}
|
||||
None => return (Ty::Unknown, None),
|
||||
};
|
||||
let def = match typable {
|
||||
None => return (Ty::Unknown, None),
|
||||
Some(it) => it,
|
||||
};
|
||||
// TODO remove the duplication between here and `Ty::from_path`?
|
||||
// TODO provide generics of function
|
||||
let generics = GenericParams::default();
|
||||
let substs = Ty::substs_from_path(
|
||||
self.db,
|
||||
&self.module,
|
||||
self.impl_block.as_ref(),
|
||||
&generics,
|
||||
path,
|
||||
def,
|
||||
);
|
||||
let substs = Ty::substs_from_path(self.db, resolver, path, def);
|
||||
match def {
|
||||
TypableDef::Struct(s) => {
|
||||
let ty = type_for_struct(self.db, s);
|
||||
@ -1303,12 +1257,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
path: ref p,
|
||||
args: ref fields,
|
||||
} => self.infer_struct_pat(p.as_ref(), fields, expected),
|
||||
Pat::Path(path) => self
|
||||
.module
|
||||
.resolve_path(self.db, &path)
|
||||
.take_values()
|
||||
.and_then(|module_def| module_def.into())
|
||||
.map_or(Ty::Unknown, |resolved| self.db.type_for_def(resolved)),
|
||||
Pat::Path(path) => {
|
||||
// TODO use correct resolver for the surrounding expression
|
||||
let resolver = self.resolver.clone();
|
||||
self.infer_path_expr(&resolver, &path)
|
||||
.unwrap_or(Ty::Unknown)
|
||||
}
|
||||
Pat::Bind {
|
||||
mode,
|
||||
name: _name,
|
||||
@ -1496,7 +1450,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
|
||||
expected.ty
|
||||
}
|
||||
Expr::Path(p) => self.infer_path_expr(tgt_expr, p).unwrap_or(Ty::Unknown),
|
||||
Expr::Path(p) => {
|
||||
// TODO this could be more efficient...
|
||||
let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr);
|
||||
self.infer_path_expr(&resolver, p).unwrap_or(Ty::Unknown)
|
||||
}
|
||||
Expr::Continue => Ty::Never,
|
||||
Expr::Break { expr } => {
|
||||
if let Some(expr) = expr {
|
||||
@ -1730,10 +1688,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> {
|
||||
db.check_canceled();
|
||||
let body = func.body(db);
|
||||
let scopes = db.expr_scopes(func);
|
||||
let module = func.module(db);
|
||||
let impl_block = func.impl_block(db);
|
||||
let mut ctx = InferenceContext::new(db, body, scopes, module, impl_block);
|
||||
let resolver = func.resolver(db);
|
||||
let mut ctx = InferenceContext::new(db, body, resolver);
|
||||
|
||||
let signature = func.signature(db);
|
||||
ctx.collect_fn_signature(&signature);
|
||||
|
@ -7,12 +7,10 @@ use std::sync::Arc;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{
|
||||
HirDatabase, module_tree::ModuleId, Module, ModuleDef, Crate, Name, Function, Trait,
|
||||
HirDatabase, module_tree::ModuleId, Module, Crate, Name, Function, Trait,
|
||||
ids::TraitId,
|
||||
impl_block::{ImplId, ImplBlock, ImplItem},
|
||||
generics::GenericParams,
|
||||
ty::{AdtDef, Ty},
|
||||
type_ref::TypeRef,
|
||||
};
|
||||
|
||||
/// This is used as a key for indexing impls.
|
||||
@ -85,17 +83,10 @@ impl CrateImplBlocks {
|
||||
fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) {
|
||||
let module_impl_blocks = db.impls_in_module(module.clone());
|
||||
|
||||
for (impl_id, impl_data) in module_impl_blocks.impls.iter() {
|
||||
for (impl_id, _) in module_impl_blocks.impls.iter() {
|
||||
let impl_block = ImplBlock::from_id(Arc::clone(&module_impl_blocks), impl_id);
|
||||
// TODO provide generics of impl
|
||||
let generics = GenericParams::default();
|
||||
let target_ty = Ty::from_hir(
|
||||
db,
|
||||
&module,
|
||||
Some(&impl_block),
|
||||
&generics,
|
||||
impl_data.target_type(),
|
||||
);
|
||||
|
||||
let target_ty = impl_block.target_ty(db);
|
||||
|
||||
if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
|
||||
self.impls
|
||||
@ -104,14 +95,11 @@ impl CrateImplBlocks {
|
||||
.push((module.module_id, impl_id));
|
||||
}
|
||||
|
||||
if let Some(TypeRef::Path(path)) = impl_data.target_trait() {
|
||||
let perns = module.resolve_path(db, path);
|
||||
if let Some(ModuleDef::Trait(tr)) = perns.take_types() {
|
||||
self.impls_by_trait
|
||||
.entry(tr.id)
|
||||
.or_insert_with(Vec::new)
|
||||
.push((module.module_id, impl_id));
|
||||
}
|
||||
if let Some(tr) = impl_block.target_trait(db) {
|
||||
self.impls_by_trait
|
||||
.entry(tr.id)
|
||||
.or_insert_with(Vec::new)
|
||||
.push((module.module_id, impl_id));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
---
|
||||
created: "2019-01-26T18:16:16.530712344+00:00"
|
||||
created: "2019-01-27T14:52:29.934503829+00:00"
|
||||
creator: insta@0.5.2
|
||||
expression: "&result"
|
||||
source: crates/ra_hir/src/ty/tests.rs
|
||||
---
|
||||
[10; 11) 't': [unknown]
|
||||
[21; 26) '{ t }': [unknown]
|
||||
[23; 24) 't': [unknown]
|
||||
[10; 11) 't': T
|
||||
[21; 26) '{ t }': T
|
||||
[23; 24) 't': T
|
||||
[38; 98) '{ ...(1); }': ()
|
||||
[44; 46) 'id': fn id<u32>(T) -> T
|
||||
[44; 52) 'id(1u32)': u32
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
created: "2019-01-26T17:46:03.866825843+00:00"
|
||||
created: "2019-01-27T14:52:29.938713255+00:00"
|
||||
creator: insta@0.5.2
|
||||
expression: "&result"
|
||||
source: crates/ra_hir/src/ty/tests.rs
|
||||
@ -8,9 +8,9 @@ source: crates/ra_hir/src/ty/tests.rs
|
||||
[65; 87) '{ ... }': [unknown]
|
||||
[75; 79) 'self': A<[unknown]>
|
||||
[75; 81) 'self.x': [unknown]
|
||||
[99; 100) 't': [unknown]
|
||||
[110; 115) '{ t }': [unknown]
|
||||
[112; 113) 't': [unknown]
|
||||
[99; 100) 't': T
|
||||
[110; 115) '{ t }': T
|
||||
[112; 113) 't': T
|
||||
[135; 261) '{ ....x() }': i128
|
||||
[146; 147) 'x': i32
|
||||
[150; 151) '1': i32
|
||||
|
@ -1,15 +1,15 @@
|
||||
---
|
||||
created: "2019-01-27T16:54:18.368427685+00:00"
|
||||
created: "2019-01-27T20:38:32.153717698+00:00"
|
||||
creator: insta@0.5.2
|
||||
expression: "&result"
|
||||
source: crates/ra_hir/src/ty/tests.rs
|
||||
---
|
||||
[10; 11) 'x': [unknown]
|
||||
[21; 30) '{ x }': [unknown]
|
||||
[27; 28) 'x': [unknown]
|
||||
[44; 45) 'x': &[unknown]
|
||||
[56; 65) '{ x }': &[unknown]
|
||||
[62; 63) 'x': &[unknown]
|
||||
[10; 11) 'x': T
|
||||
[21; 30) '{ x }': T
|
||||
[27; 28) 'x': T
|
||||
[44; 45) 'x': &T
|
||||
[56; 65) '{ x }': &T
|
||||
[62; 63) 'x': &T
|
||||
[77; 157) '{ ...(1); }': ()
|
||||
[87; 88) 'y': u32
|
||||
[91; 96) '10u32': u32
|
||||
|
Loading…
Reference in New Issue
Block a user