From 073a1ef834be5e2e1ae6733c6c299d2ae68050d8 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 6 Mar 2020 15:26:49 +0100 Subject: Support aliases and Self in struct literals Fixes #3306. --- crates/ra_hir_ty/src/infer.rs | 28 +++++++++++++++++++++++- crates/ra_hir_ty/src/tests/simple.rs | 41 ++++++++++++++++++++++++++++++++++++ crates/ra_ide/src/diagnostics.rs | 27 ++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 377f44fa7..39f144216 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -425,7 +425,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); // FIXME: this should resolve assoc items as well, see this example: // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 - match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) { + return match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) { Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { let substs = Ty::substs_from_path(&ctx, path, strukt.into()); let ty = self.db.ty(strukt.into()); @@ -438,7 +438,33 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let ty = self.insert_type_vars(ty.subst(&substs)); (ty, Some(var.into())) } + Some(TypeNs::SelfType(impl_id)) => { + let generics = crate::utils::generics(self.db, impl_id.into()); + let substs = Substs::type_params_for_generics(&generics); + let ty = self.db.impl_self_ty(impl_id).subst(&substs); + let variant = ty_variant(&ty); + (ty, variant) + } + Some(TypeNs::TypeAliasId(it)) => { + let substs = Substs::build_for_def(self.db, it) + .fill(std::iter::repeat_with(|| self.table.new_type_var())) + .build(); + let ty = self.db.ty(it.into()).subst(&substs); + let variant = ty_variant(&ty); + (ty, variant) + } Some(_) | None => (Ty::Unknown, None), + }; + + fn ty_variant(ty: &Ty) -> Option { + ty.as_adt().and_then(|(adt_id, _)| match adt_id { + AdtId::StructId(s) => Some(VariantId::StructId(s)), + AdtId::UnionId(u) => Some(VariantId::UnionId(u)), + AdtId::EnumId(_) => { + // Error E0071, expected struct, variant or union type, found enum `Foo` + None + } + }) } } diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 3803f5938..c140bd513 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -50,6 +50,47 @@ fn test() { assert_eq!("Nat", type_at_pos(&db, pos)); } +#[test] +fn self_in_struct_lit() { + assert_snapshot!(infer( + r#" +//- /main.rs +struct S { x: T } + +impl S { + fn foo() { + Self { x: 1 }; + } +} +"#, + ), @r###" + [63; 93) '{ ... }': () + [73; 86) 'Self { x: 1 }': S + [83; 84) '1': u32 + "###); +} + +#[test] +fn type_alias_in_struct_lit() { + assert_snapshot!(infer( + r#" +//- /main.rs +struct S { x: T } + +type SS = S; + +fn foo() { + SS { x: 1 }; +} + +"#, + ), @r###" + [64; 84) '{ ...1 }; }': () + [70; 81) 'SS { x: 1 }': S + [78; 79) '1': u32 + "###); +} + #[test] fn infer_ranges() { let (db, pos) = TestDB::with_position( diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index a52f7fdd9..a10e642db 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs @@ -472,6 +472,33 @@ mod tests { check_apply_diagnostic_fix(before, after); } + #[test] + fn test_fill_struct_fields_self() { + let before = r" + struct TestStruct { + one: i32, + } + + impl TestStruct { + fn test_fn() { + let s = Self {}; + } + } + "; + let after = r" + struct TestStruct { + one: i32, + } + + impl TestStruct { + fn test_fn() { + let s = Self { one: ()}; + } + } + "; + check_apply_diagnostic_fix(before, after); + } + #[test] fn test_fill_struct_fields_enum() { let before = r" -- cgit v1.2.3