bazelbuild / bazelbuild/rules_rust

crate_universe: aliases attr can't reference targets that are themselves rust_library wrappers (e.g. transition aliases)

Open
#4,035 1 comment 0 reactions 0 assignees View on GitHub
awaiting-response crate-universe
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.