Skip to content

Tracking issue for tweaks to dyn compatibility (RFC 2027) #43561

Closed as not planned

Description

@withoutboats

This is the tracking issue for RFC 2027, tweaks to dyn-compatibility1 (rust-lang/rfcs#2027)

Footnotes

  1. Formerly known as "object safety". ↩

Activity

  1. added
    B-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.
    B-unstableBlocker: Implemented in the nightly compiler and unstable.
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    T-langRelevant to the language team
    on Jul 30, 2017
  2. withoutboats commented on Jul 30, 2017

    @withoutboats
    ContributorAuthor

    If anyone can mentor I'd be excited to try to implement this.

    From my naive perspective, it seems like what we need to do is stop checking object safety at certain points (possibly determining if a type is well formed?) and start checking it at other points (checking if the object type implements its corresponding trait). More insight would be great, cc'ing @eddyb

  3. eddyb commented on Jul 30, 2017

    @eddyb
    Contributor

    I'm afraid @nikomatsakis understands the details here much better than me.

  4. withoutboats commented on Aug 7, 2017

    @withoutboats
    ContributorAuthor

    I experimented with implementing this, but I definitely don't know what I'm doing. I noticed some interesting cases.

    trait Foo: Sized { }
    
    fn foo(_: &Foo) { panic!() }
    
    fn main {
        let x: Box<Foo>;
    }

    Today these types are just invalid types, but I believe this RFC would make them valid. You would just never be able to initialize x or call foo. I didn't consider these in the RFC, but it seems fine to me.

  5. JeanMertz commented on Dec 22, 2018

    @JeanMertz
    Contributor

    Hey @withoutboats, I was just wondering if anything has changed for this RFC since it was approved?

    I don’t have the skills to tackle this, and you probably don’t have the time, but I wanted to “bump” this anyway. Perhaps it can get some more mentoring love to move it forward?

  6. withoutboats commented on Dec 22, 2018

    @withoutboats
    ContributorAuthor

    I still wish this would be implemented, but nothing has changed and I also don't have the knowledge of compiler internals to mentor anyone on it.

  7. bovinebuddha commented on Jan 10, 2019

    @bovinebuddha
    Contributor

    So, I took a crack at this over the holidays. Tried to wrap my head around the compiler internals.

    I think I've got most of the RFC working. Currently trying to put all the relevant code behind a feature gate, I'll put up a PR in a couple of days when that's working. All the tests that were broken, ~30 IIRC (at least of those I managed to run), failed because of anticipated reasons. So all good so far.

    Just a few corner cases I've been thinking about. The RFC is a little vague on some of the details of what exactly should compile or not.

    • What should the feature gate be called? I used 'object_safe_for_dispatch' from the RFC but I think something that indicates that it's more about 'non-object safety trait objects are legal', or maybe 'symmetric_object_safety'.

    • How do we alert users about its existence?The RFC basically turns previously illegal code into legal code, but there is no 'good' place to do emit_feature_err!("Static dispatch for non-object safe traits not stable"). Should we add some extra text to E0038 ('cannot be made into an object') to clarify that there is a feature unlocking the error?

    • Should the following code compile:

    trait Foo {
        fn foo() {}
    }
    
    trait Bar: Sized {}
    
    impl Foo for dyn Bar {}
    
    fn static_poly<T: Foo>() {
        T::foo();
    }
    
    fn main() {
        Bar::foo(); // Works now!
        static_poly::<dyn Bar>(); // Does not work currently
    }
    • What about if I add the following:
    fn inferred_poly<T: Foo>(t: &T) {
        T::foo();
    }
    
    fn infer_using_trait_obj(t: &dyn Bar) {
        inferred_poly(t); // Does not work currently
    }
    • I currently removed the automatic 'impl Trait for dyn Trait' for non object-safe traits in src/librustc/traits/select.rs which I think is part of the old style trait solving, and not using chalk. Can I switch to use the new trait style solving with chalk somehow? Or is it used under the hood? The rustc guide isn't really clear on if there two styles coexist or if there is a WIP opt-in somewhere.

    • Also, the RFC mentions we could possibly allow manual 'impl Trait for dyn Trait'. Is this something we would want? I figure it would be most prudent to add a new error forbidding this, and a future RFC could add it later.

    Sorry for the Wall of Text.

    TL/DR - Expect a pull request in a couple of days, some thorny questions remain.

    @withoutboats

  8. withoutboats commented on Jan 10, 2019

    @withoutboats
    ContributorAuthor

    @bovinebuddha Is it intentional in your code samples that you do not do T: ?Sized + Foo? It seems necessary that the code you wrote does not compile because dyn Bar does not implement Sized, and all type parameters are implicitly bound Sized unless you add ?Sized.

  9. bovinebuddha commented on Jan 10, 2019

    @bovinebuddha
    Contributor

    Ah... What a gotcha! Quite new to Rust, forgot about traits defaulting to !Sized.

    Adding that solved made the call in main() compile. The inferred call still doesn't compile with the following message:

    23 | fn infer_using_trait_obj(t: &dyn Bar) {
       |                             -------- help: add explicit lifetime `'static` to the type of `t`: `&'static (dyn Bar + 'static)`
    24 |     inferred_poly(t);
       |     ^^^^^^^^^^^^^ lifetime `'static` required

    I'm not 100% confident in exactly how traits and lifetimes intermingle. Changing to the following did not do the trick:

    fn inferred_poly<'a, T: Foo + ?Sized + 'a>(t: &'a T) {
        T::foo();
    }

    and neither did adding the caller to:

    fn infer_using_trait_obj<'a>(t: &'a (dyn Bar + 'a)) {
        inferred_poly(t);
    }

    which resulted in this:

    error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
      --> src/main.rs:24:19
       |
    24 |     inferred_poly(t);
       |                   ^
       |
    note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 23:26...
      --> src/main.rs:23:26
       |
    23 | fn infer_using_trait_obj<'a>(t: &'a (dyn Bar + 'a)) {
       |                          ^^
       = note: ...so that the expression is assignable:
               expected &dyn Bar
                  found &(dyn Bar + 'a)
       = note: but, the lifetime must be valid for the static lifetime...
       = note: ...so that the types are compatible:
               expected Foo
                  found Foo
    
  10. withoutboats commented on Jan 10, 2019

    @withoutboats
    ContributorAuthor

    The reason is that you have only implemented Foo for dyn Bar + 'static (because thats the inference in the impl header position).

    All of these are normal & expected errors, then (even if they are confusing!). Seems like you got the feature working :)

  11. bovinebuddha commented on Jan 10, 2019

    @bovinebuddha
    Contributor

    Yay :)

    I realized the problem I had with the feature gate was that I wrote #[feature...] instead of #![feature...], so that's working now.

    Is there any way of writing the lifetimes so that the inferred method compiles though? Or should it even compile in any form? I tried adding separate lifetimes for the referance and the trait bound and an outlives relationship but that didn't do the trick...

  12. withoutboats commented on Jan 10, 2019

    @withoutboats
    ContributorAuthor

    either of these changes should make it compile:

    impl<'a> Foo for dyn Bar + 'a { }
    fn infer_using_trait_obj(t: &dyn Bar + 'static) { } 
  13. 17 remaining items

  14. added a commit that references this issue on Oct 31, 2019
  15. added
    B-RFC-implementedBlocker: Approved by a merged RFC and implemented but not stabilized.
    B-unstableBlocker: Implemented in the nightly compiler and unstable.
    on Nov 8, 2019
  16. added and removed
    B-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.
    on Nov 26, 2019
  17. added
    S-tracking-needs-summaryStatus: It's hard to tell what's been done and what hasn't! Someone should do some investigation.
    on Feb 9, 2022
  18. joshtriplett commented on Feb 9, 2022

    @joshtriplett
    Member

    Paging @nikomatsakis, it would help to have a summary of this to know what state it's in and whether it's on a path to stabilization.

  19. changed the title [-]Tracking issue for tweaks to object safety (RFC 2027)[/-] [+]Tracking issue for tweaks to object safety / dyn compatibility (RFC 2027)[/+] on Oct 3, 2024
  20. changed the title [-]Tracking issue for tweaks to object safety / dyn compatibility (RFC 2027)[/-] [+]Tracking issue for tweaks to dyn compatibility (RFC 2027)[/+] on Oct 11, 2024
  21. added a commit that references this issue on Feb 25, 2025
  22. added a commit that references this issue on Feb 25, 2025
  23. fmease commented on Apr 2, 2025

    @fmease
    Member

    The feature has been removed in #136522.

    While there hasn't been a de-RFC, readding this feature would require a new RFC anyway since so much has changed.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-trait-systemArea: Trait systemB-RFC-implementedBlocker: Approved by a merged RFC and implemented but not stabilized.B-unstableBlocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCF-dyn_compatible_for_dispatch`#![feature(dyn_compatible_for_dispatch)]`; formerly `object_safe_for_dispatch`S-tracking-needs-summaryStatus: It's hard to tell what's been done and what hasn't! Someone should do some investigation.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions