aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authoradamrk <[email protected]>2020-08-22 19:11:37 +0100
committeradamrk <[email protected]>2020-08-30 11:34:32 +0100
commitc6ddb907144688ae77a6de3666159feef53638e1 (patch)
treea560689c0ff6a35b7ed6a6738c48524730a60263 /crates
parentac4b134c6be27642dbe915f32a41f9a21bd0c1c9 (diff)
Add references to fn args during completion
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/code_model.rs34
-rw-r--r--crates/hir_ty/src/db.rs3
-rw-r--r--crates/hir_ty/src/infer.rs15
-rw-r--r--crates/hir_ty/src/lib.rs2
-rw-r--r--crates/ide/src/completion/presentation.rs107
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
750pub struct Param {
751 _ty: (),
752}
753
754impl SelfParam { 762impl 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
58mod unify; 58pub mod unify;
59mod path; 59mod path;
60mod expr; 60mod expr;
61mod pat; 61mod 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
81pub(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)]
82enum ExprOrPatId { 95enum 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
45pub use autoderef::autoderef; 45pub use autoderef::autoderef;
46pub use infer::{InferTy, InferenceResult}; 46pub use infer::{unify, InferTy, InferenceResult};
47pub use lower::CallableDefId; 47pub use lower::CallableDefId;
48pub use lower::{ 48pub 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, &param_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#"
895struct Foo {}
896fn ref_arg(x: &Foo) {}
897fn main() {
898 let x = Foo {};
899 ref_ar<|>
900}
901"#,
902 r#"
903struct Foo {}
904fn ref_arg(x: &Foo) {}
905fn 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#"
918struct Foo {}
919fn ref_arg(x: &mut Foo) {}
920fn main() {
921 let x = Foo {};
922 ref_ar<|>
923}
924"#,
925 r#"
926struct Foo {}
927fn ref_arg(x: &mut Foo) {}
928fn 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#"
941struct Foo {}
942struct Bar {}
943impl Bar {
944 fn apply_foo(&self, x: &Foo) {}
945}
946
947fn main() {
948 let x = Foo {};
949 let y = Bar {};
950 y.<|>
951}
952"#,
953 r#"
954struct Foo {}
955struct Bar {}
956impl Bar {
957 fn apply_foo(&self, x: &Foo) {}
958}
959
960fn 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(