Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/expr_store/tests/signatures.rs')
-rw-r--r--crates/hir-def/src/expr_store/tests/signatures.rs190
1 files changed, 190 insertions, 0 deletions
diff --git a/crates/hir-def/src/expr_store/tests/signatures.rs b/crates/hir-def/src/expr_store/tests/signatures.rs
new file mode 100644
index 0000000000..80561d6470
--- /dev/null
+++ b/crates/hir-def/src/expr_store/tests/signatures.rs
@@ -0,0 +1,190 @@
+use crate::{
+ GenericDefId, ModuleDefId,
+ expr_store::pretty::{print_function, print_struct},
+ test_db::TestDB,
+};
+use expect_test::{Expect, expect};
+use test_fixture::WithFixture;
+
+use super::super::*;
+
+fn lower_and_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
+ let db = TestDB::with_files(ra_fixture);
+
+ let krate = db.fetch_test_crate();
+ let def_map = db.crate_def_map(krate);
+ let mut defs = vec![];
+ for (_, module) in def_map.modules() {
+ for decl in module.scope.declarations() {
+ let def: GenericDefId = match decl {
+ ModuleDefId::ModuleId(_) => continue,
+ ModuleDefId::FunctionId(id) => id.into(),
+ ModuleDefId::AdtId(id) => id.into(),
+ ModuleDefId::ConstId(id) => id.into(),
+ ModuleDefId::StaticId(id) => id.into(),
+ ModuleDefId::TraitId(id) => id.into(),
+ ModuleDefId::TraitAliasId(id) => id.into(),
+ ModuleDefId::TypeAliasId(id) => id.into(),
+ ModuleDefId::EnumVariantId(_) => continue,
+ ModuleDefId::BuiltinType(_) => continue,
+ ModuleDefId::MacroId(_) => continue,
+ };
+ defs.push(def);
+ }
+ }
+
+ let mut out = String::new();
+ for def in defs {
+ match def {
+ GenericDefId::AdtId(adt_id) => match adt_id {
+ crate::AdtId::StructId(struct_id) => {
+ out += &print_struct(&db, &db.struct_signature(struct_id), Edition::CURRENT);
+ }
+ crate::AdtId::UnionId(_id) => (),
+ crate::AdtId::EnumId(_id) => (),
+ },
+ GenericDefId::ConstId(_id) => (),
+ GenericDefId::FunctionId(function_id) => {
+ out += &print_function(&db, &db.function_signature(function_id), Edition::CURRENT)
+ }
+
+ GenericDefId::ImplId(_id) => (),
+ GenericDefId::StaticId(_id) => (),
+ GenericDefId::TraitAliasId(_id) => (),
+ GenericDefId::TraitId(_id) => (),
+ GenericDefId::TypeAliasId(_id) => (),
+ }
+ }
+
+ expect.assert_eq(&out);
+}
+
+#[test]
+fn structs() {
+ lower_and_print(
+ r"
+struct S { field: foo, }
+struct S(i32, u32, &'static str);
+#[repr(Rust)]
+struct S;
+
+struct S<'a, 'b, T: Clone, const C: usize = 3, X = ()> where X: Default, for<'a, 'c> fn() -> i32: for<'b> Trait<'a, Item = Boo>;
+#[repr(C, packed)]
+struct S {}
+",
+ expect![[r#"
+ struct S {...}
+ struct S(...)
+ ;
+ struct S;
+ struct S<'a, 'b, T, const C: usize = 3, X = ()>
+ where
+ T: Clone,
+ X: Default,
+ for<'a, 'c> fn() -> i32: for<'b> Trait::<'a, Item = Boo>
+ ;
+ #[repr(C)]
+ #[repr(pack(1))]
+ struct S {...}
+ "#]],
+ );
+}
+
+#[test]
+fn functions() {
+ lower_and_print(
+ r#"
+fn foo<'a, const C: usize = 314235, T: Trait<Item = A> = B>(Struct { foo: bar }: &Struct, _: (), a: u32) -> &'a dyn Fn() -> i32 where (): Default {}
+const async unsafe extern "C" fn a() {}
+fn ret_impl_trait() -> impl Trait {}
+"#,
+ expect![[r#"
+ fn foo<'a, const C: usize = 314235, T = B>(&Struct, (), u32) -> &'a dyn Fn::<(), Output = i32>
+ where
+ T: Trait::<Item = A>,
+ (): Default
+ {...}
+ const async unsafe extern "C" fn a() -> impl ::core::future::Future::<Output = ()> {...}
+ fn ret_impl_trait() -> impl Trait {...}
+ "#]],
+ );
+}
+
+#[test]
+fn argument_position_impl_trait_functions() {
+ lower_and_print(
+ r"
+fn impl_trait_args<T>(_: impl Trait) {}
+fn impl_trait_args2<T>(_: impl Trait<impl Trait>) {}
+
+fn impl_trait_ret<T>() -> impl Trait {}
+fn impl_trait_ret2<T>() -> impl Trait<impl Trait> {}
+
+fn not_allowed1(f: impl Fn(impl Foo)) {
+ let foo = S;
+ f(foo);
+}
+
+// This caused stack overflow in #17498
+fn not_allowed2(f: impl Fn(&impl Foo)) {
+ let foo = S;
+ f(&foo);
+}
+
+fn not_allowed3(bar: impl Bar<impl Foo>) {}
+
+// This also caused stack overflow
+fn not_allowed4(bar: impl Bar<&impl Foo>) {}
+
+fn allowed1(baz: impl Baz<Assoc = impl Foo>) {}
+
+fn allowed2<'a>(baz: impl Baz<Assoc = &'a (impl Foo + 'a)>) {}
+
+fn allowed3(baz: impl Baz<Assoc = Qux<impl Foo>>) {}
+",
+ expect![[r#"
+ fn impl_trait_args<T, Param[1]>(Param[1])
+ where
+ Param[1]: Trait
+ {...}
+ fn impl_trait_args2<T, Param[1]>(Param[1])
+ where
+ Param[1]: Trait::<{error}>
+ {...}
+ fn impl_trait_ret<T>() -> impl Trait {...}
+ fn impl_trait_ret2<T>() -> impl Trait::<{error}> {...}
+ fn not_allowed1<Param[0]>(Param[0])
+ where
+ Param[0]: Fn::<({error}), Output = ()>
+ {...}
+ fn not_allowed2<Param[0]>(Param[0])
+ where
+ Param[0]: Fn::<(&{error}), Output = ()>
+ {...}
+ fn not_allowed3<Param[0]>(Param[0])
+ where
+ Param[0]: Bar::<{error}>
+ {...}
+ fn not_allowed4<Param[0]>(Param[0])
+ where
+ Param[0]: Bar::<&{error}>
+ {...}
+ fn allowed1<Param[0], Param[1]>(Param[1])
+ where
+ Param[0]: Foo,
+ Param[1]: Baz::<Assoc = Param[0]>
+ {...}
+ fn allowed2<'a, Param[0], Param[1]>(Param[1])
+ where
+ Param[0]: Foo,
+ Param[0]: 'a,
+ Param[1]: Baz::<Assoc = &'a Param[0]>
+ {...}
+ fn allowed3<Param[0], Param[1]>(Param[1])
+ where
+ Param[0]: Foo,
+ Param[1]: Baz::<Assoc = Qux::<Param[0]>>
+ {...}
+ "#]],
+ );
+}