bazelbuild / bazelbuild/rules_rust
crate_universe: aliases attr can't reference targets that are themselves rust_library wrappers (e.g. transition aliases)
- Dominant language
- Starlark
- Stars
- 843
- Forks
- 651
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 15
Description
## Background
Tracking the chain so it's clear what this is downstream of:
- **#2312** (closed): introduced `render_config(default_alias_rule = "opt")` as a shortcut to wrap all crate_universe crates in a `compilation_mode=opt` transition.
- **#2832** (open): with `crates_vendor`, the generated BUILDs reference `@@crate_index//:alias_rules.bzl` but the file isn't shipped in the vendored output, so `default_alias_rule = "opt"` fails to load.
- Users who still want opt-mode work around #2832 by dropping a hand-rolled `alias_rules.bzl` in their workspace and pointing `default_alias_rule` at it. The natural way to write that file is to copy upstream's own `crate_universe/src/rendering/verbatim/alias_rules.bzl` verbatim (it's the canonical implementation).
- That workaround then surfaces **this** bug in `rust/private/rustc.bzl::collect_deps`.
Important to note up front: **the bug here is independent of which alias rule you use.** Upstream's verbatim `alias_rules.bzl` and the hand-rolled workaround copy are byte-identical, and either one trips this. Today the issue is mostly latent because #2832 blocks the upstream path, but once #2832 is fixed and users adopt `default_alias_rule = "opt"`, they'd hit this immediately.
## The bug
`rust/private/rustc.bzl::collect_deps` (0.70.0):
```python
aliases = {k.label: v for k, v in aliases.items()}
for dep in crate_deps:
crate_info = dep.crate_info
...
if crate_info.owner in aliases:
...
```
The dict is keyed by the *aliased target's own `.label`*, but the lookup is against `crate_info.owner` of the dep. These differ whenever the aliased target is a rule that forwards `COMMON_PROVIDERS` from an underlying `rust_library` — which is exactly what the canonical `transition_alias_opt` rule does:
```python
def _transition_alias_impl(ctx):
return [ctx.attr.actual[0][provider] for provider in COMMON_PROVIDERS]
```
So `crate_info.owner` ends up as the *wrapped* rust_library's label (e.g. `@crate_index__hyper-0.14.29//:hyper`), but the dict key is the *wrapper*'s label (e.g. `//third_party/rust/crates:hyper1427`). They don't match → the alias is silently dropped → the crate gets imported under its original name → compile error like `unresolved import alias_name`.
## Reproducer
In a workspace where #2832 is worked around with a custom `alias_rules.bzl` (or, hypothetically, once #2832 is fixed, with `default_alias_rule = "opt"` directly):
```python
# Cargo.toml → renders as `transition_alias_opt(name="hyper", actual="@crate_index__hyper-0.14.29//:hyper")` in crate_index
# user-facing rust_library:
rust_library(
name = "foo",
aliases = {"@crate_index//:hyper": "hyper1427"},
deps = ["@crate_index//:hyper"],
...
)
```
`foo`'s source imports the crate as `hyper1427` (e.g. `use hyper1427::Body;`). Compile fails with `unresolved import hyper1427` because the alias dict key doesn't match `dep.crate_info.owner`.
## Proposed fix
Use the underlying library's owner when the alias key is itself a `crate_info`-providing target:
```python
aliases = {
k[rust_common.crate_info].owner if rust_common.crate_info in k else k.label: v
for k, v in aliases.items()
}
```
This is what we carry as a local patch (`0010-allow-using-aliased-crate-in-aliases-attr.patch`) against 0.70.0. Happy to send a PR if the maintainers agree.
## Versions
- rules_rust: 0.70.0
- bazel: 7.7.1
Contributor guide
Assessment
This issue has not been assessed yet.