Skip to content

Commit 93527b5

Browse files
Merge #3574
3574: Fix completion of HashMap::new r=matklad a=flodiebold 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.) The `ty` function for fields was used for signature help, so there we want placeholders so that it looks nicer, I think. Hence I renamed it to `signature_ty`. Co-authored-by: Florian Diebold <[email protected]>
2 parents 02b4400 + d6195fa commit 93527b5

File tree

5 files changed

+62
-6
lines changed

5 files changed

+62
-6
lines changed

crates/ra_hir/src/code_model.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,11 @@ impl StructField {
311311
self.parent.variant_data(db).fields()[self.id].name.clone()
312312
}
313313

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 {
315319
let var_id = self.parent.into();
316320
let generic_def_id: GenericDefId = match self.parent {
317321
VariantDef::Struct(it) => it.id.into(),
@@ -485,6 +489,10 @@ impl Adt {
485489
let subst = db.generic_defaults(self.into());
486490
subst.iter().any(|ty| ty == &Ty::Unknown)
487491
}
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.
488496
pub fn ty(self, db: &impl HirDatabase) -> Type {
489497
let id = AdtId::from(self);
490498
Type::from_def(db, id.module(db).krate, id)
@@ -1031,7 +1039,7 @@ impl Type {
10311039
krate: CrateId,
10321040
def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>,
10331041
) -> Type {
1034-
let substs = Substs::type_params(db, def);
1042+
let substs = Substs::build_for_def(db, def).fill_with_unknown().build();
10351043
let ty = db.ty(def.into()).subst(&substs);
10361044
Type::new(db, krate, def, ty)
10371045
}

crates/ra_ide/src/call_info.rs

+14
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,20 @@ fn main() {
543543
assert_eq!(info.active_parameter, Some(1));
544544
}
545545

546+
#[test]
547+
fn generic_struct() {
548+
let info = call_info(
549+
r#"
550+
struct TS<T>(T);
551+
fn 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+
546560
#[test]
547561
#[should_panic]
548562
fn cant_call_named_structs() {

crates/ra_ide/src/completion/complete_path.rs

+32
Original file line numberDiff line numberDiff line change
@@ -1005,4 +1005,36 @@ mod tests {
10051005
"###
10061006
);
10071007
}
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+
}
10081040
}

crates/ra_ide/src/completion/presentation.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,10 @@ impl Completions {
273273
pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) {
274274
let is_deprecated = is_deprecated(variant, ctx.db);
275275
let name = variant.name(ctx.db);
276-
let detail_types =
277-
variant.fields(ctx.db).into_iter().map(|field| (field.name(ctx.db), field.ty(ctx.db)));
276+
let detail_types = variant
277+
.fields(ctx.db)
278+
.into_iter()
279+
.map(|field| (field.name(ctx.db), field.signature_ty(ctx.db)));
278280
let detail = match variant.kind(ctx.db) {
279281
StructKind::Tuple | StructKind::Unit => {
280282
join(detail_types.map(|(_, t)| t.display(ctx.db).to_string()))

crates/ra_ide/src/display/function_signature.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl FunctionSignature {
6464
.fields(db)
6565
.into_iter()
6666
.map(|field: hir::StructField| {
67-
let ty = field.ty(db);
67+
let ty = field.signature_ty(db);
6868
format!("{}", ty.display(db))
6969
})
7070
.collect();
@@ -102,7 +102,7 @@ impl FunctionSignature {
102102
.into_iter()
103103
.map(|field: hir::StructField| {
104104
let name = field.name(db);
105-
let ty = field.ty(db);
105+
let ty = field.signature_ty(db);
106106
format!("{}: {}", name, ty.display(db))
107107
})
108108
.collect();

0 commit comments

Comments
 (0)