From ff0312fa32715ce42f134fd9f049c4df5956d042 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 16 Jul 2020 13:00:56 +0200 Subject: Semantical call info --- crates/ra_hir/src/code_model.rs | 76 ++++++++++++++++++++++++++++++++---- crates/ra_hir/src/lib.rs | 13 +++--- crates/ra_hir/src/semantics.rs | 25 +++++++++--- crates/ra_hir/src/source_analyzer.rs | 6 +-- 4 files changed, 99 insertions(+), 21 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 9891b0785..057dfb82a 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -1,5 +1,5 @@ //! FIXME: write short doc here -use std::sync::Arc; +use std::{iter, sync::Arc}; use arrayvec::ArrayVec; use either::Either; @@ -12,6 +12,7 @@ use hir_def::{ import_map, per_ns::PerNs, resolver::{HasResolver, Resolver}, + src::HasSource as _, type_ref::{Mutability, TypeRef}, AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, @@ -25,8 +26,8 @@ use hir_expand::{ use hir_ty::{ autoderef, display::{HirDisplayError, HirFormatter}, - method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, - TraitEnvironment, Ty, TyDefId, TypeCtor, + method_resolution, ApplicationTy, CallableDefId, Canonical, FnSig, GenericPredicate, + InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, }; use ra_db::{CrateId, Edition, FileId}; use ra_prof::profile; @@ -40,7 +41,7 @@ use stdx::impl_from; use crate::{ db::{DefDatabase, HirDatabase}, has_source::HasSource, - CallableDefId, HirDisplay, InFile, Name, + HirDisplay, InFile, Name, }; /// hir::Crate describes a single crate. It's the main interface with which @@ -1168,6 +1169,12 @@ impl Type { Type::new(db, krate, def, ty) } + pub fn is_unit(&self) -> bool { + matches!( + self.ty.value, + Ty::Apply(ApplicationTy { ctor: TypeCtor::Tuple { cardinality: 0 }, .. }) + ) + } pub fn is_bool(&self) -> bool { matches!(self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. })) } @@ -1225,9 +1232,10 @@ impl Type { db.trait_solve(self.krate, goal).is_some() } - // FIXME: this method is broken, as it doesn't take closures into account. - pub fn as_callable(&self) -> Option { - Some(self.ty.value.as_callable()?.0) + pub fn as_callable(&self, db: &dyn HirDatabase) -> Option { + let (id, substs) = self.ty.value.as_callable()?; + let sig = db.callable_item_signature(id).subst(substs); + Some(Callable { ty: self.clone(), sig, id, is_bound_method: false }) } pub fn is_closure(&self) -> bool { @@ -1512,6 +1520,60 @@ impl HirDisplay for Type { } } +// FIXME: closures +#[derive(Debug)] +pub struct Callable { + ty: Type, + sig: FnSig, + id: CallableDefId, + pub(crate) is_bound_method: bool, +} + +pub enum CallableKind { + Function(Function), + TupleStruct(Struct), + TupleEnumVariant(EnumVariant), +} + +impl Callable { + pub fn kind(&self) -> CallableKind { + match self.id { + CallableDefId::FunctionId(it) => CallableKind::Function(it.into()), + CallableDefId::StructId(it) => CallableKind::TupleStruct(it.into()), + CallableDefId::EnumVariantId(it) => CallableKind::TupleEnumVariant(it.into()), + } + } + pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option { + let func = match self.id { + CallableDefId::FunctionId(it) if self.is_bound_method => it, + _ => return None, + }; + let src = func.lookup(db.upcast()).source(db.upcast()); + let param_list = src.value.param_list()?; + param_list.self_param() + } + pub fn params(&self, db: &dyn HirDatabase) -> Vec<(Option, Type)> { + let types = self + .sig + .params() + .iter() + .skip(if self.is_bound_method { 1 } else { 0 }) + .map(|ty| self.ty.derived(ty.clone())); + let patterns = match self.id { + CallableDefId::FunctionId(func) => { + let src = func.lookup(db.upcast()).source(db.upcast()); + src.value.param_list().map(|it| it.params().map(|it| it.pat())) + } + CallableDefId::StructId(_) => None, + CallableDefId::EnumVariantId(_) => None, + }; + patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect() + } + pub fn return_type(&self) -> Type { + self.ty.derived(self.sig.ret().clone()) + } +} + /// For IDE only #[derive(Debug)] pub enum ScopeDef { diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index cf7134923..31f3241c9 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -32,10 +32,10 @@ mod has_source; pub use crate::{ code_model::{ - Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate, CrateDependency, - DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function, GenericDef, HasAttrs, - HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, - Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, + Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Callable, CallableKind, Const, + Crate, CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function, + GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, + Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, }, has_source::HasSource, semantics::{original_range, PathResolution, Semantics, SemanticsScope}, @@ -52,7 +52,8 @@ pub use hir_def::{ type_ref::Mutability, }; pub use hir_expand::{ - hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, + hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, + MacroDefId, /* FIXME */ MacroFile, Origin, }; -pub use hir_ty::{display::HirDisplay, CallableDefId}; +pub use hir_ty::display::HirDisplay; diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 155b666d7..f5283ab22 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs @@ -6,7 +6,7 @@ use std::{cell::RefCell, fmt, iter::successors}; use hir_def::{ resolver::{self, HasResolver, Resolver}, - AsMacroCall, TraitId, VariantId, + AsMacroCall, FunctionId, TraitId, VariantId, }; use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; use hir_ty::associated_type_shorthand_candidates; @@ -24,8 +24,8 @@ use crate::{ diagnostics::Diagnostic, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, - AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, - Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, + AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, + ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, }; use resolver::TypeNs; @@ -197,7 +197,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { } pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { - self.imp.resolve_method_call(call) + self.imp.resolve_method_call(call).map(Function::from) + } + + pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option { + self.imp.resolve_method_call_as_callable(call) } pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option { @@ -385,10 +389,21 @@ impl<'db> SemanticsImpl<'db> { self.analyze(param.syntax()).type_of_self(self.db, ¶m) } - fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { + fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { self.analyze(call.syntax()).resolve_method_call(self.db, call) } + fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option { + // FIXME: this erases Substs + let func = self.resolve_method_call(call)?; + let ty = self.db.value_ty(func.into()); + let resolver = self.analyze(call.syntax()).resolver; + let ty = Type::new_with_resolver(self.db, &resolver, ty.value)?; + let mut res = ty.as_callable(self.db)?; + res.is_bound_method = true; + Some(res) + } + fn resolve_field(&self, field: &ast::FieldExpr) -> Option { self.analyze(field.syntax()).resolve_field(self.db, field) } diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index ecb54f653..86a47a9e5 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs @@ -14,7 +14,7 @@ use hir_def::{ }, expr::{ExprId, Pat, PatId}, resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, - AsMacroCall, DefWithBodyId, FieldId, LocalFieldId, VariantId, + AsMacroCall, DefWithBodyId, FieldId, FunctionId, LocalFieldId, VariantId, }; use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; use hir_ty::{ @@ -142,9 +142,9 @@ impl SourceAnalyzer { &self, db: &dyn HirDatabase, call: &ast::MethodCallExpr, - ) -> Option { + ) -> Option { let expr_id = self.expr_id(db, &call.clone().into())?; - self.infer.as_ref()?.method_resolution(expr_id).map(Function::from) + self.infer.as_ref()?.method_resolution(expr_id) } pub(crate) fn resolve_field( -- cgit v1.2.3