aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-11-26 11:02:57 +0000
committerAleksey Kladov <[email protected]>2019-11-26 11:02:57 +0000
commite5eadb339039e21718d382c0b3d02a4bf053b3f4 (patch)
tree2f7839288ce5676a89c6d6062cbaf70544e0beed /crates
parent5901cc736074bbc4d780a8e45079d405ab2cec4b (diff)
Introduce hir::Type
It should provide a convenient API over more low-level Ty
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/assists/add_explicit_type.rs13
-rw-r--r--crates/ra_assists/src/assists/fill_match_arms.rs7
-rw-r--r--crates/ra_hir/src/code_model.rs166
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/source_binder.rs46
-rw-r--r--crates/ra_hir_def/src/lib.rs10
-rw-r--r--crates/ra_ide_api/src/call_info.rs4
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs36
-rw-r--r--crates/ra_ide_api/src/completion/complete_postfix.rs16
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_literal.rs7
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_pattern.rs7
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs39
-rw-r--r--crates/ra_ide_api/src/goto_type_definition.rs4
-rw-r--r--crates/ra_ide_api/src/inlay_hints.rs23
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs9
15 files changed, 253 insertions, 136 deletions
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs
index 562a09685..eeb4ff39f 100644
--- a/crates/ra_assists/src/assists/add_explicit_type.rs
+++ b/crates/ra_assists/src/assists/add_explicit_type.rs
@@ -1,4 +1,4 @@
1use hir::{db::HirDatabase, HirDisplay, Ty}; 1use hir::{db::HirDatabase, HirDisplay};
2use ra_syntax::{ 2use ra_syntax::{
3 ast::{self, AstNode, LetStmt, NameOwner}, 3 ast::{self, AstNode, LetStmt, NameOwner},
4 T, 4 T,
@@ -43,7 +43,7 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
43 let analyzer = ctx.source_analyzer(stmt.syntax(), None); 43 let analyzer = ctx.source_analyzer(stmt.syntax(), None);
44 let ty = analyzer.type_of(db, &expr)?; 44 let ty = analyzer.type_of(db, &expr)?;
45 // Assist not applicable if the type is unknown 45 // Assist not applicable if the type is unknown
46 if is_unknown(&ty) { 46 if ty.contains_unknown() {
47 return None; 47 return None;
48 } 48 }
49 49
@@ -53,15 +53,6 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
53 }) 53 })
54} 54}
55 55
56/// Returns true if any type parameter is unknown
57fn is_unknown(ty: &Ty) -> bool {
58 match ty {
59 Ty::Unknown => true,
60 Ty::Apply(a_ty) => a_ty.parameters.iter().any(is_unknown),
61 _ => false,
62 }
63}
64
65#[cfg(test)] 56#[cfg(test)]
66mod tests { 57mod tests {
67 use super::*; 58 use super::*;
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs
index 8482897c5..b75bd44eb 100644
--- a/crates/ra_assists/src/assists/fill_match_arms.rs
+++ b/crates/ra_assists/src/assists/fill_match_arms.rs
@@ -83,10 +83,11 @@ fn resolve_enum_def(
83) -> Option<ast::EnumDef> { 83) -> Option<ast::EnumDef> {
84 let expr_ty = analyzer.type_of(db, &expr)?; 84 let expr_ty = analyzer.type_of(db, &expr)?;
85 85
86 analyzer.autoderef(db, expr_ty).find_map(|ty| match ty.as_adt() { 86 let res = expr_ty.autoderef(db).find_map(|ty| match ty.as_adt() {
87 Some((Adt::Enum(e), _)) => Some(e.source(db).value), 87 Some(Adt::Enum(e)) => Some(e.source(db).value),
88 _ => None, 88 _ => None,
89 }) 89 });
90 res
90} 91}
91 92
92fn build_pat(var: ast::EnumVariant) -> Option<ast::Pat> { 93fn build_pat(var: ast::EnumVariant) -> Option<ast::Pat> {
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index f7fc80d4e..a7bba85e1 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -10,9 +10,9 @@ use hir_def::{
10 docs::Documentation, 10 docs::Documentation,
11 per_ns::PerNs, 11 per_ns::PerNs,
12 resolver::{HasResolver, TypeNs}, 12 resolver::{HasResolver, TypeNs},
13 type_ref::TypeRef, 13 type_ref::{Mutability, TypeRef},
14 AstItemDef, ConstId, ContainerId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, 14 AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule,
15 LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, 15 ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId,
16 StaticId, StructId, TraitId, TypeAliasId, UnionId, 16 StaticId, StructId, TraitId, TypeAliasId, UnionId,
17}; 17};
18use hir_expand::{ 18use hir_expand::{
@@ -26,8 +26,12 @@ use ra_syntax::{ast, AstNode, SyntaxNode};
26use crate::{ 26use crate::{
27 db::{DefDatabase, HirDatabase}, 27 db::{DefDatabase, HirDatabase},
28 expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId}, 28 expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId},
29 ty::{InferenceResult, Namespace, TraitRef}, 29 ty::display::HirFormatter,
30 Either, Name, Source, Ty, 30 ty::{
31 self, InEnvironment, InferenceResult, Namespace, TraitEnvironment, TraitRef, Ty, TypeCtor,
32 TypeWalk,
33 },
34 CallableDef, Either, HirDisplay, Name, Source,
31}; 35};
32 36
33/// hir::Crate describes a single crate. It's the main interface with which 37/// hir::Crate describes a single crate. It's the main interface with which
@@ -469,6 +473,10 @@ pub enum Adt {
469impl_froms!(Adt: Struct, Union, Enum); 473impl_froms!(Adt: Struct, Union, Enum);
470 474
471impl Adt { 475impl Adt {
476 pub fn has_non_default_type_params(self, db: &impl HirDatabase) -> bool {
477 let subst = db.generic_defaults(self.into());
478 subst.iter().any(|ty| ty == &Ty::Unknown)
479 }
472 pub fn ty(self, db: &impl HirDatabase) -> Ty { 480 pub fn ty(self, db: &impl HirDatabase) -> Ty {
473 match self { 481 match self {
474 Adt::Struct(it) => it.ty(db), 482 Adt::Struct(it) => it.ty(db),
@@ -777,6 +785,11 @@ pub struct TypeAlias {
777} 785}
778 786
779impl TypeAlias { 787impl TypeAlias {
788 pub fn has_non_default_type_params(self, db: &impl HirDatabase) -> bool {
789 let subst = db.generic_defaults(self.id.into());
790 subst.iter().any(|ty| ty == &Ty::Unknown)
791 }
792
780 pub fn module(self, db: &impl DefDatabase) -> Module { 793 pub fn module(self, db: &impl DefDatabase) -> Module {
781 Module { id: self.id.lookup(db).module(db) } 794 Module { id: self.id.lookup(db).module(db) }
782 } 795 }
@@ -927,9 +940,14 @@ impl Local {
927 self.parent.module(db) 940 self.parent.module(db)
928 } 941 }
929 942
930 pub fn ty(self, db: &impl HirDatabase) -> Ty { 943 pub fn ty(self, db: &impl HirDatabase) -> Type {
931 let infer = db.infer(self.parent); 944 let infer = db.infer(self.parent);
932 infer[self.pat_id].clone() 945 let ty = infer[self.pat_id].clone();
946 let def = DefWithBodyId::from(self.parent);
947 let resolver = def.resolver(db);
948 let krate = def.module(db).krate;
949 let environment = TraitEnvironment::lower(db, &resolver);
950 Type { krate, ty: InEnvironment { value: ty, environment } }
933 } 951 }
934 952
935 pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> { 953 pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> {
@@ -986,6 +1004,140 @@ impl ImplBlock {
986 } 1004 }
987} 1005}
988 1006
1007#[derive(Clone, PartialEq, Eq)]
1008pub struct Type {
1009 pub(crate) krate: CrateId,
1010 pub(crate) ty: InEnvironment<Ty>,
1011}
1012
1013impl Type {
1014 pub fn is_bool(&self) -> bool {
1015 match &self.ty.value {
1016 Ty::Apply(a_ty) => match a_ty.ctor {
1017 TypeCtor::Bool => true,
1018 _ => false,
1019 },
1020 _ => false,
1021 }
1022 }
1023
1024 pub fn is_mutable_reference(&self) -> bool {
1025 match &self.ty.value {
1026 Ty::Apply(a_ty) => match a_ty.ctor {
1027 TypeCtor::Ref(Mutability::Mut) => true,
1028 _ => false,
1029 },
1030 _ => false,
1031 }
1032 }
1033
1034 pub fn is_unknown(&self) -> bool {
1035 match &self.ty.value {
1036 Ty::Unknown => true,
1037 _ => false,
1038 }
1039 }
1040
1041 // FIXME: this method is broken, as it doesn't take closures into account.
1042 pub fn as_callable(&self) -> Option<CallableDef> {
1043 Some(self.ty.value.as_callable()?.0)
1044 }
1045
1046 pub fn contains_unknown(&self) -> bool {
1047 return go(&self.ty.value);
1048
1049 fn go(ty: &Ty) -> bool {
1050 match ty {
1051 Ty::Unknown => true,
1052 Ty::Apply(a_ty) => a_ty.parameters.iter().any(go),
1053 _ => false,
1054 }
1055 }
1056 }
1057
1058 pub fn fields(&self, db: &impl HirDatabase) -> Vec<(StructField, Type)> {
1059 let mut res = Vec::new();
1060 if let Ty::Apply(a_ty) = &self.ty.value {
1061 match a_ty.ctor {
1062 ty::TypeCtor::Adt(Adt::Struct(s)) => {
1063 for field in s.fields(db) {
1064 let ty = field.ty(db).subst(&a_ty.parameters);
1065 res.push((field, self.derived(ty)));
1066 }
1067 }
1068 _ => {}
1069 }
1070 };
1071 res
1072 }
1073
1074 pub fn tuple_fields(&self, _db: &impl HirDatabase) -> Vec<Type> {
1075 let mut res = Vec::new();
1076 if let Ty::Apply(a_ty) = &self.ty.value {
1077 match a_ty.ctor {
1078 ty::TypeCtor::Tuple { .. } => {
1079 for ty in a_ty.parameters.iter() {
1080 let ty = ty.clone().subst(&a_ty.parameters);
1081 res.push(self.derived(ty));
1082 }
1083 }
1084 _ => {}
1085 }
1086 };
1087 res
1088 }
1089
1090 pub fn variant_fields(
1091 &self,
1092 db: &impl HirDatabase,
1093 def: VariantDef,
1094 ) -> Vec<(StructField, Type)> {
1095 // FIXME: check that ty and def match
1096 match &self.ty.value {
1097 Ty::Apply(a_ty) => def
1098 .fields(db)
1099 .into_iter()
1100 .map(|it| (it, self.derived(it.ty(db).subst(&a_ty.parameters))))
1101 .collect(),
1102 _ => Vec::new(),
1103 }
1104 }
1105
1106 pub fn autoderef<'a>(&'a self, db: &'a impl HirDatabase) -> impl Iterator<Item = Type> + 'a {
1107 // There should be no inference vars in types passed here
1108 // FIXME check that?
1109 let canonical = crate::ty::Canonical { value: self.ty.value.clone(), num_vars: 0 };
1110 let environment = self.ty.environment.clone();
1111 let ty = InEnvironment { value: canonical, environment: environment.clone() };
1112 ty::autoderef(db, Some(self.krate), ty)
1113 .map(|canonical| canonical.value)
1114 .map(move |ty| self.derived(ty))
1115 }
1116
1117 // FIXME: remove
1118 pub fn into_ty(self) -> Ty {
1119 self.ty.value
1120 }
1121
1122 pub fn as_adt(&self) -> Option<Adt> {
1123 let (adt, _subst) = self.ty.value.as_adt()?;
1124 Some(adt)
1125 }
1126
1127 fn derived(&self, ty: Ty) -> Type {
1128 Type {
1129 krate: self.krate,
1130 ty: InEnvironment { value: ty, environment: self.ty.environment.clone() },
1131 }
1132 }
1133}
1134
1135impl HirDisplay for Type {
1136 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> std::fmt::Result {
1137 self.ty.value.hir_fmt(f)
1138 }
1139}
1140
989/// For IDE only 1141/// For IDE only
990pub enum ScopeDef { 1142pub enum ScopeDef {
991 ModuleDef(ModuleDef), 1143 ModuleDef(ModuleDef),
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 843ce6a88..b88e4c745 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -51,7 +51,7 @@ pub use crate::{
51 src::HasSource, Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency, 51 src::HasSource, Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency,
52 DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, GenericParam, 52 DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, GenericParam,
53 HasAttrs, ImplBlock, Import, Local, MacroDef, Module, ModuleDef, ModuleSource, ScopeDef, 53 HasAttrs, ImplBlock, Import, Local, MacroDef, Module, ModuleDef, ModuleSource, ScopeDef,
54 Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, 54 Static, Struct, StructField, Trait, Type, TypeAlias, Union, VariantDef,
55 }, 55 },
56 expr::ExprScopes, 56 expr::ExprScopes,
57 from_source::FromSource, 57 from_source::FromSource,
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index cbfeca3ab..95a94c3f0 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -28,10 +28,10 @@ use crate::{
28 expr::{BodySourceMap, ExprScopes, ScopeId}, 28 expr::{BodySourceMap, ExprScopes, ScopeId},
29 ty::{ 29 ty::{
30 method_resolution::{self, implements_trait}, 30 method_resolution::{self, implements_trait},
31 TraitEnvironment, 31 InEnvironment, TraitEnvironment, Ty,
32 }, 32 },
33 Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function, 33 Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function,
34 GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Ty, TypeAlias, 34 GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias,
35}; 35};
36 36
37fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option<Resolver> { 37fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option<Resolver> {
@@ -198,14 +198,18 @@ impl SourceAnalyzer {
198 self.body_source_map.as_ref()?.node_pat(src) 198 self.body_source_map.as_ref()?.node_pat(src)
199 } 199 }
200 200
201 pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> { 201 pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option<Type> {
202 let expr_id = self.expr_id(expr)?; 202 let expr_id = self.expr_id(expr)?;
203 Some(self.infer.as_ref()?[expr_id].clone()) 203 let ty = self.infer.as_ref()?[expr_id].clone();
204 let environment = TraitEnvironment::lower(db, &self.resolver);
205 Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
204 } 206 }
205 207
206 pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> { 208 pub fn type_of_pat(&self, db: &impl HirDatabase, pat: &ast::Pat) -> Option<Type> {
207 let pat_id = self.pat_id(pat)?; 209 let pat_id = self.pat_id(pat)?;
208 Some(self.infer.as_ref()?[pat_id].clone()) 210 let ty = self.infer.as_ref()?[pat_id].clone();
211 let environment = TraitEnvironment::lower(db, &self.resolver);
212 Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
209 } 213 }
210 214
211 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { 215 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
@@ -361,14 +365,14 @@ impl SourceAnalyzer {
361 pub fn iterate_method_candidates<T>( 365 pub fn iterate_method_candidates<T>(
362 &self, 366 &self,
363 db: &impl HirDatabase, 367 db: &impl HirDatabase,
364 ty: Ty, 368 ty: &Type,
365 name: Option<&Name>, 369 name: Option<&Name>,
366 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 370 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
367 ) -> Option<T> { 371 ) -> Option<T> {
368 // There should be no inference vars in types passed here 372 // There should be no inference vars in types passed here
369 // FIXME check that? 373 // FIXME check that?
370 // FIXME replace Unknown by bound vars here 374 // FIXME replace Unknown by bound vars here
371 let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; 375 let canonical = crate::ty::Canonical { value: ty.ty.value.clone(), num_vars: 0 };
372 method_resolution::iterate_method_candidates( 376 method_resolution::iterate_method_candidates(
373 &canonical, 377 &canonical,
374 db, 378 db,
@@ -403,19 +407,19 @@ impl SourceAnalyzer {
403 ) 407 )
404 } 408 }
405 409
406 pub fn autoderef<'a>( 410 // pub fn autoderef<'a>(
407 &'a self, 411 // &'a self,
408 db: &'a impl HirDatabase, 412 // db: &'a impl HirDatabase,
409 ty: Ty, 413 // ty: Ty,
410 ) -> impl Iterator<Item = Ty> + 'a { 414 // ) -> impl Iterator<Item = Ty> + 'a {
411 // There should be no inference vars in types passed here 415 // // There should be no inference vars in types passed here
412 // FIXME check that? 416 // // FIXME check that?
413 let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; 417 // let canonical = crate::ty::Canonical { value: ty, num_vars: 0 };
414 let krate = self.resolver.krate(); 418 // let krate = self.resolver.krate();
415 let environment = TraitEnvironment::lower(db, &self.resolver); 419 // let environment = TraitEnvironment::lower(db, &self.resolver);
416 let ty = crate::ty::InEnvironment { value: canonical, environment }; 420 // let ty = crate::ty::InEnvironment { value: canonical, environment };
417 crate::ty::autoderef(db, krate, ty).map(|canonical| canonical.value) 421 // crate::ty::autoderef(db, krate, ty).map(|canonical| canonical.value)
418 } 422 // }
419 423
420 /// Checks that particular type `ty` implements `std::future::Future`. 424 /// Checks that particular type `ty` implements `std::future::Future`.
421 /// This function is used in `.await` syntax completion. 425 /// This function is used in `.await` syntax completion.
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index a88a78b38..274dd1467 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -489,6 +489,16 @@ impl HasModule for AdtId {
489 } 489 }
490} 490}
491 491
492impl HasModule for DefWithBodyId {
493 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
494 match self {
495 DefWithBodyId::FunctionId(it) => it.lookup(db).module(db),
496 DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
497 DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
498 }
499 }
500}
501
492impl HasModule for StaticLoc { 502impl HasModule for StaticLoc {
493 fn module(&self, _db: &impl db::DefDatabase) -> ModuleId { 503 fn module(&self, _db: &impl db::DefDatabase) -> ModuleId {
494 self.container 504 self.container
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs
index 9beceb29c..d0283e410 100644
--- a/crates/ra_ide_api/src/call_info.rs
+++ b/crates/ra_ide_api/src/call_info.rs
@@ -26,8 +26,8 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
26 ); 26 );
27 let (mut call_info, has_self) = match &calling_node { 27 let (mut call_info, has_self) = match &calling_node {
28 FnCallNode::CallExpr(expr) => { 28 FnCallNode::CallExpr(expr) => {
29 //FIXME: don't poke into Ty 29 //FIXME: Type::as_callable is broken
30 let (callable_def, _subst) = analyzer.type_of(db, &expr.expr()?)?.as_callable()?; 30 let callable_def = analyzer.type_of(db, &expr.expr()?)?.as_callable()?;
31 match callable_def { 31 match callable_def {
32 hir::CallableDef::FunctionId(it) => { 32 hir::CallableDef::FunctionId(it) => {
33 let fn_def = it.into(); 33 let fn_def = it.into();
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index 5a3f9b5f6..b6fe48627 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{Adt, Ty, TypeCtor}; 3use hir::Type;
4 4
5use crate::completion::completion_item::CompletionKind; 5use crate::completion::completion_item::CompletionKind;
6use crate::{ 6use crate::{
@@ -22,12 +22,12 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
22 }; 22 };
23 23
24 if !ctx.is_call { 24 if !ctx.is_call {
25 complete_fields(acc, ctx, receiver_ty.clone()); 25 complete_fields(acc, ctx, &receiver_ty);
26 } 26 }
27 complete_methods(acc, ctx, receiver_ty.clone()); 27 complete_methods(acc, ctx, &receiver_ty);
28 28
29 // Suggest .await syntax for types that implement Future trait 29 // Suggest .await syntax for types that implement Future trait
30 if ctx.analyzer.impls_future(ctx.db, receiver_ty) { 30 if ctx.analyzer.impls_future(ctx.db, receiver_ty.into_ty()) {
31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") 31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
32 .detail("expr.await") 32 .detail("expr.await")
33 .insert_text("await") 33 .insert_text("await")
@@ -35,28 +35,18 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
35 } 35 }
36} 36}
37 37
38fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { 38fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
39 for receiver in ctx.analyzer.autoderef(ctx.db, receiver) { 39 for receiver in receiver.autoderef(ctx.db) {
40 if let Ty::Apply(a_ty) = receiver { 40 for (field, ty) in receiver.fields(ctx.db) {
41 match a_ty.ctor { 41 acc.add_field(ctx, field, &ty);
42 TypeCtor::Adt(Adt::Struct(s)) => { 42 }
43 for field in s.fields(ctx.db) { 43 for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
44 acc.add_field(ctx, field, &a_ty.parameters); 44 acc.add_tuple_field(ctx, i, &ty);
45 } 45 }
46 }
47 // FIXME unions
48 TypeCtor::Tuple { .. } => {
49 for (i, ty) in a_ty.parameters.iter().enumerate() {
50 acc.add_tuple_field(ctx, i, ty);
51 }
52 }
53 _ => {}
54 }
55 };
56 } 46 }
57} 47}
58 48
59fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { 49fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
60 let mut seen_methods = FxHashSet::default(); 50 let mut seen_methods = FxHashSet::default();
61 ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| { 51 ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| {
62 if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) { 52 if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) {
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs
index 17b75cf7e..646a30c76 100644
--- a/crates/ra_ide_api/src/completion/complete_postfix.rs
+++ b/crates/ra_ide_api/src/completion/complete_postfix.rs
@@ -1,6 +1,5 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{Ty, TypeCtor};
4use ra_syntax::{ast::AstNode, TextRange, TextUnit}; 3use ra_syntax::{ast::AstNode, TextRange, TextUnit};
5use ra_text_edit::TextEdit; 4use ra_text_edit::TextEdit;
6 5
@@ -30,9 +29,12 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
30 dot_receiver.syntax().text().to_string() 29 dot_receiver.syntax().text().to_string()
31 }; 30 };
32 31
33 let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); 32 let receiver_ty = match ctx.analyzer.type_of(ctx.db, &dot_receiver) {
33 Some(it) => it,
34 None => return,
35 };
34 36
35 if is_bool_or_unknown(receiver_ty) { 37 if receiver_ty.is_bool() || receiver_ty.is_unknown() {
36 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) 38 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
37 .add_to(acc); 39 .add_to(acc);
38 postfix_snippet( 40 postfix_snippet(
@@ -75,14 +77,6 @@ fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet:
75 .snippet_edit(edit) 77 .snippet_edit(edit)
76} 78}
77 79
78fn is_bool_or_unknown(ty: Option<Ty>) -> bool {
79 match &ty {
80 Some(Ty::Apply(app)) if app.ctor == TypeCtor::Bool => true,
81 Some(Ty::Unknown) | None => true,
82 Some(_) => false,
83 }
84}
85
86#[cfg(test)] 80#[cfg(test)]
87mod tests { 81mod tests {
88 use insta::assert_debug_snapshot; 82 use insta::assert_debug_snapshot;
diff --git a/crates/ra_ide_api/src/completion/complete_record_literal.rs b/crates/ra_ide_api/src/completion/complete_record_literal.rs
index 45a4a9738..577c394d2 100644
--- a/crates/ra_ide_api/src/completion/complete_record_literal.rs
+++ b/crates/ra_ide_api/src/completion/complete_record_literal.rs
@@ -1,7 +1,5 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::Substs;
4
5use crate::completion::{CompletionContext, Completions}; 3use crate::completion::{CompletionContext, Completions};
6 4
7/// Complete fields in fields literals. 5/// Complete fields in fields literals.
@@ -15,10 +13,9 @@ pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionCon
15 Some(it) => it, 13 Some(it) => it,
16 _ => return, 14 _ => return,
17 }; 15 };
18 let substs = &ty.substs().unwrap_or_else(Substs::empty);
19 16
20 for field in variant.fields(ctx.db) { 17 for (field, field_ty) in ty.variant_fields(ctx.db, variant) {
21 acc.add_field(ctx, field, substs); 18 acc.add_field(ctx, field, &field_ty);
22 } 19 }
23} 20}
24 21
diff --git a/crates/ra_ide_api/src/completion/complete_record_pattern.rs b/crates/ra_ide_api/src/completion/complete_record_pattern.rs
index aa0fd6d24..a56c7e3a1 100644
--- a/crates/ra_ide_api/src/completion/complete_record_pattern.rs
+++ b/crates/ra_ide_api/src/completion/complete_record_pattern.rs
@@ -1,7 +1,5 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::Substs;
4
5use crate::completion::{CompletionContext, Completions}; 3use crate::completion::{CompletionContext, Completions};
6 4
7pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionContext) {
@@ -14,10 +12,9 @@ pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionCon
14 Some(it) => it, 12 Some(it) => it,
15 _ => return, 13 _ => return,
16 }; 14 };
17 let substs = &ty.substs().unwrap_or_else(Substs::empty);
18 15
19 for field in variant.fields(ctx.db) { 16 for (field, field_ty) in ty.variant_fields(ctx.db, variant) {
20 acc.add_field(ctx, field, substs); 17 acc.add_field(ctx, field, &field_ty);
21 } 18 }
22} 19}
23 20
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index 85b053a6e..5f056730a 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -1,12 +1,12 @@
1//! This modules takes care of rendering various definitions as completion items. 1//! This modules takes care of rendering various definitions as completion items.
2 2
3use hir::{db::HirDatabase, Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; 3use hir::{db::HirDatabase, Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, Type};
4use join_to_string::join; 4use join_to_string::join;
5use ra_syntax::ast::NameOwner; 5use ra_syntax::ast::NameOwner;
6use test_utils::tested_by; 6use test_utils::tested_by;
7 7
8use crate::completion::{ 8use crate::completion::{
9 db, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 9 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
10}; 10};
11 11
12use crate::display::{const_label, function_label, macro_label, type_label}; 12use crate::display::{const_label, function_label, macro_label, type_label};
@@ -16,7 +16,7 @@ impl Completions {
16 &mut self, 16 &mut self,
17 ctx: &CompletionContext, 17 ctx: &CompletionContext,
18 field: hir::StructField, 18 field: hir::StructField,
19 substs: &hir::Substs, 19 ty: &Type,
20 ) { 20 ) {
21 let is_deprecated = is_deprecated(field, ctx.db); 21 let is_deprecated = is_deprecated(field, ctx.db);
22 CompletionItem::new( 22 CompletionItem::new(
@@ -25,13 +25,13 @@ impl Completions {
25 field.name(ctx.db).to_string(), 25 field.name(ctx.db).to_string(),
26 ) 26 )
27 .kind(CompletionItemKind::Field) 27 .kind(CompletionItemKind::Field)
28 .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string()) 28 .detail(ty.display(ctx.db).to_string())
29 .set_documentation(field.docs(ctx.db)) 29 .set_documentation(field.docs(ctx.db))
30 .set_deprecated(is_deprecated) 30 .set_deprecated(is_deprecated)
31 .add_to(self); 31 .add_to(self);
32 } 32 }
33 33
34 pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) { 34 pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) {
35 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string()) 35 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
36 .kind(CompletionItemKind::Field) 36 .kind(CompletionItemKind::Field)
37 .detail(ty.display(ctx.db).to_string()) 37 .detail(ty.display(ctx.db).to_string())
@@ -98,7 +98,7 @@ impl Completions {
98 CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone()); 98 CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
99 if let ScopeDef::Local(local) = resolution { 99 if let ScopeDef::Local(local) = resolution {
100 let ty = local.ty(ctx.db); 100 let ty = local.ty(ctx.db);
101 if ty != Ty::Unknown { 101 if !ty.is_unknown() {
102 completion_item = completion_item.detail(ty.display(ctx.db).to_string()); 102 completion_item = completion_item.detail(ty.display(ctx.db).to_string());
103 } 103 }
104 }; 104 };
@@ -108,19 +108,17 @@ impl Completions {
108 && !ctx.has_type_args 108 && !ctx.has_type_args
109 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") 109 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
110 { 110 {
111 let generic_def: Option<hir::GenericDef> = match resolution { 111 let has_non_default_type_params = match resolution {
112 ScopeDef::ModuleDef(Adt(it)) => Some((*it).into()), 112 ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db),
113 ScopeDef::ModuleDef(TypeAlias(it)) => Some((*it).into()), 113 ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db),
114 _ => None, 114 _ => false,
115 }; 115 };
116 if let Some(def) = generic_def { 116 if has_non_default_type_params {
117 if has_non_default_type_params(def, ctx.db) { 117 tested_by!(inserts_angle_brackets_for_generics);
118 tested_by!(inserts_angle_brackets_for_generics); 118 completion_item = completion_item
119 completion_item = completion_item 119 .lookup_by(local_name.clone())
120 .lookup_by(local_name.clone()) 120 .label(format!("{}<…>", local_name))
121 .label(format!("{}<…>", local_name)) 121 .insert_snippet(format!("{}<$0>", local_name));
122 .insert_snippet(format!("{}<$0>", local_name));
123 }
124 } 122 }
125 } 123 }
126 124
@@ -291,11 +289,6 @@ fn is_deprecated(node: impl HasAttrs, db: &impl HirDatabase) -> bool {
291 node.attrs(db).by_key("deprecated").exists() 289 node.attrs(db).by_key("deprecated").exists()
292} 290}
293 291
294fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool {
295 let subst = db.generic_defaults(def.into());
296 subst.iter().any(|ty| ty == &Ty::Unknown)
297}
298
299#[cfg(test)] 292#[cfg(test)]
300mod tests { 293mod tests {
301 use insta::assert_debug_snapshot; 294 use insta::assert_debug_snapshot;
diff --git a/crates/ra_ide_api/src/goto_type_definition.rs b/crates/ra_ide_api/src/goto_type_definition.rs
index 28a83a3e2..992a08809 100644
--- a/crates/ra_ide_api/src/goto_type_definition.rs
+++ b/crates/ra_ide_api/src/goto_type_definition.rs
@@ -24,7 +24,7 @@ pub(crate) fn goto_type_definition(
24 24
25 let analyzer = hir::SourceAnalyzer::new(db, token.with_value(&node), None); 25 let analyzer = hir::SourceAnalyzer::new(db, token.with_value(&node), None);
26 26
27 let ty: hir::Ty = if let Some(ty) = 27 let ty: hir::Type = if let Some(ty) =
28 ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e)) 28 ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e))
29 { 29 {
30 ty 30 ty
@@ -35,7 +35,7 @@ pub(crate) fn goto_type_definition(
35 return None; 35 return None;
36 }; 36 };
37 37
38 let adt_def = analyzer.autoderef(db, ty).find_map(|ty| ty.as_adt().map(|adt| adt.0))?; 38 let adt_def = ty.autoderef(db).find_map(|ty| ty.as_adt())?;
39 39
40 let nav = adt_def.to_nav(db); 40 let nav = adt_def.to_nav(db);
41 Some(RangeInfo::new(node.text_range(), vec![nav])) 41 Some(RangeInfo::new(node.text_range(), vec![nav]))
diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs
index 24a7ca5e7..45149bf0c 100644
--- a/crates/ra_ide_api/src/inlay_hints.rs
+++ b/crates/ra_ide_api/src/inlay_hints.rs
@@ -1,7 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use crate::{db::RootDatabase, FileId}; 3use crate::{db::RootDatabase, FileId};
4use hir::{HirDisplay, SourceAnalyzer, Ty}; 4use hir::{HirDisplay, SourceAnalyzer};
5use ra_syntax::{ 5use ra_syntax::{
6 ast::{self, AstNode, TypeAscriptionOwner}, 6 ast::{self, AstNode, TypeAscriptionOwner},
7 match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange, 7 match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange,
@@ -100,8 +100,11 @@ fn get_pat_type_hints(
100 .into_iter() 100 .into_iter()
101 .filter(|pat| !skip_root_pat_hint || pat != original_pat) 101 .filter(|pat| !skip_root_pat_hint || pat != original_pat)
102 .filter_map(|pat| { 102 .filter_map(|pat| {
103 get_node_displayable_type(db, &analyzer, &pat) 103 let ty = analyzer.type_of_pat(db, &pat)?;
104 .map(|pat_type| (pat.syntax().text_range(), pat_type)) 104 if ty.is_unknown() {
105 return None;
106 }
107 Some((pat.syntax().text_range(), ty))
105 }) 108 })
106 .map(|(range, pat_type)| InlayHint { 109 .map(|(range, pat_type)| InlayHint {
107 range, 110 range,
@@ -158,20 +161,6 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
158 leaf_pats 161 leaf_pats
159} 162}
160 163
161fn get_node_displayable_type(
162 db: &RootDatabase,
163 analyzer: &SourceAnalyzer,
164 node_pat: &ast::Pat,
165) -> Option<Ty> {
166 analyzer.type_of_pat(db, node_pat).and_then(|resolved_type| {
167 if let Ty::Apply(_) = resolved_type {
168 Some(resolved_type)
169 } else {
170 None
171 }
172 })
173}
174
175#[cfg(test)] 164#[cfg(test)]
176mod tests { 165mod tests {
177 use crate::mock_analysis::single_file; 166 use crate::mock_analysis::single_file;
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index 2b653fe8f..10165a9bb 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -2,7 +2,7 @@
2 2
3use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
4 4
5use hir::{Mutability, Name, Source}; 5use hir::{Name, Source};
6use ra_db::SourceDatabase; 6use ra_db::SourceDatabase;
7use ra_prof::profile; 7use ra_prof::profile;
8use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T}; 8use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T};
@@ -230,11 +230,10 @@ fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str {
230 Local(local) => { 230 Local(local) => {
231 if local.is_mut(db) { 231 if local.is_mut(db) {
232 "variable.mut" 232 "variable.mut"
233 } else if local.ty(db).is_mutable_reference() {
234 "variable.mut"
233 } else { 235 } else {
234 match local.ty(db).as_reference() { 236 "variable"
235 Some((_, Mutability::Mut)) => "variable.mut",
236 _ => "variable",
237 }
238 } 237 }
239 } 238 }
240 } 239 }