aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-03-13 10:45:58 +0000
committerFlorian Diebold <[email protected]>2020-03-13 12:04:32 +0000
commitd6195fa21f09aa3f987e09d847c156e1788ec834 (patch)
treefda6b0e03da9ef7fc7426dbf785bd6c050e845dd
parent02b44006b8e37a8cd3f96d5b1c949d62e01be2e8 (diff)
Fix completion of HashMap::new
The `ty` function in code_model returned the type with placeholders for type parameters. That's nice for printing, but not good for completion, because placeholders won't unify with anything else: So the type we got for `HashMap` was `HashMap<K, V, T>`, which doesn't unify with `HashMap<?, ?, RandomState>`, so the `new` method wasn't shown. Now we instead return `HashMap<{unknown}, {unknown}, {unknown}>`, which does unify with the impl type. Maybe we should just expose this properly as variables though, i.e. we'd return something like `exists<type, type, type> HashMap<?0, ?1, ?2>` (in Chalk notation). It'll make the API more complicated, but harder to misuse. (And it would handle cases like `type TypeAlias<T> = HashMap<T, T>` more correctly.)
-rw-r--r--crates/ra_hir/src/code_model.rs12
-rw-r--r--crates/ra_ide/src/call_info.rs14
-rw-r--r--crates/ra_ide/src/completion/complete_path.rs32
-rw-r--r--crates/ra_ide/src/completion/presentation.rs6
-rw-r--r--crates/ra_ide/src/display/function_signature.rs4
5 files changed, 62 insertions, 6 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 2854631c6..ff041150b 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -311,7 +311,11 @@ impl StructField {
311 self.parent.variant_data(db).fields()[self.id].name.clone() 311 self.parent.variant_data(db).fields()[self.id].name.clone()
312 } 312 }
313 313
314 pub fn ty(&self, db: &impl HirDatabase) -> Type { 314 /// Returns the type as in the signature of the struct (i.e., with
315 /// placeholder types for type parameters). This is good for showing
316 /// signature help, but not so good to actually get the type of the field
317 /// when you actually have a variable of the struct.
318 pub fn signature_ty(&self, db: &impl HirDatabase) -> Type {
315 let var_id = self.parent.into(); 319 let var_id = self.parent.into();
316 let generic_def_id: GenericDefId = match self.parent { 320 let generic_def_id: GenericDefId = match self.parent {
317 VariantDef::Struct(it) => it.id.into(), 321 VariantDef::Struct(it) => it.id.into(),
@@ -485,6 +489,10 @@ impl Adt {
485 let subst = db.generic_defaults(self.into()); 489 let subst = db.generic_defaults(self.into());
486 subst.iter().any(|ty| ty == &Ty::Unknown) 490 subst.iter().any(|ty| ty == &Ty::Unknown)
487 } 491 }
492
493 /// Turns this ADT into a type. Any type parameters of the ADT will be
494 /// turned into unknown types, which is good for e.g. finding the most
495 /// general set of completions, but will not look very nice when printed.
488 pub fn ty(self, db: &impl HirDatabase) -> Type { 496 pub fn ty(self, db: &impl HirDatabase) -> Type {
489 let id = AdtId::from(self); 497 let id = AdtId::from(self);
490 Type::from_def(db, id.module(db).krate, id) 498 Type::from_def(db, id.module(db).krate, id)
@@ -1031,7 +1039,7 @@ impl Type {
1031 krate: CrateId, 1039 krate: CrateId,
1032 def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>, 1040 def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>,
1033 ) -> Type { 1041 ) -> Type {
1034 let substs = Substs::type_params(db, def); 1042 let substs = Substs::build_for_def(db, def).fill_with_unknown().build();
1035 let ty = db.ty(def.into()).subst(&substs); 1043 let ty = db.ty(def.into()).subst(&substs);
1036 Type::new(db, krate, def, ty) 1044 Type::new(db, krate, def, ty)
1037 } 1045 }
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index 2b35a3803..39d09a07f 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -544,6 +544,20 @@ fn main() {
544 } 544 }
545 545
546 #[test] 546 #[test]
547 fn generic_struct() {
548 let info = call_info(
549 r#"
550struct TS<T>(T);
551fn main() {
552 let s = TS(<|>);
553}"#,
554 );
555
556 assert_eq!(info.label(), "struct TS<T>(T) -> TS");
557 assert_eq!(info.active_parameter, Some(0));
558 }
559
560 #[test]
547 #[should_panic] 561 #[should_panic]
548 fn cant_call_named_structs() { 562 fn cant_call_named_structs() {
549 let _ = call_info( 563 let _ = call_info(
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs
index 65b3bf6e6..3db17f15f 100644
--- a/crates/ra_ide/src/completion/complete_path.rs
+++ b/crates/ra_ide/src/completion/complete_path.rs
@@ -1005,4 +1005,36 @@ mod tests {
1005 "### 1005 "###
1006 ); 1006 );
1007 } 1007 }
1008
1009 #[test]
1010 fn completes_hashmap_new() {
1011 assert_debug_snapshot!(
1012 do_reference_completion(
1013 r"
1014 struct RandomState;
1015 struct HashMap<K, V, S = RandomState> {}
1016
1017 impl<K, V> HashMap<K, V, RandomState> {
1018 pub fn new() -> HashMap<K, V, RandomState> { }
1019 }
1020 fn foo() {
1021 HashMap::<|>
1022 }
1023 "
1024 ),
1025 @r###"
1026 [
1027 CompletionItem {
1028 label: "new()",
1029 source_range: [292; 292),
1030 delete: [292; 292),
1031 insert: "new()$0",
1032 kind: Function,
1033 lookup: "new",
1034 detail: "pub fn new() -> HashMap<K, V, RandomState>",
1035 },
1036 ]
1037 "###
1038 );
1039 }
1008} 1040}
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index a4e9aefe2..910844244 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -273,8 +273,10 @@ impl Completions {
273 pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { 273 pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) {
274 let is_deprecated = is_deprecated(variant, ctx.db); 274 let is_deprecated = is_deprecated(variant, ctx.db);
275 let name = variant.name(ctx.db); 275 let name = variant.name(ctx.db);
276 let detail_types = 276 let detail_types = variant
277 variant.fields(ctx.db).into_iter().map(|field| (field.name(ctx.db), field.ty(ctx.db))); 277 .fields(ctx.db)
278 .into_iter()
279 .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db)));
278 let detail = match variant.kind(ctx.db) { 280 let detail = match variant.kind(ctx.db) {
279 StructKind::Tuple | StructKind::Unit => { 281 StructKind::Tuple | StructKind::Unit => {
280 join(detail_types.map(|(_, t)| t.display(ctx.db).to_string())) 282 join(detail_types.map(|(_, t)| t.display(ctx.db).to_string()))
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs
index 2c4c932de..ec1bbd5a0 100644
--- a/crates/ra_ide/src/display/function_signature.rs
+++ b/crates/ra_ide/src/display/function_signature.rs
@@ -64,7 +64,7 @@ impl FunctionSignature {
64 .fields(db) 64 .fields(db)
65 .into_iter() 65 .into_iter()
66 .map(|field: hir::StructField| { 66 .map(|field: hir::StructField| {
67 let ty = field.ty(db); 67 let ty = field.signature_ty(db);
68 format!("{}", ty.display(db)) 68 format!("{}", ty.display(db))
69 }) 69 })
70 .collect(); 70 .collect();
@@ -102,7 +102,7 @@ impl FunctionSignature {
102 .into_iter() 102 .into_iter()
103 .map(|field: hir::StructField| { 103 .map(|field: hir::StructField| {
104 let name = field.name(db); 104 let name = field.name(db);
105 let ty = field.ty(db); 105 let ty = field.signature_ty(db);
106 format!("{}: {}", name, ty.display(db)) 106 format!("{}: {}", name, ty.display(db))
107 }) 107 })
108 .collect(); 108 .collect();