Functions use new id scheme

This commit is contained in:
Aleksey Kladov 2019-01-24 15:28:50 +03:00
parent f1959bbae0
commit ec7ed054e0
13 changed files with 297 additions and 201 deletions

View File

@ -16,6 +16,7 @@ use crate::{
code_model_impl::def_id_to_ast,
docs::{Documentation, Docs, docs_from_ast},
module_tree::ModuleId,
ids::FunctionId,
};
/// hir::Crate describes a single crate. It's the main interface with which
@ -49,7 +50,6 @@ pub enum Def {
Struct(Struct),
Enum(Enum),
EnumVariant(EnumVariant),
Function(Function),
Const(Const),
Static(Static),
Trait(Trait),
@ -67,6 +67,7 @@ pub struct Module {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ModuleDef {
Module(Module),
Function(Function),
Def(DefId),
}
@ -76,6 +77,12 @@ impl Into<ModuleDef> for Module {
}
}
impl Into<ModuleDef> for Function {
fn into(self) -> ModuleDef {
ModuleDef::Function(self)
}
}
impl Into<ModuleDef> for DefId {
fn into(self) -> ModuleDef {
ModuleDef::Def(self)
@ -225,7 +232,7 @@ impl Struct {
}
pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> {
db.generic_params(self.def_id)
db.generic_params(self.def_id.into())
}
}
@ -262,7 +269,7 @@ impl Enum {
}
pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> {
db.generic_params(self.def_id)
db.generic_params(self.def_id.into())
}
}
@ -320,9 +327,9 @@ impl Docs for EnumVariant {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Function {
pub(crate) def_id: DefId,
pub(crate) id: FunctionId,
}
pub use crate::code_model_impl::function::ScopeEntryWithSyntax;
@ -359,21 +366,17 @@ impl FnSignature {
}
impl Function {
pub fn def_id(&self) -> DefId {
self.def_id
}
pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::FnDef>) {
def_id_to_ast(db, self.def_id)
self.id.loc(db).source(db)
}
pub fn body_syntax_mapping(&self, db: &impl HirDatabase) -> Arc<BodySyntaxMapping> {
db.body_syntax_mapping(self.def_id)
db.body_syntax_mapping(*self)
}
pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSyntaxMapping {
let scopes = db.fn_scopes(self.def_id);
let syntax_mapping = db.body_syntax_mapping(self.def_id);
let scopes = db.fn_scopes(*self);
let syntax_mapping = db.body_syntax_mapping(*self);
ScopesWithSyntaxMapping {
scopes,
syntax_mapping,
@ -381,15 +384,15 @@ impl Function {
}
pub fn signature(&self, db: &impl HirDatabase) -> Arc<FnSignature> {
db.fn_signature(self.def_id)
db.fn_signature(*self)
}
pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> {
db.infer(self.def_id)
db.infer(*self)
}
pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> {
db.generic_params(self.def_id)
db.generic_params((*self).into())
}
}
@ -456,7 +459,7 @@ impl Trait {
}
pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> {
db.generic_params(self.def_id)
db.generic_params(self.def_id.into())
}
}
@ -481,7 +484,7 @@ impl Type {
}
pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> {
db.generic_params(self.def_id)
db.generic_params(self.def_id.into())
}
}

View File

@ -2,41 +2,48 @@ mod scope;
use std::sync::Arc;
use ra_syntax::{TreeArc, ast::{self, NameOwner}};
use ra_syntax::ast::{self, NameOwner};
use crate::{
DefId, HirDatabase, Name, AsName, Function, FnSignature, Module,
HirDatabase, Name, AsName, Function, FnSignature, Module, HirFileId,
type_ref::{TypeRef, Mutability},
expr::Body,
impl_block::ImplBlock,
code_model_impl::def_id_to_ast,
ids::FunctionLoc,
};
pub use self::scope::{FnScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax};
impl Function {
pub(crate) fn new(def_id: DefId) -> Function {
Function { def_id }
pub(crate) fn from_ast(
db: &impl HirDatabase,
module: Module,
file_id: HirFileId,
ast: &ast::FnDef,
) -> Function {
let loc: FunctionLoc = FunctionLoc::from_ast(db, module, file_id, ast);
let id = loc.id(db);
Function { id }
}
pub(crate) fn body(&self, db: &impl HirDatabase) -> Arc<Body> {
db.body_hir(self.def_id)
db.body_hir(*self)
}
pub(crate) fn module(&self, db: &impl HirDatabase) -> Module {
self.def_id.module(db)
self.id.loc(db).module
}
/// The containing impl block, if this is a method.
pub(crate) fn impl_block(&self, db: &impl HirDatabase) -> Option<ImplBlock> {
self.def_id.impl_block(db)
let module_impls = db.impls_in_module(self.module(db));
ImplBlock::containing(module_impls, (*self).into())
}
}
impl FnSignature {
pub(crate) fn fn_signature_query(db: &impl HirDatabase, def_id: DefId) -> Arc<FnSignature> {
// FIXME: we're using def_id_to_ast here to avoid returning Cancelable... this is a bit hacky
let node: TreeArc<ast::FnDef> = def_id_to_ast(db, def_id).1;
pub(crate) fn fn_signature_query(db: &impl HirDatabase, func: Function) -> Arc<FnSignature> {
let (_, node) = func.source(db);
let name = node
.name()
.map(|n| n.as_name())

View File

@ -135,6 +135,7 @@ impl Module {
None => PerNs::none(),
}
}
ModuleDef::Function(_) => PerNs::none(),
ModuleDef::Def(def) => {
match def.resolve(db) {
Def::Enum(e) => {

View File

@ -7,14 +7,14 @@ use crate::{
DefId, MacroCallId, Name, HirFileId,
SourceFileItems, SourceItemId, Crate, Module, HirInterner,
query_definitions,
FnSignature, FnScopes,
Function, FnSignature, FnScopes,
macros::MacroExpansion,
module_tree::ModuleTree,
nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks},
ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef},
adt::{StructData, EnumData, EnumVariantData},
impl_block::ModuleImplBlocks,
generics::GenericParams,
generics::{GenericParams, GenericDef},
};
#[salsa::query_group]
@ -26,7 +26,7 @@ pub trait HirDatabase: SyntaxDatabase + AsRef<HirInterner> {
fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option<Arc<MacroExpansion>>;
#[salsa::invoke(query_definitions::fn_scopes)]
fn fn_scopes(&self, def_id: DefId) -> Arc<FnScopes>;
fn fn_scopes(&self, func: Function) -> Arc<FnScopes>;
#[salsa::invoke(crate::adt::StructData::struct_data_query)]
fn struct_data(&self, def_id: DefId) -> Arc<StructData>;
@ -38,10 +38,10 @@ pub trait HirDatabase: SyntaxDatabase + AsRef<HirInterner> {
fn enum_variant_data(&self, def_id: DefId) -> Arc<EnumVariantData>;
#[salsa::invoke(crate::ty::infer)]
fn infer(&self, def_id: DefId) -> Arc<InferenceResult>;
fn infer(&self, func: Function) -> Arc<InferenceResult>;
#[salsa::invoke(crate::ty::type_for_def)]
fn type_for_def(&self, def_id: DefId) -> Ty;
fn type_for_def(&self, def: TypableDef) -> Ty;
#[salsa::invoke(crate::ty::type_for_field)]
fn type_for_field(&self, def_id: DefId, field: Name) -> Option<Ty>;
@ -77,14 +77,14 @@ pub trait HirDatabase: SyntaxDatabase + AsRef<HirInterner> {
fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>;
#[salsa::invoke(crate::expr::body_hir)]
fn body_hir(&self, def_id: DefId) -> Arc<crate::expr::Body>;
fn body_hir(&self, func: Function) -> Arc<crate::expr::Body>;
#[salsa::invoke(crate::expr::body_syntax_mapping)]
fn body_syntax_mapping(&self, def_id: DefId) -> Arc<crate::expr::BodySyntaxMapping>;
fn body_syntax_mapping(&self, func: Function) -> Arc<crate::expr::BodySyntaxMapping>;
#[salsa::invoke(crate::generics::GenericParams::generic_params_query)]
fn generic_params(&self, def_id: DefId) -> Arc<GenericParams>;
fn generic_params(&self, def: GenericDef) -> Arc<GenericParams>;
#[salsa::invoke(crate::FnSignature::fn_signature_query)]
fn fn_signature(&self, def_id: DefId) -> Arc<FnSignature>;
fn fn_signature(&self, func: Function) -> Arc<FnSignature>;
}

View File

@ -9,7 +9,11 @@ use ra_syntax::{
ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralFlavor}
};
use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName};
use crate::{
Path, Name, HirDatabase, Function,
name::AsName,
type_ref::{Mutability, TypeRef},
};
use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -435,8 +439,8 @@ impl Pat {
// Queries
pub(crate) fn body_hir(db: &impl HirDatabase, def_id: DefId) -> Arc<Body> {
Arc::clone(&body_syntax_mapping(db, def_id).body)
pub(crate) fn body_hir(db: &impl HirDatabase, func: Function) -> Arc<Body> {
Arc::clone(&body_syntax_mapping(db, func).body)
}
struct ExprCollector {
@ -955,14 +959,8 @@ pub(crate) fn collect_fn_body_syntax(node: &ast::FnDef) -> BodySyntaxMapping {
collector.into_body_syntax_mapping(params, body)
}
pub(crate) fn body_syntax_mapping(db: &impl HirDatabase, def_id: DefId) -> Arc<BodySyntaxMapping> {
let def = def_id.resolve(db);
let body_syntax_mapping = match def {
Def::Function(f) => collect_fn_body_syntax(&f.source(db).1),
// TODO: consts, etc.
_ => panic!("Trying to get body for item type without body"),
};
pub(crate) fn body_syntax_mapping(db: &impl HirDatabase, func: Function) -> Arc<BodySyntaxMapping> {
let (_, fn_def) = func.source(db);
let body_syntax_mapping = collect_fn_body_syntax(&fn_def);
Arc::new(body_syntax_mapping)
}

View File

@ -5,9 +5,9 @@
use std::sync::Arc;
use ra_syntax::ast::{TypeParamList, AstNode, NameOwner};
use ra_syntax::ast::{self, AstNode, NameOwner, TypeParamsOwner};
use crate::{db::HirDatabase, DefId, Name, AsName};
use crate::{db::HirDatabase, DefId, Name, AsName, Function};
/// Data about a generic parameter (to a function, struct, impl, ...).
#[derive(Clone, PartialEq, Eq, Debug)]
@ -22,26 +22,62 @@ pub struct GenericParams {
pub(crate) params: Vec<GenericParam>,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum GenericDef {
Function(Function),
Def(DefId),
}
impl From<Function> for GenericDef {
fn from(func: Function) -> GenericDef {
GenericDef::Function(func)
}
}
impl From<DefId> for GenericDef {
fn from(def_id: DefId) -> GenericDef {
GenericDef::Def(def_id)
}
}
impl GenericParams {
pub(crate) fn generic_params_query(db: &impl HirDatabase, def_id: DefId) -> Arc<GenericParams> {
let (_file_id, node) = def_id.source(db);
pub(crate) fn generic_params_query(
db: &impl HirDatabase,
def: GenericDef,
) -> Arc<GenericParams> {
let mut generics = GenericParams::default();
if let Some(type_param_list) = node.children().find_map(TypeParamList::cast) {
for (idx, type_param) in type_param_list.type_params().enumerate() {
let name = type_param
.name()
.map(AsName::as_name)
.unwrap_or_else(Name::missing);
let param = GenericParam {
idx: idx as u32,
name,
};
generics.params.push(param);
match def {
GenericDef::Function(func) => {
let (_, fn_def) = func.source(db);
if let Some(type_param_list) = fn_def.type_param_list() {
generics.fill(type_param_list)
}
}
GenericDef::Def(def_id) => {
let (_file_id, node) = def_id.source(db);
if let Some(type_param_list) = node.children().find_map(ast::TypeParamList::cast) {
generics.fill(type_param_list)
}
}
}
Arc::new(generics)
}
fn fill(&mut self, params: &ast::TypeParamList) {
for (idx, type_param) in params.type_params().enumerate() {
let name = type_param
.name()
.map(AsName::as_name)
.unwrap_or_else(Name::missing);
let param = GenericParam {
idx: idx as u32,
name,
};
self.params.push(param);
}
}
pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
self.params.iter().find(|p| &p.name == name)
}

View File

@ -1,9 +1,11 @@
use std::marker::PhantomData;
use ra_db::{LocationIntener, FileId};
use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, ast};
use ra_arena::{Arena, RawId, impl_arena_id};
use crate::{
HirDatabase, Def, Function, Struct, Enum, EnumVariant, ImplBlock, Crate,
HirDatabase, Def, Struct, Enum, EnumVariant, Crate,
Module, Trait, Type, Static, Const,
};
@ -129,15 +131,56 @@ impl MacroCallLoc {
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ItemLoc<N: AstNode> {
pub(crate) module: Module,
raw: SourceItemId,
_ty: PhantomData<N>,
}
impl<N: AstNode> ItemLoc<N> {
pub(crate) fn from_ast(
db: &impl HirDatabase,
module: Module,
file_id: HirFileId,
ast: &N,
) -> ItemLoc<N> {
let items = db.file_items(file_id);
let raw = SourceItemId {
file_id,
item_id: Some(items.id_of(file_id, ast.syntax())),
};
ItemLoc {
module,
raw,
_ty: PhantomData,
}
}
pub(crate) fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<N>) {
let syntax = db.file_item(self.raw);
let ast = N::cast(&syntax)
.unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", self.raw))
.to_owned();
(self.raw.file_id, ast)
}
}
impl<N: AstNode> Clone for ItemLoc<N> {
fn clone(&self) -> ItemLoc<N> {
ItemLoc {
module: self.module,
raw: self.raw,
_ty: PhantomData,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FunctionId(RawId);
impl_arena_id!(FunctionId);
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct FunctionLoc {
pub(crate) module: Module,
pub(crate) source_item_id: SourceItemId,
}
pub(crate) type FunctionLoc = ItemLoc<ast::FnDef>;
impl FunctionId {
pub(crate) fn loc(self, db: &impl AsRef<HirInterner>) -> FunctionLoc {
@ -196,10 +239,7 @@ impl DefId {
pub fn resolve(self, db: &impl HirDatabase) -> Def {
let loc = self.loc(db);
match loc.kind {
DefKind::Function => {
let function = Function::new(self);
Def::Function(function)
}
DefKind::Function => unreachable!(),
DefKind::Struct => {
let struct_def = Struct::new(self);
Def::Struct(struct_def)
@ -243,12 +283,6 @@ impl DefId {
pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
self.module(db).krate(db)
}
/// Returns the containing impl block, if this is an impl item.
pub fn impl_block(self, db: &impl HirDatabase) -> Option<ImplBlock> {
let module_impls = db.impls_in_module(self.loc(db).module);
ImplBlock::containing(module_impls, self)
}
}
impl DefLoc {

View File

@ -6,7 +6,7 @@ use ra_syntax::ast::{self, AstNode};
use crate::{
DefId, DefLoc, DefKind, SourceItemId, SourceFileItems,
Function, HirFileId, HirInterner,
Function, HirFileId,
db::HirDatabase,
type_ref::TypeRef,
};
@ -22,9 +22,9 @@ pub struct ImplBlock {
impl ImplBlock {
pub(crate) fn containing(
module_impl_blocks: Arc<ModuleImplBlocks>,
def_id: DefId,
item: ImplItem,
) -> Option<ImplBlock> {
let impl_id = *module_impl_blocks.impls_by_def.get(&def_id)?;
let impl_id = *module_impl_blocks.impls_by_def.get(&item)?;
Some(ImplBlock {
module_impl_blocks,
impl_id,
@ -64,7 +64,7 @@ pub struct ImplData {
impl ImplData {
pub(crate) fn from_ast(
db: &impl AsRef<HirInterner>,
db: &impl HirDatabase,
file_id: HirFileId,
file_items: &SourceFileItems,
module: Module,
@ -93,7 +93,9 @@ impl ImplData {
};
let def_id = def_loc.id(db);
match item_node.kind() {
ast::ImplItemKind::FnDef(..) => ImplItem::Method(Function::new(def_id)),
ast::ImplItemKind::FnDef(it) => {
ImplItem::Method(Function::from_ast(db, module, file_id, it))
}
ast::ImplItemKind::ConstDef(..) => ImplItem::Const(def_id),
ast::ImplItemKind::TypeDef(..) => ImplItem::Type(def_id),
}
@ -122,7 +124,8 @@ impl ImplData {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
//TODO: rename to ImplDef?
pub enum ImplItem {
Method(Function),
// these don't have their own types yet
@ -131,13 +134,9 @@ pub enum ImplItem {
// Existential
}
impl ImplItem {
pub fn def_id(&self) -> DefId {
match self {
ImplItem::Method(f) => f.def_id(),
ImplItem::Const(def_id) => *def_id,
ImplItem::Type(def_id) => *def_id,
}
impl From<Function> for ImplItem {
fn from(func: Function) -> ImplItem {
ImplItem::Method(func)
}
}
@ -153,7 +152,7 @@ impl_arena_id!(ImplId);
#[derive(Debug, PartialEq, Eq)]
pub struct ModuleImplBlocks {
pub(crate) impls: Arena<ImplId, ImplData>,
impls_by_def: FxHashMap<DefId, ImplId>,
impls_by_def: FxHashMap<ImplItem, ImplId>,
}
impl ModuleImplBlocks {
@ -181,8 +180,8 @@ impl ModuleImplBlocks {
let impl_block =
ImplData::from_ast(db, file_id, &source_file_items, module, impl_block_ast);
let id = self.impls.alloc(impl_block);
for impl_item in &self.impls[id].items {
self.impls_by_def.insert(impl_item.def_id(), id);
for &impl_item in &self.impls[id].items {
self.impls_by_def.insert(impl_item, id);
}
}
}

View File

@ -9,7 +9,7 @@ use rustc_hash::FxHashMap;
use crate::{
SourceItemId, Path, ModuleSource, HirDatabase, Name, SourceFileItems,
HirFileId, MacroCallLoc, AsName, PerNs, DefKind, DefLoc,
HirFileId, MacroCallLoc, AsName, PerNs, DefKind, DefLoc, Function,
ModuleDef, Module,
};
@ -149,7 +149,14 @@ impl LoweredModule {
let name = match item.kind() {
ast::ModuleItemKind::StructDef(it) => it.name(),
ast::ModuleItemKind::EnumDef(it) => it.name(),
ast::ModuleItemKind::FnDef(it) => it.name(),
ast::ModuleItemKind::FnDef(it) => {
if let Some(name) = it.name() {
let func = Function::from_ast(db, module, file_id, it);
self.declarations
.insert(name.as_name(), PerNs::values(func.into()));
}
return;
}
ast::ModuleItemKind::TraitDef(it) => it.name(),
ast::ModuleItemKind::TypeDef(it) => it.name(),
ast::ModuleItemKind::ImplBlock(_) => {
@ -218,7 +225,7 @@ fn assign_def_id(
impl DefKind {
fn for_syntax_kind(kind: SyntaxKind) -> PerNs<DefKind> {
match kind {
SyntaxKind::FN_DEF => PerNs::values(DefKind::Function),
SyntaxKind::FN_DEF => unreachable!(),
SyntaxKind::STRUCT_DEF => PerNs::both(DefKind::Struct, DefKind::StructCtor),
SyntaxKind::ENUM_DEF => PerNs::types(DefKind::Enum),
SyntaxKind::TRAIT_DEF => PerNs::types(DefKind::Trait),

View File

@ -10,14 +10,14 @@ use ra_syntax::{
use ra_db::{CrateId};
use crate::{
SourceFileItems, SourceItemId, DefId, HirFileId,
FnScopes, Module,
SourceFileItems, SourceItemId, HirFileId,
Function, FnScopes, Module,
db::HirDatabase,
nameres::{ItemMap, Resolver},
};
pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Arc<FnScopes> {
let body = db.body_hir(def_id);
pub(super) fn fn_scopes(db: &impl HirDatabase, func: Function) -> Arc<FnScopes> {
let body = db.body_hir(func);
let res = FnScopes::new(body);
Arc::new(res)
}

View File

@ -14,7 +14,7 @@ use ra_syntax::{
use crate::{
HirDatabase, Function, SourceItemId, ModuleDef,
DefKind, DefLoc, AsName, Module,
AsName, Module,
};
/// Locates the module by `FileId`. Picks topmost module in the file.
@ -105,29 +105,18 @@ pub fn function_from_source(
fn_def: &ast::FnDef,
) -> Option<Function> {
let module = module_from_child_node(db, file_id, fn_def.syntax())?;
let res = function_from_module(db, &module, fn_def);
let res = function_from_module(db, module, fn_def);
Some(res)
}
pub fn function_from_module(
db: &impl HirDatabase,
module: &Module,
module: Module,
fn_def: &ast::FnDef,
) -> Function {
let (file_id, _) = module.definition_source(db);
let file_id = file_id.into();
let file_items = db.file_items(file_id);
let item_id = file_items.id_of(file_id, fn_def.syntax());
let source_item_id = SourceItemId {
file_id,
item_id: Some(item_id),
};
let def_loc = DefLoc {
module: module.clone(),
kind: DefKind::Function,
source_item_id,
};
Function::new(def_loc.id(db))
Function::from_ast(db, module, file_id, fn_def)
}
pub fn function_from_child_node(

View File

@ -382,7 +382,8 @@ impl Ty {
// Resolve in module (in type namespace)
let resolved = match module.resolve_path(db, path).take_types() {
Some(ModuleDef::Def(r)) => r,
Some(ModuleDef::Def(r)) => r.into(),
Some(ModuleDef::Function(f)) => f.into(),
None | Some(ModuleDef::Module(_)) => return Ty::Unknown,
};
let ty = db.type_for_def(resolved);
@ -399,36 +400,38 @@ impl Ty {
impl_block: Option<&ImplBlock>,
outer_generics: &GenericParams,
path: &Path,
resolved: DefId,
resolved: TypableDef,
) -> Substs {
let mut substs = Vec::new();
let def = resolved.resolve(db);
let last = path
.segments
.last()
.expect("path should have at least one segment");
let (def_generics, segment) = match def {
Def::Struct(s) => (s.generic_params(db), last),
Def::Enum(e) => (e.generic_params(db), last),
Def::Function(f) => (f.generic_params(db), last),
Def::Trait(t) => (t.generic_params(db), last),
Def::EnumVariant(ev) => {
// the generic args for an enum variant may be either specified
// on the segment referring to the enum, or on the segment
// referring to the variant. So `Option::<T>::None` and
// `Option::None::<T>` are both allowed (though the former is
// preferred). See also `def_ids_for_path_segments` in rustc.
let len = path.segments.len();
let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() {
// Option::<T>::None
&path.segments[len - 2]
} else {
// Option::None::<T>
last
};
(ev.parent_enum(db).generic_params(db), segment)
}
_ => return Substs::empty(),
let (def_generics, segment) = match resolved {
TypableDef::Function(func) => (func.generic_params(db), last),
TypableDef::Def(def_id) => match def_id.resolve(db) {
Def::Struct(s) => (s.generic_params(db), last),
Def::Enum(e) => (e.generic_params(db), last),
Def::Trait(t) => (t.generic_params(db), last),
Def::EnumVariant(ev) => {
// the generic args for an enum variant may be either specified
// on the segment referring to the enum, or on the segment
// referring to the variant. So `Option::<T>::None` and
// `Option::None::<T>` are both allowed (though the former is
// preferred). See also `def_ids_for_path_segments` in rustc.
let len = path.segments.len();
let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some()
{
// Option::<T>::None
&path.segments[len - 2]
} else {
// Option::None::<T>
last
};
(ev.parent_enum(db).generic_params(db), segment)
}
_ => return Substs::empty(),
},
};
// substs_from_path
if let Some(generic_args) = &segment.args_and_bindings {
@ -660,21 +663,40 @@ pub(crate) fn type_for_enum_variant(db: &impl HirDatabase, ev: EnumVariant) -> T
type_for_enum(db, enum_parent)
}
pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Ty {
let def = def_id.resolve(db);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum TypableDef {
Function(Function),
Def(DefId),
}
impl From<Function> for TypableDef {
fn from(func: Function) -> TypableDef {
TypableDef::Function(func)
}
}
impl From<DefId> for TypableDef {
fn from(func: DefId) -> TypableDef {
TypableDef::Def(func)
}
}
pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty {
match def {
Def::Function(f) => type_for_fn(db, f),
Def::Struct(s) => type_for_struct(db, s),
Def::Enum(e) => type_for_enum(db, e),
Def::EnumVariant(ev) => type_for_enum_variant(db, ev),
_ => {
log::debug!(
"trying to get type for item of unknown type {:?} {:?}",
def_id,
def
);
Ty::Unknown
}
TypableDef::Function(f) => type_for_fn(db, f),
TypableDef::Def(def_id) => match def_id.resolve(db) {
Def::Struct(s) => type_for_struct(db, s),
Def::Enum(e) => type_for_enum(db, e),
Def::EnumVariant(ev) => type_for_enum_variant(db, ev),
_ => {
log::debug!(
"trying to get type for item of unknown type {:?} {:?}",
def_id,
def
);
Ty::Unknown
}
},
}
}
@ -694,28 +716,23 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name)
),
};
let module = def_id.module(db);
let impl_block = def_id.impl_block(db);
// We can't have an impl block ere, right?
// let impl_block = def_id.impl_block(db);
let type_ref = variant_data.get_field_type_ref(&field)?;
Some(Ty::from_hir(
db,
&module,
impl_block.as_ref(),
&generics,
&type_ref,
))
Some(Ty::from_hir(db, &module, None, &generics, &type_ref))
}
/// The result of type inference: A mapping from expressions and patterns to types.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct InferenceResult {
/// For each method call expr, record the function it resolved to.
method_resolutions: FxHashMap<ExprId, DefId>,
method_resolutions: FxHashMap<ExprId, Function>,
type_of_expr: ArenaMap<ExprId, Ty>,
type_of_pat: ArenaMap<PatId, Ty>,
}
impl InferenceResult {
pub fn method_resolution(&self, expr: ExprId) -> Option<DefId> {
pub fn method_resolution(&self, expr: ExprId) -> Option<Function> {
self.method_resolutions.get(&expr).map(|it| *it)
}
}
@ -745,7 +762,7 @@ struct InferenceContext<'a, D: HirDatabase> {
module: Module,
impl_block: Option<ImplBlock>,
var_unification_table: InPlaceUnificationTable<TypeVarId>,
method_resolutions: FxHashMap<ExprId, DefId>,
method_resolutions: FxHashMap<ExprId, Function>,
type_of_expr: ArenaMap<ExprId, Ty>,
type_of_pat: ArenaMap<PatId, Ty>,
/// The return type of the function being inferred.
@ -871,8 +888,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
self.type_of_expr.insert(expr, ty);
}
fn write_method_resolution(&mut self, expr: ExprId, def_id: DefId) {
self.method_resolutions.insert(expr, def_id);
fn write_method_resolution(&mut self, expr: ExprId, func: Function) {
self.method_resolutions.insert(expr, func);
}
fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
@ -1060,7 +1077,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
// resolve in module
let resolved = match self.module.resolve_path(self.db, &path).take_values()? {
ModuleDef::Def(it) => it,
ModuleDef::Def(it) => it.into(),
ModuleDef::Function(func) => func.into(),
ModuleDef::Module(_) => return None,
};
let ty = self.db.type_for_def(resolved);
@ -1073,8 +1091,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Some(path) => path,
None => return (Ty::Unknown, None),
};
let def_id = match self.module.resolve_path(self.db, &path).take_types() {
Some(ModuleDef::Def(def_id)) => def_id,
let def = match self.module.resolve_path(self.db, &path).take_types() {
Some(ModuleDef::Def(def_id)) => def_id.into(),
Some(ModuleDef::Function(func)) => func.into(),
_ => return (Ty::Unknown, None),
};
// TODO remove the duplication between here and `Ty::from_path`?
@ -1086,20 +1105,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
self.impl_block.as_ref(),
&generics,
path,
def_id,
def,
);
match def_id.resolve(self.db) {
Def::Struct(s) => {
let ty = type_for_struct(self.db, s);
let ty = self.insert_type_vars(ty.apply_substs(substs));
(ty, Some(def_id))
}
Def::EnumVariant(ev) => {
let ty = type_for_enum_variant(self.db, ev);
let ty = self.insert_type_vars(ty.apply_substs(substs));
(ty, Some(def_id))
}
_ => (Ty::Unknown, None),
match def {
TypableDef::Def(def_id) => match def_id.resolve(self.db) {
Def::Struct(s) => {
let ty = type_for_struct(self.db, s);
let ty = self.insert_type_vars(ty.apply_substs(substs));
(ty, Some(def_id))
}
Def::EnumVariant(ev) => {
let ty = type_for_enum_variant(self.db, ev);
let ty = self.insert_type_vars(ty.apply_substs(substs));
(ty, Some(def_id))
}
_ => (Ty::Unknown, None),
},
TypableDef::Function(_) => (Ty::Unknown, None),
}
}
@ -1216,7 +1238,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
.resolve_path(self.db, &path)
.take_values()
.and_then(|module_def| match module_def {
ModuleDef::Def(it) => Some(it),
ModuleDef::Def(it) => Some(it.into()),
ModuleDef::Function(func) => Some(func.into()),
ModuleDef::Module(_) => None,
})
.map_or(Ty::Unknown, |resolved| self.db.type_for_def(resolved)),
@ -1339,9 +1362,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
let resolved = receiver_ty.clone().lookup_method(self.db, method_name);
let method_ty = match resolved {
Some(def_id) => {
self.write_method_resolution(expr, def_id);
self.db.type_for_def(def_id)
Some(func) => {
self.write_method_resolution(expr, func);
self.db.type_for_def(func.into())
}
None => Ty::Unknown,
};
@ -1610,16 +1633,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
}
}
pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Arc<InferenceResult> {
pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> {
db.check_canceled();
let function = Function::new(def_id); // TODO: consts also need inference
let body = function.body(db);
let scopes = db.fn_scopes(def_id);
let module = function.module(db);
let impl_block = function.impl_block(db);
let body = func.body(db);
let scopes = db.fn_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 signature = function.signature(db);
let signature = func.signature(db);
ctx.collect_fn_signature(&signature);
ctx.infer_body();

View File

@ -118,11 +118,11 @@ impl Ty {
// TODO: cache this as a query?
// - if so, what signature? (TyFingerprint, Name)?
// - or maybe cache all names and def_ids of methods per fingerprint?
pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<DefId> {
pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<Function> {
self.iterate_methods(db, |f| {
let sig = f.signature(db);
if sig.name() == name && sig.has_self_param() {
Some(f.def_id())
Some(f)
} else {
None
}