diff options
author | adamrk <[email protected]> | 2020-08-22 19:11:37 +0100 |
---|---|---|
committer | adamrk <[email protected]> | 2020-08-30 11:34:32 +0100 |
commit | c6ddb907144688ae77a6de3666159feef53638e1 (patch) | |
tree | a560689c0ff6a35b7ed6a6738c48524730a60263 | |
parent | ac4b134c6be27642dbe915f32a41f9a21bd0c1c9 (diff) |
Add references to fn args during completion
-rw-r--r-- | crates/hir/src/code_model.rs | 34 | ||||
-rw-r--r-- | crates/hir_ty/src/db.rs | 3 | ||||
-rw-r--r-- | crates/hir_ty/src/infer.rs | 15 | ||||
-rw-r--r-- | crates/hir_ty/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/completion/presentation.rs | 107 |
5 files changed, 151 insertions, 10 deletions
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index c2fc819e7..f182ab228 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -708,12 +708,24 @@ impl Function { | |||
708 | Some(SelfParam { func: self.id }) | 708 | Some(SelfParam { func: self.id }) |
709 | } | 709 | } |
710 | 710 | ||
711 | pub fn params(self, db: &dyn HirDatabase) -> Vec<Param> { | 711 | pub fn params(self, db: &dyn HirDatabase) -> Vec<Type> { |
712 | let resolver = self.id.resolver(db.upcast()); | ||
713 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
714 | let environment = TraitEnvironment::lower(db, &resolver); | ||
712 | db.function_data(self.id) | 715 | db.function_data(self.id) |
713 | .params | 716 | .params |
714 | .iter() | 717 | .iter() |
715 | .skip(if self.self_param(db).is_some() { 1 } else { 0 }) | 718 | .skip(if self.self_param(db).is_some() { 1 } else { 0 }) |
716 | .map(|_| Param { _ty: () }) | 719 | .map(|type_ref| { |
720 | let ty = Type { | ||
721 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate, | ||
722 | ty: InEnvironment { | ||
723 | value: Ty::from_hir_ext(&ctx, type_ref).0, | ||
724 | environment: environment.clone(), | ||
725 | }, | ||
726 | }; | ||
727 | ty | ||
728 | }) | ||
717 | .collect() | 729 | .collect() |
718 | } | 730 | } |
719 | 731 | ||
@@ -747,10 +759,6 @@ pub struct SelfParam { | |||
747 | func: FunctionId, | 759 | func: FunctionId, |
748 | } | 760 | } |
749 | 761 | ||
750 | pub struct Param { | ||
751 | _ty: (), | ||
752 | } | ||
753 | |||
754 | impl SelfParam { | 762 | impl SelfParam { |
755 | pub fn access(self, db: &dyn HirDatabase) -> Access { | 763 | pub fn access(self, db: &dyn HirDatabase) -> Access { |
756 | let func_data = db.function_data(self.func); | 764 | let func_data = db.function_data(self.func); |
@@ -1100,6 +1108,12 @@ impl Local { | |||
1100 | ast.map_left(|it| it.cast().unwrap().to_node(&root)).map_right(|it| it.to_node(&root)) | 1108 | ast.map_left(|it| it.cast().unwrap().to_node(&root)).map_right(|it| it.to_node(&root)) |
1101 | }) | 1109 | }) |
1102 | } | 1110 | } |
1111 | |||
1112 | pub fn can_unify(self, other: Type, db: &dyn HirDatabase) -> bool { | ||
1113 | let def = DefWithBodyId::from(self.parent); | ||
1114 | let infer = db.infer(def); | ||
1115 | db.can_unify(def, infer[self.pat_id].clone(), other.ty.value) | ||
1116 | } | ||
1103 | } | 1117 | } |
1104 | 1118 | ||
1105 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 1119 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
@@ -1276,6 +1290,14 @@ impl Type { | |||
1276 | ) | 1290 | ) |
1277 | } | 1291 | } |
1278 | 1292 | ||
1293 | pub fn remove_ref(&self) -> Option<Type> { | ||
1294 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(_), .. }) = self.ty.value { | ||
1295 | self.ty.value.substs().map(|substs| self.derived(substs[0].clone())) | ||
1296 | } else { | ||
1297 | None | ||
1298 | } | ||
1299 | } | ||
1300 | |||
1279 | pub fn is_unknown(&self) -> bool { | 1301 | pub fn is_unknown(&self) -> bool { |
1280 | matches!(self.ty.value, Ty::Unknown) | 1302 | matches!(self.ty.value, Ty::Unknown) |
1281 | } | 1303 | } |
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs index 25cf9eb7f..57e60c53b 100644 --- a/crates/hir_ty/src/db.rs +++ b/crates/hir_ty/src/db.rs | |||
@@ -26,6 +26,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
26 | #[salsa::invoke(crate::infer::infer_query)] | 26 | #[salsa::invoke(crate::infer::infer_query)] |
27 | fn infer_query(&self, def: DefWithBodyId) -> Arc<InferenceResult>; | 27 | fn infer_query(&self, def: DefWithBodyId) -> Arc<InferenceResult>; |
28 | 28 | ||
29 | #[salsa::invoke(crate::infer::can_unify)] | ||
30 | fn can_unify(&self, def: DefWithBodyId, ty1: Ty, ty2: Ty) -> bool; | ||
31 | |||
29 | #[salsa::invoke(crate::lower::ty_query)] | 32 | #[salsa::invoke(crate::lower::ty_query)] |
30 | #[salsa::cycle(crate::lower::ty_recover)] | 33 | #[salsa::cycle(crate::lower::ty_recover)] |
31 | fn ty(&self, def: TyDefId) -> Binders<Ty>; | 34 | fn ty(&self, def: TyDefId) -> Binders<Ty>; |
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index 03b00b101..d461e077b 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -55,7 +55,7 @@ macro_rules! ty_app { | |||
55 | }; | 55 | }; |
56 | } | 56 | } |
57 | 57 | ||
58 | mod unify; | 58 | pub mod unify; |
59 | mod path; | 59 | mod path; |
60 | mod expr; | 60 | mod expr; |
61 | mod pat; | 61 | mod pat; |
@@ -78,6 +78,19 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer | |||
78 | Arc::new(ctx.resolve_all()) | 78 | Arc::new(ctx.resolve_all()) |
79 | } | 79 | } |
80 | 80 | ||
81 | pub(crate) fn can_unify(db: &dyn HirDatabase, def: DefWithBodyId, ty1: Ty, ty2: Ty) -> bool { | ||
82 | let resolver = def.resolver(db.upcast()); | ||
83 | let mut ctx = InferenceContext::new(db, def, resolver); | ||
84 | |||
85 | let ty1 = ctx.canonicalizer().canonicalize_ty(ty1).value; | ||
86 | let ty2 = ctx.canonicalizer().canonicalize_ty(ty2).value; | ||
87 | let mut kinds = Vec::from(ty1.kinds.to_vec()); | ||
88 | kinds.extend_from_slice(ty2.kinds.as_ref()); | ||
89 | let tys = crate::Canonical::new((ty1.value, ty2.value), kinds); | ||
90 | |||
91 | unify(&tys).is_some() | ||
92 | } | ||
93 | |||
81 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | 94 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
82 | enum ExprOrPatId { | 95 | enum ExprOrPatId { |
83 | ExprId(ExprId), | 96 | ExprId(ExprId), |
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 1e748476a..681f98bde 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -43,7 +43,7 @@ use crate::{ | |||
43 | }; | 43 | }; |
44 | 44 | ||
45 | pub use autoderef::autoderef; | 45 | pub use autoderef::autoderef; |
46 | pub use infer::{InferTy, InferenceResult}; | 46 | pub use infer::{unify, InferTy, InferenceResult}; |
47 | pub use lower::CallableDefId; | 47 | pub use lower::CallableDefId; |
48 | pub use lower::{ | 48 | pub use lower::{ |
49 | associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId, | 49 | associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId, |
diff --git a/crates/ide/src/completion/presentation.rs b/crates/ide/src/completion/presentation.rs index 24c507f9b..cfcb6dfa1 100644 --- a/crates/ide/src/completion/presentation.rs +++ b/crates/ide/src/completion/presentation.rs | |||
@@ -191,6 +191,22 @@ impl Completions { | |||
191 | func: hir::Function, | 191 | func: hir::Function, |
192 | local_name: Option<String>, | 192 | local_name: Option<String>, |
193 | ) { | 193 | ) { |
194 | fn add_arg(arg: &str, ty: &Type, ctx: &CompletionContext) -> String { | ||
195 | let mut prefix = ""; | ||
196 | if let Some(derefed_ty) = ty.remove_ref() { | ||
197 | ctx.scope.process_all_names(&mut |name, scope| { | ||
198 | if prefix != "" { | ||
199 | return; | ||
200 | } | ||
201 | if let ScopeDef::Local(local) = scope { | ||
202 | if name.to_string() == arg && local.can_unify(derefed_ty.clone(), ctx.db) { | ||
203 | prefix = if ty.is_mutable_reference() { "&mut " } else { "&" }; | ||
204 | } | ||
205 | } | ||
206 | }); | ||
207 | } | ||
208 | prefix.to_string() + arg | ||
209 | }; | ||
194 | let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); | 210 | let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); |
195 | let ast_node = func.source(ctx.db).value; | 211 | let ast_node = func.source(ctx.db).value; |
196 | 212 | ||
@@ -205,12 +221,20 @@ impl Completions { | |||
205 | .set_deprecated(is_deprecated(func, ctx.db)) | 221 | .set_deprecated(is_deprecated(func, ctx.db)) |
206 | .detail(function_declaration(&ast_node)); | 222 | .detail(function_declaration(&ast_node)); |
207 | 223 | ||
224 | let params_ty = func.params(ctx.db); | ||
208 | let params = ast_node | 225 | let params = ast_node |
209 | .param_list() | 226 | .param_list() |
210 | .into_iter() | 227 | .into_iter() |
211 | .flat_map(|it| it.params()) | 228 | .flat_map(|it| it.params()) |
212 | .flat_map(|it| it.pat()) | 229 | .zip(params_ty) |
213 | .map(|pat| pat.to_string().trim_start_matches('_').into()) | 230 | .flat_map(|(it, param_ty)| { |
231 | if let Some(pat) = it.pat() { | ||
232 | let name = pat.to_string(); | ||
233 | let arg = name.trim_start_matches('_'); | ||
234 | return Some(add_arg(arg, ¶m_ty, ctx)); | ||
235 | } | ||
236 | None | ||
237 | }) | ||
214 | .collect(); | 238 | .collect(); |
215 | 239 | ||
216 | builder = builder.add_call_parens(ctx, name, Params::Named(params)); | 240 | builder = builder.add_call_parens(ctx, name, Params::Named(params)); |
@@ -864,6 +888,85 @@ fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 } | |||
864 | } | 888 | } |
865 | 889 | ||
866 | #[test] | 890 | #[test] |
891 | fn insert_ref_when_matching_local_in_scope() { | ||
892 | check_edit( | ||
893 | "ref_arg", | ||
894 | r#" | ||
895 | struct Foo {} | ||
896 | fn ref_arg(x: &Foo) {} | ||
897 | fn main() { | ||
898 | let x = Foo {}; | ||
899 | ref_ar<|> | ||
900 | } | ||
901 | "#, | ||
902 | r#" | ||
903 | struct Foo {} | ||
904 | fn ref_arg(x: &Foo) {} | ||
905 | fn main() { | ||
906 | let x = Foo {}; | ||
907 | ref_arg(${1:&x})$0 | ||
908 | } | ||
909 | "#, | ||
910 | ); | ||
911 | } | ||
912 | |||
913 | #[test] | ||
914 | fn insert_mut_ref_when_matching_local_in_scope() { | ||
915 | check_edit( | ||
916 | "ref_arg", | ||
917 | r#" | ||
918 | struct Foo {} | ||
919 | fn ref_arg(x: &mut Foo) {} | ||
920 | fn main() { | ||
921 | let x = Foo {}; | ||
922 | ref_ar<|> | ||
923 | } | ||
924 | "#, | ||
925 | r#" | ||
926 | struct Foo {} | ||
927 | fn ref_arg(x: &mut Foo) {} | ||
928 | fn main() { | ||
929 | let x = Foo {}; | ||
930 | ref_arg(${1:&mut x})$0 | ||
931 | } | ||
932 | "#, | ||
933 | ); | ||
934 | } | ||
935 | |||
936 | #[test] | ||
937 | fn insert_ref_when_matching_local_in_scope_for_method() { | ||
938 | check_edit( | ||
939 | "apply_foo", | ||
940 | r#" | ||
941 | struct Foo {} | ||
942 | struct Bar {} | ||
943 | impl Bar { | ||
944 | fn apply_foo(&self, x: &Foo) {} | ||
945 | } | ||
946 | |||
947 | fn main() { | ||
948 | let x = Foo {}; | ||
949 | let y = Bar {}; | ||
950 | y.<|> | ||
951 | } | ||
952 | "#, | ||
953 | r#" | ||
954 | struct Foo {} | ||
955 | struct Bar {} | ||
956 | impl Bar { | ||
957 | fn apply_foo(&self, x: &Foo) {} | ||
958 | } | ||
959 | |||
960 | fn main() { | ||
961 | let x = Foo {}; | ||
962 | let y = Bar {}; | ||
963 | y.apply_foo(${1:&x})$0 | ||
964 | } | ||
965 | "#, | ||
966 | ); | ||
967 | } | ||
968 | |||
969 | #[test] | ||
867 | fn inserts_parens_for_tuple_enums() { | 970 | fn inserts_parens_for_tuple_enums() { |
868 | mark::check!(inserts_parens_for_tuple_enums); | 971 | mark::check!(inserts_parens_for_tuple_enums); |
869 | check_edit( | 972 | check_edit( |