Skip to content

Conversation

@oli-obk
Copy link
Contributor

@oli-obk oli-obk commented Dec 19, 2025

tracking issue: #144361

cc @theemathas can you find an unsoundness when combined with generic impls where there are no lifetimes, but reference other impls that have lifetimes with constraints? I couldn't find anything.

cc @ivarflakstad @izagawd

@rustbot
Copy link
Collaborator

rustbot commented Dec 19, 2025

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

Some changes occurred to the core trait solver

cc @rust-lang/initiative-trait-system-refactor

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Dec 19, 2025
@rustbot rustbot added the WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) label Dec 19, 2025
@rustbot
Copy link
Collaborator

rustbot commented Dec 19, 2025

r? @SparrowLii

rustbot has assigned @SparrowLii.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rust-log-analyzer

This comment has been minimized.

@oli-obk oli-obk force-pushed the try_as_dyn_non_static branch 2 times, most recently from e7ef1ee to 29f1dba Compare December 19, 2025 16:44
Copy link
Contributor

@danielhenrymantilla danielhenrymantilla left a comment

Choose a reason for hiding this comment

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

Some drive-by comments; but I'm not rustc/HIR-savy, so take these with a grain of salt 🙇

View changes since this review

assert!(std::any::try_as_dyn::<_, dyn Trait>(&()).is_some());
assert!(std::any::try_as_dyn::<_, dyn Trait>(&&[()]).is_some());
assert!(std::any::try_as_dyn::<_, dyn Trait>(&&()).is_some());
assert!(std::any::try_as_dyn::<_, dyn Trait>(&&42_u32).is_none());
Copy link
Contributor

Choose a reason for hiding this comment

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

This one is a "regression", right? With the old design we could be involving a &'static u32 which is both : 'static, and implementing Trait in the classical sense. Perhaps we'll want a try_as_dyn_static() function as well, for those interested in this use case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll add this to the tracking issue

Comment on lines +89 to +92
if let TypingMode::Reflection = ecx.typing_mode()
&& !cx.is_fully_generic_for_reflection(impl_def_id)
{
return Err(NoSolution);
Copy link
Contributor

@danielhenrymantilla danielhenrymantilla Dec 19, 2025

Choose a reason for hiding this comment

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

This is way over my head, lol, but just to sanity-check: could this branch be hoisted to the beginning of the function, as in, any impl that is not fully_generic_for_reflection(), when checking in Reflection mode, ought to result in Err(NoSolution), right? As in, it's not specific to this double-Negative branch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, it's only relevant if the polarities match. Otherwise it's not a match anyway. So while it could be lifted to the front, it's not really necessary either. No strong opinion, but also easily changeable without affecting behavior

@BoxyUwU
Copy link
Member

BoxyUwU commented Dec 19, 2025

r? BoxyUwU

@rustbot rustbot assigned BoxyUwU and unassigned SparrowLii Dec 19, 2025
@theemathas

This comment has been minimized.

@theemathas

This comment has been minimized.

@theemathas

This comment has been minimized.

@BoxyUwU BoxyUwU added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 30, 2025
@oli-obk oli-obk force-pushed the try_as_dyn_non_static branch from 29f1dba to fe33b0c Compare January 7, 2026 12:41
@rustbot

This comment has been minimized.

@oli-obk oli-obk force-pushed the try_as_dyn_non_static branch 3 times, most recently from dfa5c33 to 30f5641 Compare January 7, 2026 12:44

fn extend(a: &Payload) -> &'static Payload {
// TODO: should panic at the `unwrap` here
let b: &(dyn Trait + 'static) = try_as_dyn::<&Payload, dyn Trait + 'static>(&a).unwrap();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't have a solution for this yet. The easy hammer is to reject traits that have such methods. Nicer would be to figure out how to make a bound that ensures the dyn Trait's lifetimes are shorter than the arguments'

Copy link
Member

Choose a reason for hiding this comment

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

Can we check during mir_typeck that the source type outlives the lifetime of the trait object type?

Copy link
Member

Choose a reason for hiding this comment

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

ah its not the intrinsic 🤔 yeah thats tricky

@rust-log-analyzer

This comment has been minimized.

@oli-obk
Copy link
Contributor Author

oli-obk commented Jan 13, 2026

The hacky solution is obviously not a general fix. But I think it's progress. As a next step I will add the input type as a generic parameter on TryAsDynCompat, at which point we should be able to enforce (in borrowck) that the input type outlives any lifetimes on the dyn Trait or its generic parameters. So if a generic parameter T has a 'static bound, it could be used as an input type for a try_as_dyn irrespective of the bounds on the dyn Trait. In the other direction, we will likely end up rejecting many traits that have generic parameters as the bounds are not something that can be written in Rust.

@theemathas

This comment was marked as resolved.

@theemathas

This comment was marked as resolved.

@oli-obk oli-obk force-pushed the try_as_dyn_non_static branch from c027131 to 96dfdf7 Compare February 7, 2026 19:16
@rustbot
Copy link
Collaborator

rustbot commented Feb 7, 2026

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

This comment was marked as resolved.

@theemathas

This comment was marked as resolved.

@theemathas
Copy link
Contributor

Do we need to prohibit manually implementing TryAsDynCompatible?

@oli-obk
Copy link
Contributor Author

oli-obk commented Feb 9, 2026

Yea I think it's pretty useless to impl, feels similar to the Tuple trait

@oli-obk
Copy link
Contributor Author

oli-obk commented Feb 9, 2026

And trying to downcast to an HRTB trait object results in an ICE:

fun... if the input type also is behind a binder, I can't really construct the obligation T: 'a, as it would require merging/nesting the binders. I guess that could happen if it is in a closure? I'll flip it for now and add an assert

@theemathas
Copy link
Contributor

theemathas commented Feb 9, 2026

@oli-obk Why does the input type T have to outlive each generic lifetime in the dyn trait? What unsoundness does this prevent?

@oli-obk
Copy link
Contributor Author

oli-obk commented Feb 9, 2026

Well. What I'm trying to emulate here is a version of the logic that coercion does when going from T to dyn Trait. But since we need to do it for all T here, we can't just look at the right impl and perform the appropriate obligation checks. Instead we need to have the most pessimistic view on how any type can implement that trait. So, generic lifetimes of the trait must always be outlived by the self type. Since you can shuttle lifetimes through generic type params, generic type params of the trait must only contain lifetimes that are outlived by the self type, too. But since we do not have such constraints anywhere else in the language, I'm just gonna make the presence of generic type params on the trait cause a T: 'static requirement, which (as before this PR) makes everything immediately sound

@theemathas

This comment was marked as resolved.

@theemathas

This comment was marked as resolved.

@theemathas

This comment was marked as resolved.

@oli-obk oli-obk force-pushed the try_as_dyn_non_static branch from 96dfdf7 to 6c42a6c Compare February 10, 2026 08:34
@rust-log-analyzer

This comment has been minimized.

@oli-obk oli-obk force-pushed the try_as_dyn_non_static branch from 35cbc7c to 914b5e2 Compare February 10, 2026 11:32
@rust-log-analyzer

This comment has been minimized.

@theemathas
Copy link
Contributor

I had a look at this one last time. I think it should be good to go in terms of soundness.

@theemathas theemathas added the T-types Relevant to the types team, which will review and decide on the PR/issue. label Feb 10, 2026
@oli-obk oli-obk force-pushed the try_as_dyn_non_static branch from 914b5e2 to bf73dc3 Compare February 10, 2026 14:25
@rust-log-analyzer
Copy link
Collaborator

The job pr-check-2 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
REPOSITORY                                   TAG       IMAGE ID       CREATED       SIZE
ghcr.io/dependabot/dependabot-updater-core   latest    b72a662c47e3   10 days ago   790MB
=> Removing docker images...
Deleted Images:
untagged: ghcr.io/dependabot/dependabot-updater-core:latest
untagged: ghcr.io/dependabot/dependabot-updater-core@sha256:57ef9cc45f72cc4258ee1baa8243bc3cd55c0a0e570b6768c37346247be35f0d
deleted: sha256:b72a662c47e31df2e7bf59368b2b83be239f02a1baa721393717711a1a719df9
deleted: sha256:3e13ccd80f19769f39008cfc6549938e1ea4905f47b028c1df2dd6085191386c
deleted: sha256:842807995a512b2c5a9b241a3aecdbe79af6b0642d96fa5460cfcf0c9d8be295
deleted: sha256:0f9074b9f46f4570eb7cb4b65fcb3c3d909f9b1d14ca66b30508117b6deda303
deleted: sha256:2ca99cb9251d19157c56b5d91c8961bb4b35196a5ca9b4ffdccbf24abbfe2a5f
---
---- library/core/src/any.rs - any::try_as_dyn (line 946) stdout ----
error[E0405]: cannot find trait `Trait` in this scope
   --> library/core/src/any.rs:947:36
    |
947 | impl<'a, 'b, T: Debug, U: Display> Trait<'a, T> for Type<'b, U> {}
    |                                    ^^^^^ not found in this scope

error[E0425]: cannot find type `Type` in this scope
   --> library/core/src/any.rs:947:53
    |
947 | impl<'a, 'b, T: Debug, U: Display> Trait<'a, T> for Type<'b, U> {}
    |                                                     ^^^^ not found in this scope
    |
help: consider importing this struct
    |
946 + use std::mem::type_info::Type;
    |

error[E0404]: expected trait, found derive macro `Debug`
   --> library/core/src/any.rs:947:17
    |
947 | impl<'a, 'b, T: Debug, U: Display> Trait<'a, T> for Type<'b, U> {}
    |                 ^^^^^ not a trait
    |
help: consider importing this trait instead
    |
946 + use std::fmt::Debug;
    |

error[E0405]: cannot find trait `Display` in this scope
   --> library/core/src/any.rs:947:27
    |
947 | impl<'a, 'b, T: Debug, U: Display> Trait<'a, T> for Type<'b, U> {}
    |                           ^^^^^^^ not found in this scope
    |
help: consider importing this trait
    |
946 + use std::fmt::Display;

@rust-bors
Copy link
Contributor

rust-bors bot commented Feb 10, 2026

☔ The latest upstream changes (presumably #152437) made this pull request unmergeable. Please resolve the merge conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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. T-libs Relevant to the library team, which will review and decide on the PR/issue. 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

Development

Successfully merging this pull request may close these issues.

8 participants