Skip to content

Commit 995a928

Browse files
Merge #3490
3490: Support aliases and Self in struct literals r=matklad a=flodiebold Fixes #3306. Co-authored-by: Florian Diebold <florian.diebold@freiheit.com>
2 parents 13879af + 073a1ef commit 995a928

File tree

3 files changed

+95
-1
lines changed

3 files changed

+95
-1
lines changed

crates/ra_hir_ty/src/infer.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
425425
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
426426
// FIXME: this should resolve assoc items as well, see this example:
427427
// https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
428-
match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) {
428+
return match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) {
429429
Some(TypeNs::AdtId(AdtId::StructId(strukt))) => {
430430
let substs = Ty::substs_from_path(&ctx, path, strukt.into());
431431
let ty = self.db.ty(strukt.into());
@@ -438,7 +438,33 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
438438
let ty = self.insert_type_vars(ty.subst(&substs));
439439
(ty, Some(var.into()))
440440
}
441+
Some(TypeNs::SelfType(impl_id)) => {
442+
let generics = crate::utils::generics(self.db, impl_id.into());
443+
let substs = Substs::type_params_for_generics(&generics);
444+
let ty = self.db.impl_self_ty(impl_id).subst(&substs);
445+
let variant = ty_variant(&ty);
446+
(ty, variant)
447+
}
448+
Some(TypeNs::TypeAliasId(it)) => {
449+
let substs = Substs::build_for_def(self.db, it)
450+
.fill(std::iter::repeat_with(|| self.table.new_type_var()))
451+
.build();
452+
let ty = self.db.ty(it.into()).subst(&substs);
453+
let variant = ty_variant(&ty);
454+
(ty, variant)
455+
}
441456
Some(_) | None => (Ty::Unknown, None),
457+
};
458+
459+
fn ty_variant(ty: &Ty) -> Option<VariantId> {
460+
ty.as_adt().and_then(|(adt_id, _)| match adt_id {
461+
AdtId::StructId(s) => Some(VariantId::StructId(s)),
462+
AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
463+
AdtId::EnumId(_) => {
464+
// Error E0071, expected struct, variant or union type, found enum `Foo`
465+
None
466+
}
467+
})
442468
}
443469
}
444470

crates/ra_hir_ty/src/tests/simple.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,47 @@ fn test() {
5050
assert_eq!("Nat", type_at_pos(&db, pos));
5151
}
5252

53+
#[test]
54+
fn self_in_struct_lit() {
55+
assert_snapshot!(infer(
56+
r#"
57+
//- /main.rs
58+
struct S<T> { x: T }
59+
60+
impl S<u32> {
61+
fn foo() {
62+
Self { x: 1 };
63+
}
64+
}
65+
"#,
66+
), @r###"
67+
[63; 93) '{ ... }': ()
68+
[73; 86) 'Self { x: 1 }': S<u32>
69+
[83; 84) '1': u32
70+
"###);
71+
}
72+
73+
#[test]
74+
fn type_alias_in_struct_lit() {
75+
assert_snapshot!(infer(
76+
r#"
77+
//- /main.rs
78+
struct S<T> { x: T }
79+
80+
type SS = S<u32>;
81+
82+
fn foo() {
83+
SS { x: 1 };
84+
}
85+
86+
"#,
87+
), @r###"
88+
[64; 84) '{ ...1 }; }': ()
89+
[70; 81) 'SS { x: 1 }': S<u32>
90+
[78; 79) '1': u32
91+
"###);
92+
}
93+
5394
#[test]
5495
fn infer_ranges() {
5596
let (db, pos) = TestDB::with_position(

crates/ra_ide/src/diagnostics.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,33 @@ mod tests {
472472
check_apply_diagnostic_fix(before, after);
473473
}
474474

475+
#[test]
476+
fn test_fill_struct_fields_self() {
477+
let before = r"
478+
struct TestStruct {
479+
one: i32,
480+
}
481+
482+
impl TestStruct {
483+
fn test_fn() {
484+
let s = Self {};
485+
}
486+
}
487+
";
488+
let after = r"
489+
struct TestStruct {
490+
one: i32,
491+
}
492+
493+
impl TestStruct {
494+
fn test_fn() {
495+
let s = Self { one: ()};
496+
}
497+
}
498+
";
499+
check_apply_diagnostic_fix(before, after);
500+
}
501+
475502
#[test]
476503
fn test_fill_struct_fields_enum() {
477504
let before = r"

0 commit comments

Comments
 (0)