Don't emit `CrateInfo` from `rust_static_library` and `rust_shared_library` (#1298)

These rules emit a `staticlib` and `cdylib` which are not meant for consumption by other rust targets.

However, one should still be able to write a `rust_test` for `rust_shared_library` and `rust_static_library` targets, which needs a `CrateInfo`. For this purpose we provide a `CrateInfo` wrapped in a `TestCrateInfo` provider, that `rust_test` understands. 
diff --git a/rust/private/common.bzl b/rust/private/common.bzl
index 021a197..ebf2b7e 100644
--- a/rust/private/common.bzl
+++ b/rust/private/common.bzl
@@ -23,7 +23,7 @@
 In the Bazel lingo, `rust_common` gives the access to the Rust Sandwich API.
 """
 
-load(":providers.bzl", "CrateInfo", "DepInfo", "StdLibInfo")
+load(":providers.bzl", "CrateInfo", "DepInfo", "StdLibInfo", "TestCrateInfo")
 
 # This constant only represents the default value for attributes and macros
 # defined in `rules_rust`. Like any attribute public attribute, it can be
@@ -54,5 +54,6 @@
     crate_info = CrateInfo,
     dep_info = DepInfo,
     stdlib_info = StdLibInfo,
+    test_crate_info = TestCrateInfo,
     default_version = DEFAULT_RUST_VERSION,
 )
diff --git a/rust/private/providers.bzl b/rust/private/providers.bzl
index b471ac0..3f5d8fc 100644
--- a/rust/private/providers.bzl
+++ b/rust/private/providers.bzl
@@ -107,3 +107,15 @@
         "output": "File with the clippy output.",
     },
 )
+
+TestCrateInfo = provider(
+    doc = "A wrapper around a CrateInfo. " +
+          "Certain rule types, like rust_static_library and rust_shared_library " +
+          "are not intended for consumption by other Rust targets, and should not " +
+          "provide a CrateInfo. However, one should still be able to write a rust_test " +
+          "for them. Thus, we create a CrateInfo, but do not advertise it as such, " +
+          "but rather through this provider, that rust_test understands.",
+    fields = {
+        "crate": "CrateInfo: The underlying CrateInfo of the dependency",
+    },
+)
diff --git a/rust/private/rust.bzl b/rust/private/rust.bzl
index 6a7f230..f3a874a 100644
--- a/rust/private/rust.bzl
+++ b/rust/private/rust.bzl
@@ -353,7 +353,7 @@
 
     if ctx.attr.crate:
         # Target is building the crate in `test` config
-        crate = ctx.attr.crate[rust_common.crate_info]
+        crate = ctx.attr.crate[rust_common.crate_info] if rust_common.crate_info in ctx.attr.crate else ctx.attr.crate[rust_common.test_crate_info].crate
 
         # Optionally join compile data
         if crate.compile_data:
@@ -745,7 +745,6 @@
 
 rust_static_library = rule(
     implementation = _rust_static_library_impl,
-    provides = _common_providers,
     attrs = dict(_common_attrs.items()),
     fragments = ["cpp"],
     host_fragments = ["cpp"],
@@ -769,7 +768,6 @@
 
 rust_shared_library = rule(
     implementation = _rust_shared_library_impl,
-    provides = _common_providers,
     attrs = dict(_common_attrs.items()),
     fragments = ["cpp"],
     host_fragments = ["cpp"],
diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl
index 2055f25..b8428f2 100644
--- a/rust/private/rustc.bzl
+++ b/rust/private/rustc.bzl
@@ -986,8 +986,6 @@
     out_binary = getattr(attr, "out_binary", False)
 
     providers = [
-        crate_info,
-        dep_info,
         DefaultInfo(
             # nb. This field is required for cc_library to depend on our output.
             files = depset(outputs),
@@ -995,6 +993,16 @@
             executable = crate_info.output if crate_info.type == "bin" or crate_info.is_test or out_binary else None,
         ),
     ]
+
+    if crate_info.type in ["staticlib", "cdylib"]:
+        # These rules are not supposed to be depended on by other rust targets, and
+        # as such they shouldn't provide a CrateInfo. However, one may still want to
+        # write a rust_test for them, so we provide the CrateInfo wrapped in a provider
+        # that rust_test understands.
+        providers.extend([rust_common.test_crate_info(crate = crate_info), dep_info])
+    else:
+        providers.extend([crate_info, dep_info])
+
     if toolchain.target_arch != "wasm32":
         providers += establish_cc_info(ctx, attr, crate_info, toolchain, cc_toolchain, feature_configuration, interface_library)
     if pdb_file:
diff --git a/test/unit/crate_info/BUILD.bazel b/test/unit/crate_info/BUILD.bazel
new file mode 100644
index 0000000..98a3ef0
--- /dev/null
+++ b/test/unit/crate_info/BUILD.bazel
@@ -0,0 +1,4 @@
+load(":crate_info_test.bzl", "crate_info_test_suite")
+
+############################ UNIT TESTS #############################
+crate_info_test_suite(name = "crate_info_test_suite")
diff --git a/test/unit/crate_info/crate_info_test.bzl b/test/unit/crate_info/crate_info_test.bzl
new file mode 100644
index 0000000..0f6dfd0
--- /dev/null
+++ b/test/unit/crate_info/crate_info_test.bzl
@@ -0,0 +1,102 @@
+"""Unittests for rust rules."""
+
+load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
+load(
+    "//rust:defs.bzl",
+    "rust_common",
+    "rust_library",
+    "rust_proc_macro",
+    "rust_shared_library",
+    "rust_static_library",
+)
+
+def _rule_provides_crate_info_test_impl(ctx):
+    env = analysistest.begin(ctx)
+    tut = analysistest.target_under_test(env)
+    asserts.true(
+        env,
+        rust_common.crate_info in tut,
+        "{} should provide CrateInfo".format(tut.label.name),
+    )
+    return analysistest.end(env)
+
+def _rule_does_not_provide_crate_info_test_impl(ctx):
+    env = analysistest.begin(ctx)
+    tut = analysistest.target_under_test(env)
+    asserts.false(
+        env,
+        rust_common.crate_info in tut,
+        "{} should not provide CrateInfo".format(tut.label.name),
+    )
+    asserts.true(
+        env,
+        rust_common.test_crate_info in tut,
+        "{} should provide a TestCrateInfo".format(tut.label.name),
+    )
+    return analysistest.end(env)
+
+rule_provides_crate_info_test = analysistest.make(_rule_provides_crate_info_test_impl)
+rule_does_not_provide_crate_info_test = analysistest.make(_rule_does_not_provide_crate_info_test_impl)
+
+def _crate_info_test():
+    rust_library(
+        name = "rlib",
+        srcs = ["lib.rs"],
+        edition = "2018",
+    )
+
+    rust_proc_macro(
+        name = "proc_macro",
+        srcs = ["lib.rs"],
+        edition = "2018",
+    )
+
+    rust_static_library(
+        name = "staticlib",
+        srcs = ["lib.rs"],
+        edition = "2018",
+    )
+
+    rust_shared_library(
+        name = "cdylib",
+        srcs = ["lib.rs"],
+        edition = "2018",
+    )
+
+    rule_provides_crate_info_test(
+        name = "rlib_provides_crate_info_test",
+        target_under_test = ":rlib",
+    )
+
+    rule_provides_crate_info_test(
+        name = "proc_macro_provides_crate_info_test",
+        target_under_test = ":proc_macro",
+    )
+
+    rule_does_not_provide_crate_info_test(
+        name = "cdylib_does_not_provide_crate_info_test",
+        target_under_test = ":cdylib",
+    )
+
+    rule_does_not_provide_crate_info_test(
+        name = "staticlib_does_not_provide_crate_info_test",
+        target_under_test = ":staticlib",
+    )
+
+def crate_info_test_suite(name):
+    """Entry-point macro called from the BUILD file.
+
+    Args:
+        name: Name of the macro.
+    """
+    _crate_info_test()
+
+    native.test_suite(
+        name = name,
+        tests = [
+            ":rlib_provides_crate_info_test",
+            ":proc_macro_provides_crate_info_test",
+            ":cdylib_does_not_provide_crate_info_test",
+            ":staticlib_does_not_provide_crate_info_test",
+        ],
+    )
diff --git a/test/unit/crate_info/lib.rs b/test/unit/crate_info/lib.rs
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/test/unit/crate_info/lib.rs
@@ -0,0 +1 @@
+