From 6b076f1931d7dc324d7bbbc4c1df9f7c1c1db8b7 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 26 Jan 2019 22:52:04 +0100 Subject: Use new Resolver API in type inference --- crates/ra_hir/src/code_model_api.rs | 39 ++- crates/ra_hir/src/expr.rs | 3 - crates/ra_hir/src/impl_block.rs | 27 ++- crates/ra_hir/src/lib.rs | 4 +- crates/ra_hir/src/nameres.rs | 23 +- crates/ra_hir/src/nameres/tests.rs | 3 +- crates/ra_hir/src/resolve.rs | 116 ++++++--- crates/ra_hir/src/ty.rs | 270 +++++++++------------ crates/ra_hir/src/ty/method_resolution.rs | 30 +-- .../snapshots/tests__infer_function_generics.snap | 8 +- .../ty/snapshots/tests__infer_generic_chain.snap | 8 +- .../src/ty/snapshots/tests__infer_type_param.snap | 14 +- 12 files changed, 295 insertions(+), 250 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index b8ca04c5c..92ab0f692 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs @@ -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 { - // 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, 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 { diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index c09d3fbf9..503a09f25 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -75,9 +75,6 @@ impl Body { #[allow(dead_code)] pub fn resolver_for_expr(body: Arc, 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::>(); for scope in scope_chain.into_iter().rev() { diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 5fa49d456..a3908048b 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -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 { + 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() } diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index e58658378..54da55598 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -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::{ diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index e825ec089..193c6a977 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -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 for ItemMap { #[derive(Debug, Default, PartialEq, Eq, Clone)] pub struct ModuleScope { - items: FxHashMap, + pub(crate) items: FxHashMap, } impl ModuleScope { @@ -113,6 +114,10 @@ impl PerNs { 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 { match namespace { Namespace::Types => self.types, @@ -139,6 +144,13 @@ impl PerNs { } } + pub fn combine(self, other: PerNs) -> PerNs { + PerNs { + types: self.types.or(other.types), + values: self.values.or(other.values), + } + } + pub fn and_then(self, f: impl Fn(T) -> Option) -> PerNs { 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); } diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 1ce7bd146..0e0683db7 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs @@ -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, ModuleId) { let (db, pos) = MockDatabase::with_position(fixture); diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index b7fbf6df2..36daed65b 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -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, // 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, } // TODO how to store these best #[derive(Debug, Clone)] pub(crate) struct ModuleItemMap { item_map: Arc, - 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), - /// Brings the function parameters into scope - FunctionParams(Arc), /// 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, }, /// 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 { + 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 { - unimplemented!() + pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs { + 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 { 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, module_id: ModuleId) -> Resolver { - self.push_scope(Scope::ModuleScope(ModuleItemMap { - item_map, - module_id, - })) + pub(crate) fn push_module_scope(self, item_map: Arc, 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) -> 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 { - 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(), + } + } + } } } diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index d3e31981a..d9c62f84c 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -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::>(); 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::>(); 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) { + } + } + + // 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: generic_param.idx, - name: generic_param.name.clone(), + 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, + }; - // Resolve in module (in type namespace) - let typable: TypableDef = match module - .resolve_path(db, path) - .take_types() - .and_then(|it| it.into()) - { + 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::>(); - 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 for InferenceResult { struct InferenceContext<'a, D: HirDatabase> { db: &'a D, body: Arc, - scopes: Arc, - module: Module, - impl_block: Option, + resolver: Resolver, var_unification_table: InPlaceUnificationTable, method_resolutions: FxHashMap, field_resolutions: FxHashMap, @@ -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, - scopes: Arc, - module: Module, - impl_block: Option, - ) -> Self { + fn new(db: &'a D, body: Arc, 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 { - 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 { + let resolved = resolver.resolve_path(self.db, &path).take_values()?; + match resolved { + Resolution::Def { def, .. } => { + let typable: Option = 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 = 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) { @@ -1186,26 +1136,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Some(path) => path, None => return (Ty::Unknown, None), }; - let typable: Option = self - .module - .resolve_path(self.db, &path) - .take_types() - .and_then(|it| it.into()); + let resolver = &self.resolver; + let typable: Option = 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 { 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); diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index e857d6856..2282286b0 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -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)); } } diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_function_generics.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_function_generics.snap index 8ff6e55a6..91c48897c 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_function_generics.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_function_generics.snap @@ -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(T) -> T [44; 52) 'id(1u32)': u32 diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap index f21bffa75..626f31252 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap @@ -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 diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_type_param.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_type_param.snap index a99323264..216d1e41f 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_type_param.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_type_param.snap @@ -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 -- cgit v1.2.3