diff options
author | Aleksey Kladov <[email protected]> | 2020-07-16 12:00:56 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-07-16 17:03:04 +0100 |
commit | ff0312fa32715ce42f134fd9f049c4df5956d042 (patch) | |
tree | b514e34d3486a650fef35e29396a810ee7741cd1 /crates/ra_hir/src | |
parent | 9210fcc076808e53e9bde84be26307fc0dc7d688 (diff) |
Semantical call info
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 76 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir/src/source_analyzer.rs | 6 |
4 files changed, 99 insertions, 21 deletions
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 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | use std::sync::Arc; | 2 | use std::{iter, sync::Arc}; |
3 | 3 | ||
4 | use arrayvec::ArrayVec; | 4 | use arrayvec::ArrayVec; |
5 | use either::Either; | 5 | use either::Either; |
@@ -12,6 +12,7 @@ use hir_def::{ | |||
12 | import_map, | 12 | import_map, |
13 | per_ns::PerNs, | 13 | per_ns::PerNs, |
14 | resolver::{HasResolver, Resolver}, | 14 | resolver::{HasResolver, Resolver}, |
15 | src::HasSource as _, | ||
15 | type_ref::{Mutability, TypeRef}, | 16 | type_ref::{Mutability, TypeRef}, |
16 | AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, | 17 | AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, |
17 | ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, | 18 | ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, |
@@ -25,8 +26,8 @@ use hir_expand::{ | |||
25 | use hir_ty::{ | 26 | use hir_ty::{ |
26 | autoderef, | 27 | autoderef, |
27 | display::{HirDisplayError, HirFormatter}, | 28 | display::{HirDisplayError, HirFormatter}, |
28 | method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, | 29 | method_resolution, ApplicationTy, CallableDefId, Canonical, FnSig, GenericPredicate, |
29 | TraitEnvironment, Ty, TyDefId, TypeCtor, | 30 | InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, |
30 | }; | 31 | }; |
31 | use ra_db::{CrateId, Edition, FileId}; | 32 | use ra_db::{CrateId, Edition, FileId}; |
32 | use ra_prof::profile; | 33 | use ra_prof::profile; |
@@ -40,7 +41,7 @@ use stdx::impl_from; | |||
40 | use crate::{ | 41 | use crate::{ |
41 | db::{DefDatabase, HirDatabase}, | 42 | db::{DefDatabase, HirDatabase}, |
42 | has_source::HasSource, | 43 | has_source::HasSource, |
43 | CallableDefId, HirDisplay, InFile, Name, | 44 | HirDisplay, InFile, Name, |
44 | }; | 45 | }; |
45 | 46 | ||
46 | /// hir::Crate describes a single crate. It's the main interface with which | 47 | /// hir::Crate describes a single crate. It's the main interface with which |
@@ -1168,6 +1169,12 @@ impl Type { | |||
1168 | Type::new(db, krate, def, ty) | 1169 | Type::new(db, krate, def, ty) |
1169 | } | 1170 | } |
1170 | 1171 | ||
1172 | pub fn is_unit(&self) -> bool { | ||
1173 | matches!( | ||
1174 | self.ty.value, | ||
1175 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Tuple { cardinality: 0 }, .. }) | ||
1176 | ) | ||
1177 | } | ||
1171 | pub fn is_bool(&self) -> bool { | 1178 | pub fn is_bool(&self) -> bool { |
1172 | matches!(self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. })) | 1179 | matches!(self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. })) |
1173 | } | 1180 | } |
@@ -1225,9 +1232,10 @@ impl Type { | |||
1225 | db.trait_solve(self.krate, goal).is_some() | 1232 | db.trait_solve(self.krate, goal).is_some() |
1226 | } | 1233 | } |
1227 | 1234 | ||
1228 | // FIXME: this method is broken, as it doesn't take closures into account. | 1235 | pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> { |
1229 | pub fn as_callable(&self) -> Option<CallableDefId> { | 1236 | let (id, substs) = self.ty.value.as_callable()?; |
1230 | Some(self.ty.value.as_callable()?.0) | 1237 | let sig = db.callable_item_signature(id).subst(substs); |
1238 | Some(Callable { ty: self.clone(), sig, id, is_bound_method: false }) | ||
1231 | } | 1239 | } |
1232 | 1240 | ||
1233 | pub fn is_closure(&self) -> bool { | 1241 | pub fn is_closure(&self) -> bool { |
@@ -1512,6 +1520,60 @@ impl HirDisplay for Type { | |||
1512 | } | 1520 | } |
1513 | } | 1521 | } |
1514 | 1522 | ||
1523 | // FIXME: closures | ||
1524 | #[derive(Debug)] | ||
1525 | pub struct Callable { | ||
1526 | ty: Type, | ||
1527 | sig: FnSig, | ||
1528 | id: CallableDefId, | ||
1529 | pub(crate) is_bound_method: bool, | ||
1530 | } | ||
1531 | |||
1532 | pub enum CallableKind { | ||
1533 | Function(Function), | ||
1534 | TupleStruct(Struct), | ||
1535 | TupleEnumVariant(EnumVariant), | ||
1536 | } | ||
1537 | |||
1538 | impl Callable { | ||
1539 | pub fn kind(&self) -> CallableKind { | ||
1540 | match self.id { | ||
1541 | CallableDefId::FunctionId(it) => CallableKind::Function(it.into()), | ||
1542 | CallableDefId::StructId(it) => CallableKind::TupleStruct(it.into()), | ||
1543 | CallableDefId::EnumVariantId(it) => CallableKind::TupleEnumVariant(it.into()), | ||
1544 | } | ||
1545 | } | ||
1546 | pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> { | ||
1547 | let func = match self.id { | ||
1548 | CallableDefId::FunctionId(it) if self.is_bound_method => it, | ||
1549 | _ => return None, | ||
1550 | }; | ||
1551 | let src = func.lookup(db.upcast()).source(db.upcast()); | ||
1552 | let param_list = src.value.param_list()?; | ||
1553 | param_list.self_param() | ||
1554 | } | ||
1555 | pub fn params(&self, db: &dyn HirDatabase) -> Vec<(Option<ast::Pat>, Type)> { | ||
1556 | let types = self | ||
1557 | .sig | ||
1558 | .params() | ||
1559 | .iter() | ||
1560 | .skip(if self.is_bound_method { 1 } else { 0 }) | ||
1561 | .map(|ty| self.ty.derived(ty.clone())); | ||
1562 | let patterns = match self.id { | ||
1563 | CallableDefId::FunctionId(func) => { | ||
1564 | let src = func.lookup(db.upcast()).source(db.upcast()); | ||
1565 | src.value.param_list().map(|it| it.params().map(|it| it.pat())) | ||
1566 | } | ||
1567 | CallableDefId::StructId(_) => None, | ||
1568 | CallableDefId::EnumVariantId(_) => None, | ||
1569 | }; | ||
1570 | patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect() | ||
1571 | } | ||
1572 | pub fn return_type(&self) -> Type { | ||
1573 | self.ty.derived(self.sig.ret().clone()) | ||
1574 | } | ||
1575 | } | ||
1576 | |||
1515 | /// For IDE only | 1577 | /// For IDE only |
1516 | #[derive(Debug)] | 1578 | #[derive(Debug)] |
1517 | pub enum ScopeDef { | 1579 | 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; | |||
32 | 32 | ||
33 | pub use crate::{ | 33 | pub use crate::{ |
34 | code_model::{ | 34 | code_model::{ |
35 | Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate, CrateDependency, | 35 | Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Callable, CallableKind, Const, |
36 | DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function, GenericDef, HasAttrs, | 36 | Crate, CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function, |
37 | HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, | 37 | GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, |
38 | Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, | 38 | Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, |
39 | }, | 39 | }, |
40 | has_source::HasSource, | 40 | has_source::HasSource, |
41 | semantics::{original_range, PathResolution, Semantics, SemanticsScope}, | 41 | semantics::{original_range, PathResolution, Semantics, SemanticsScope}, |
@@ -52,7 +52,8 @@ pub use hir_def::{ | |||
52 | type_ref::Mutability, | 52 | type_ref::Mutability, |
53 | }; | 53 | }; |
54 | pub use hir_expand::{ | 54 | pub use hir_expand::{ |
55 | hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, | 55 | hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, |
56 | MacroDefId, /* FIXME */ | ||
56 | MacroFile, Origin, | 57 | MacroFile, Origin, |
57 | }; | 58 | }; |
58 | pub use hir_ty::{display::HirDisplay, CallableDefId}; | 59 | 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}; | |||
6 | 6 | ||
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | resolver::{self, HasResolver, Resolver}, | 8 | resolver::{self, HasResolver, Resolver}, |
9 | AsMacroCall, TraitId, VariantId, | 9 | AsMacroCall, FunctionId, TraitId, VariantId, |
10 | }; | 10 | }; |
11 | use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; | 11 | use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; |
12 | use hir_ty::associated_type_shorthand_candidates; | 12 | use hir_ty::associated_type_shorthand_candidates; |
@@ -24,8 +24,8 @@ use crate::{ | |||
24 | diagnostics::Diagnostic, | 24 | diagnostics::Diagnostic, |
25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
26 | source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, | 26 | source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, |
27 | AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, | 27 | AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, |
28 | Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, | 28 | ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, |
29 | }; | 29 | }; |
30 | use resolver::TypeNs; | 30 | use resolver::TypeNs; |
31 | 31 | ||
@@ -197,7 +197,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
197 | } | 197 | } |
198 | 198 | ||
199 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 199 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { |
200 | self.imp.resolve_method_call(call) | 200 | self.imp.resolve_method_call(call).map(Function::from) |
201 | } | ||
202 | |||
203 | pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { | ||
204 | self.imp.resolve_method_call_as_callable(call) | ||
201 | } | 205 | } |
202 | 206 | ||
203 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { | 207 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { |
@@ -385,10 +389,21 @@ impl<'db> SemanticsImpl<'db> { | |||
385 | self.analyze(param.syntax()).type_of_self(self.db, ¶m) | 389 | self.analyze(param.syntax()).type_of_self(self.db, ¶m) |
386 | } | 390 | } |
387 | 391 | ||
388 | fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 392 | fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> { |
389 | self.analyze(call.syntax()).resolve_method_call(self.db, call) | 393 | self.analyze(call.syntax()).resolve_method_call(self.db, call) |
390 | } | 394 | } |
391 | 395 | ||
396 | fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { | ||
397 | // FIXME: this erases Substs | ||
398 | let func = self.resolve_method_call(call)?; | ||
399 | let ty = self.db.value_ty(func.into()); | ||
400 | let resolver = self.analyze(call.syntax()).resolver; | ||
401 | let ty = Type::new_with_resolver(self.db, &resolver, ty.value)?; | ||
402 | let mut res = ty.as_callable(self.db)?; | ||
403 | res.is_bound_method = true; | ||
404 | Some(res) | ||
405 | } | ||
406 | |||
392 | fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { | 407 | fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { |
393 | self.analyze(field.syntax()).resolve_field(self.db, field) | 408 | self.analyze(field.syntax()).resolve_field(self.db, field) |
394 | } | 409 | } |
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::{ | |||
14 | }, | 14 | }, |
15 | expr::{ExprId, Pat, PatId}, | 15 | expr::{ExprId, Pat, PatId}, |
16 | resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, | 16 | resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, |
17 | AsMacroCall, DefWithBodyId, FieldId, LocalFieldId, VariantId, | 17 | AsMacroCall, DefWithBodyId, FieldId, FunctionId, LocalFieldId, VariantId, |
18 | }; | 18 | }; |
19 | use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; | 19 | use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; |
20 | use hir_ty::{ | 20 | use hir_ty::{ |
@@ -142,9 +142,9 @@ impl SourceAnalyzer { | |||
142 | &self, | 142 | &self, |
143 | db: &dyn HirDatabase, | 143 | db: &dyn HirDatabase, |
144 | call: &ast::MethodCallExpr, | 144 | call: &ast::MethodCallExpr, |
145 | ) -> Option<Function> { | 145 | ) -> Option<FunctionId> { |
146 | let expr_id = self.expr_id(db, &call.clone().into())?; | 146 | let expr_id = self.expr_id(db, &call.clone().into())?; |
147 | self.infer.as_ref()?.method_resolution(expr_id).map(Function::from) | 147 | self.infer.as_ref()?.method_resolution(expr_id) |
148 | } | 148 | } |
149 | 149 | ||
150 | pub(crate) fn resolve_field( | 150 | pub(crate) fn resolve_field( |