Skip to content

Prohibit conflicting bounds in dyn, even with different generics.#157710

Open
theemathas wants to merge 6 commits into
rust-lang:mainfrom
theemathas:no-dup-bound-in-dyn
Open

Prohibit conflicting bounds in dyn, even with different generics.#157710
theemathas wants to merge 6 commits into
rust-lang:mainfrom
theemathas:no-dup-bound-in-dyn

Conversation

@theemathas

@theemathas theemathas commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

View all comments

Fixes #154662, fixes #150936.

In a dyn type, if multiple bounds are specified for the same associated item, then we previously accepted them if the relevant trait's generics are different, even if the bounds conflict.

This was unsound, since those generics could end up being instantiated with identical concrete types, causing the dyn type to have two different "values" for the same bound.

Thus, we prohibit multiple bounds for the same associated item, even if the trait's generics are different.

As a side effect of this change, we also now allow duplicated bounds in a dyn type, as long as the bounds are syntactically identical.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) labels Jun 10, 2026
@theemathas theemathas force-pushed the no-dup-bound-in-dyn branch from 7792410 to 67244f1 Compare June 10, 2026 14:23
@rust-log-analyzer

This comment has been minimized.

@theemathas

This comment was marked as resolved.

@theemathas

This comment was marked as resolved.

@rust-bors

This comment was marked as resolved.

@theemathas

Copy link
Copy Markdown
Contributor Author

@bors try

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jun 10, 2026
Prohibit conflicting bounds in `dyn`, even with different generics.
@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jun 10, 2026
Prohibit conflicting bounds in `dyn`, even with different generics.
@rust-bors

rust-bors Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 09eeb2b (09eeb2bacb9b40b2ed1d47f03177442c0632cda1, parent: 485ec3fbcc12fa14ef6596dabb125ad710499c9e)

@fmease

fmease commented Jun 10, 2026

Copy link
Copy Markdown
Member

@craterbot check

@craterbot

Copy link
Copy Markdown
Collaborator

👌 Experiment pr-157710 created and queued.
🤖 Automatically detected try build 09eeb2b
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 10, 2026
@theemathas theemathas mentioned this pull request Jun 12, 2026
@theemathas

Copy link
Copy Markdown
Contributor Author

@craterbot cancel

See #157814

@craterbot

Copy link
Copy Markdown
Collaborator

🗑️ Experiment pr-157710 deleted!

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels Jun 12, 2026
@theemathas

Copy link
Copy Markdown
Contributor Author

@craterbot

Copy link
Copy Markdown
Collaborator

👌 Experiment pr-157710 created and queued.
🤖 Automatically detected try build 09eeb2b
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 16, 2026
@craterbot

Copy link
Copy Markdown
Collaborator

🚧 Experiment pr-157710 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot

Copy link
Copy Markdown
Collaborator

🎉 Experiment pr-157710 is completed!
📊 1 regressed and 0 fixed (14695 total)
📊 660 spurious results on the retry-regressed-list.txt, consider a retry1 if this is a significant amount.
📰 Open the summary report.

⚠️ If you notice any spurious failure please add them to the denylist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

Footnotes

  1. re-run the experiment with crates=https://crater-reports.s3.amazonaws.com/pr-157710/retry-regressed-list.txt

@theemathas theemathas force-pushed the no-dup-bound-in-dyn branch from 67244f1 to 7251016 Compare June 21, 2026 13:03
@rust-log-analyzer

This comment has been minimized.

@theemathas theemathas force-pushed the no-dup-bound-in-dyn branch from 7251016 to b5838a9 Compare June 21, 2026 14:46
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

Comment thread compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs
Comment on lines +284 to +288
// FIXME: Improve diagnostics by pointing to
// where the bound is specified.
.with_note(format!("`{name}` is specified to be `{old_term}`"))
.with_note(format!("`{name}` is also specified to be `{term}`"))
.emit();

@theemathas theemathas Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can I get the span where the associated type bound is specified (e.g., in the supertrait clause)?

View changes since the review

Comment on lines +279 to +283
// This clause specifies that the `kind` is equal to `term`.
// We record this, and check for duplicates.
if let Some((old_term, old_pred)) =
seen_projection_bounds_ignoring_generics.insert(kind, (term, pred))
&& old_term != term

@theemathas theemathas Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The one crater regression effectively had a : Trait<i32, Assoc = i32> + Trait<bool, Assoc = bool> supertrait bound. I want to allow this. To do so, I need to check whether an older predicate's generics could be unified with the new predicate's generics. How can I do this? I found the can_eq method, but I don't know how to obtain the param_env argument required for it.

View changes since the review

@fmease fmease Jun 22, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As alluded to in #146548 (comment) and #133397, we don't really have access to semantic equality (normalization followed by type relating) in HIR ty lowering (specifically in item signatures).

can_eq is an overapproximation; anyway, obtaining the ParamEnv (tcx.param_env(self.item_def_id())) is basically impossible in item signatures due to query cycles galore (e.g., it needs to contain implied bounds but implicit_infer needs already-lowered types: cycle).

For inherent associated types, we currently use DeepRejectCtxt::…::types_may_unify but that's icky because DeepRejectCtxt is only meant for fast paths but now it leaks into the semantics of the language. The plan is to get rid of that again (...).

What's left is == which obviously doesn't properly handle infers _, bound vars and alias types. That might be the best option, unfortunately. I don't know how T-types thinks about this...

@theemathas theemathas Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking with == is unsound, since that would make two different generic type variables compare as unequal types, which will allow rust code that runs into the unsoundness this PR was trying to fix in the first place.

What I need is an operation that can tell me either "it's impossible for these two types to ever have their generics instantiated so that they become the same concrete type" or "unsure".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course 🤦.

That's ty::DeepRejectCtxt::relate_infer_infer(tcx).args_may_unify(…) but it's questionable if T-types is going to accept that for the aforesaid reason 🤔 .

@theemathas theemathas Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like it's either we use some hacky thing, or we break one crate in crater (and possibly an unknown number of crates that crater can't see) with what appears to be a legimitate use case.

Do we do an I-types-nominated?

@theemathas

theemathas commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

I am unsure what I should do with the tests that now no longer compile. Any suggestions?

Also, I'm very unsure if I handled the binder stuff correctly. I'd like a closer look on those stuff.

Also, what's up with the build failures in CI? It builds fine locally.

r? @fmease

@theemathas theemathas marked this pull request as ready for review June 21, 2026 15:25
@rustbot

rustbot commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

HIR ty lowering was modified

cc @fmease

@theemathas theemathas added needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. T-types Relevant to the types team, which will review and decide on the PR/issue. and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 21, 2026
…ics.

See rust-lang#154662

These tests will be fixed in a subsequent commit.
Fixes rust-lang#154662

In a `dyn` type, if multiple bounds are specified for the same
associated item, then we previously accepted them if the relevant
trait's generics are different, even if the bounds conflict.

This was unsound, since those generics could end up being instantiated
with identical concrete types, causing the `dyn` type to have two
different "values" for the same bound.

Thus, we prohibit multiple bounds for the same associated item, even
if the trait's generics are different.

As a side effect of this change, we also now allow duplicated bounds
in a `dyn` type, as long as the bounds are syntactically identical.

The now-unused `OverlappingAsssocItemConstraints` will be removed in
a subsequent commit.
Fixes <rust-lang#150936>

The last place where `OverlappingAsssocItemConstraints::Forbidden`
was constructed was removed in a previous commit. As a result,
this code path is now unreachable.
@theemathas theemathas force-pushed the no-dup-bound-in-dyn branch from 7a7f34c to 8bbea5e Compare June 22, 2026 04:44
@rustbot

rustbot commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@theemathas

theemathas commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

I've rebased. The previous CI failures were due to #157653 (since CI has to merge with the main branch before building). This has now been resolved.

@rust-log-analyzer

This comment has been minimized.

…ciated types in dyn.

This issue previously only affected trait aliases. This PR causes
the same issue to also affect supertraits.
@theemathas theemathas force-pushed the no-dup-bound-in-dyn branch from 0c0275a to a186b79 Compare June 22, 2026 09:53
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

Copy link
Copy Markdown
Collaborator

The job tidy failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
fmt: checked 6928 files
tidy check
tidy [rustdoc_json (src)]: `rustdoc-json-types` modified, checking format version
tidy: Skipping binary file check, read-only filesystem
tidy [style (tests)]: /checkout/tests/ui/traits/next-solver/supertrait-alias-4.rs:1: TODO is used for tasks that should be done before merging a PR; If you want to leave a message in the codebase use FIXME
tidy [style (tests)]: /checkout/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs:1: TODO is used for tasks that should be done before merging a PR; If you want to leave a message in the codebase use FIXME
tidy [style (tests)]: /checkout/tests/ui/dyn-compatibility/multiple-supers-should-work.rs:1: TODO is used for tasks that should be done before merging a PR; If you want to leave a message in the codebase use FIXME
tidy [style (tests)]: /checkout/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs:1: TODO is used for tasks that should be done before merging a PR; If you want to leave a message in the codebase use FIXME
tidy [style (tests)]: /checkout/tests/ui/error-codes/E0719.rs:2: TODO is used for tasks that should be done before merging a PR; If you want to leave a message in the codebase use FIXME
tidy [style (tests)]: FAIL
removing old virtual environment
creating virtual environment at '/checkout/obj/build/venv' using 'python3.10' and 'venv'
creating virtual environment at '/checkout/obj/build/venv' using 'python3.10' and 'virtualenv'
Requirement already satisfied: pip in ./build/venv/lib/python3.10/site-packages (26.1.1)
Collecting pip
---
info: ✓ ES-Check passed! All files are ES10 compatible.
typechecking javascript files
tidy: The following check failed: style (tests)
Bootstrap failed while executing `test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck`
Command `/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-tools-bin/rust-tidy --root-path=/checkout --cargo-path=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo --output-dir=/checkout/obj/build --concurrency=4 --npm-path=/node/bin/yarn --ci=true --extra-checks=py,cpp,js,spellcheck` failed with exit code 1
Created at: src/bootstrap/src/core/build_steps/tool.rs:1625:23
Executed at: src/bootstrap/src/core/build_steps/test.rs:1645:29

--- BACKTRACE vvv
   0: <bootstrap::utils::exec::DeferredCommand>::finish_process
             at /checkout/src/bootstrap/src/utils/exec.rs:939:17
   1: <bootstrap::utils::exec::DeferredCommand>::wait_for_output::<&bootstrap::utils::exec::ExecutionContext>
             at /checkout/src/bootstrap/src/utils/exec.rs:831:21
   2: <bootstrap::utils::exec::ExecutionContext>::run
             at /checkout/src/bootstrap/src/utils/exec.rs:741:45
   3: <bootstrap::utils::exec::BootstrapCommand>::run::<&bootstrap::core::builder::Builder>
             at /checkout/src/bootstrap/src/utils/exec.rs:339:27
   4: <bootstrap::core::build_steps::test::Tidy as bootstrap::core::builder::Step>::run
             at /checkout/src/bootstrap/src/core/build_steps/test.rs:1645:29
   5: <bootstrap::core::builder::Builder>::ensure::<bootstrap::core::build_steps::test::Tidy>
             at /checkout/src/bootstrap/src/core/builder/mod.rs:1597:36
   6: <bootstrap::core::build_steps::test::Tidy as bootstrap::core::builder::Step>::make_run
             at /checkout/src/bootstrap/src/core/build_steps/test.rs:1567:21
   7: <bootstrap::core::builder::StepDescription>::maybe_run
             at /checkout/src/bootstrap/src/core/builder/mod.rs:476:13
   8: bootstrap::core::builder::cli_paths::match_paths_to_steps_and_run
             at /checkout/src/bootstrap/src/core/builder/cli_paths.rs:232:18
   9: <bootstrap::core::builder::Builder>::run_step_descriptions
             at /checkout/src/bootstrap/src/core/builder/mod.rs:1140:9
  10: <bootstrap::core::builder::Builder>::execute_cli
             at /checkout/src/bootstrap/src/core/builder/mod.rs:1119:14
  11: <bootstrap::Build>::build
             at /checkout/src/bootstrap/src/lib.rs:803:25
  12: bootstrap::main
             at /checkout/src/bootstrap/src/bin/main.rs:130:11
  13: <fn() as core::ops::function::FnOnce<()>>::call_once
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/core/src/ops/function.rs:250:5
  14: std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/sys/backtrace.rs:166:18
  15: std::rt::lang_start::<()>::{closure#0}
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/rt.rs:206:18
  16: <&dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe as core::ops::function::FnOnce<()>>::call_once
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/core/src/ops/function.rs:287:21
  17: std::panicking::catch_unwind::do_call::<&dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe, i32>
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/panicking.rs:581:40
  18: std::panicking::catch_unwind::<i32, &dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe>
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/panicking.rs:544:19
  19: std::panic::catch_unwind::<&dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe, i32>
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/panic.rs:359:14
  20: std::rt::lang_start_internal::{closure#0}
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/rt.rs:175:24
  21: std::panicking::catch_unwind::do_call::<std::rt::lang_start_internal::{closure#0}, isize>
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/panicking.rs:581:40
---
  28: __libc_start_main
  29: _start


Command has failed. Rerun with -v to see more details.
Build completed unsuccessfully in 0:02:38
  local time: Mon Jun 22 10:14:53 UTC 2026
  network time: Mon, 22 Jun 2026 10:14:53 GMT
##[error]Process completed with exit code 1.
##[group]Run echo "disk usage:"

@fmease fmease added the I-types-nominated Nominated for discussion during a types team meeting. label Jun 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

I-types-nominated Nominated for discussion during a types team meeting. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-types Relevant to the types team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver)

Projects

None yet

5 participants