Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discuss the possibility of denying bare_trait_objects in 2021 edition #65

Closed
varkor opened this issue Oct 28, 2020 · 9 comments
Closed
Labels
meeting-proposal Proposal for a lang team design meeting T-lang

Comments

@varkor
Copy link
Member

varkor commented Oct 28, 2020

Summary

Bare trait objects do not interact well with const generics, as if a user does not surround a const expression with {}, it can be parsed as a trait object (e.g. foo + bar is interpreted as dyn foo + bar), which leads to confusing errors. See, for instance: rust-lang/rust#77502 (comment). If we deny bare_trait_objects in the 2021 edition, which is a permitted edition change, we can emit better errors for const generics, a feature we hope to stabilise in the form of min_const_generics in the near future.

bare_trait_objects would continue to work pre-2021 edition. Thus, the better error messages will only be available in the 2021 edition.

About this issue

This issue corresponds to a lang-team design meeting proposal. It corresponds
to a possible topic of discussion that may be scheduled for deeper discussion
during one of our design meetings.

@varkor varkor added T-lang meeting-proposal Proposal for a lang team design meeting labels Oct 28, 2020
@djc
Copy link

djc commented Oct 28, 2020

The link to "lang-team design meeting proposal" points to a 404, I assume that is not intended?

@varkor
Copy link
Member Author

varkor commented Oct 28, 2020

The link in the template is broken. I've changed it to what seems most appropriate.

@joshtriplett
Copy link
Member

@varkor I don't know if this is a good idea or not, but it's worth noting that we could make min_const_generics (or this specific parsing issue related to it) only available in the new edition, which would avoid the ambiguity in older editions as well. Then, foo + bar would unambiguously mean dyn foo + bar in an older edition, and would unambiguously be a const generic operation in the new edition. That would result in better error messages and potentially simplified parsing.

@varkor
Copy link
Member Author

varkor commented Nov 9, 2020

@joshtriplett: we could, but as the only issue is a diagnostics issue, I think it's still work stabilising on older editions. The usefulness outweighs the occasional diagnostic confusion, I feel.

@danielhenrymantilla
Copy link
Contributor

danielhenrymantilla commented Dec 30, 2020

Tangentially related, it would be nice to have the option for specific traits and/or specific generic parameters "slots", not to require that dyn.
The need arises when:

  • implementing custom trait objects with a defined layout, while wanting to be auto-trait generic. The best solution for that right now is to have a phantom generic parameter slot, so as to write stuff such as MyBoxedDynAny<Send + Sync> (an example). Currently, deny(bare_trait_objects) requires a redundant dyn in that name.

  • the second use case is regarding type-level sets, such as the discussed NeglectStuff options for the safe-transmute project: with transmute::<Neglect::Alignment + Neglect::SomethingElse>(...)

@scottmcm
Copy link
Member

To me, at least, those don't seem persuasive enough to dissuade from making dyn strictly required.

  • One can presumably just do type MyBoxedDynAny<T> = dyn MyBoxedDynAnyTrait<T>; if you want to expose something as a type instead of a trait.
  • That use has always felt somewhat like a hack to me, vs a representation like would be done at runtime like transmute::<{ Neglect { alignment: true, .. } }(...) or something. Or even transmute::<{Neglect::Alignment | Neglect::SomethingElse}>(...) with a const BitOr for whatever that type would be. It's certainly a fun hack, while const generics are as limited as they currently are, but I'm still not a fan of it.

@scottmcm
Copy link
Member

scottmcm commented Jan 24, 2021

I just ran into another place where it would be helpful for dyn to be required: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=03e6767e7f9a6ceedf6ac9a213055703

trait Foo : Bar {}
trait Bar {
    fn from_integer(x: i32) -> Self;
}

fn make_it<T: Foo>() -> T {
    Foo::from_integer(123)
}

It currently gives a book:

error[E0038]: the trait `Foo` cannot be made into an object
 --> src/lib.rs:7:5
  |
7 |     Foo::from_integer(123)
  |     ^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
  |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 --> src/lib.rs:3:8
  |
1 | trait Foo : Bar {}
  |       --- this trait cannot be made into an object...
2 | trait Bar {
3 |     fn from_integer(x: i32) -> Self;
  |        ^^^^^^^^^^^^ ...because associated function `from_integer` has no `self` parameter
help: consider turning `from_integer` into a method by giving it a `&self` argument
  |
3 |     fn from_integer(&self, x: i32) -> Self;
  |                     ^^^^^^
help: alternatively, consider constraining `from_integer` so it does not apply to trait objects
  |
3 |     fn from_integer(x: i32) -> Self where Self: Sized;
  |                                     ^^^^^^^^^^^^^^^^^

error[E0308]: mismatched types
 --> src/lib.rs:7:5
  |
6 | fn make_it<T: Foo>() -> T {
  |            -            - expected `T` because of return type
  |            |
  |            this type parameter
7 |     Foo::from_integer(123)
  |     ^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found trait object `dyn Foo`
  |
  = note: expected type parameter `T`
               found trait object `dyn Foo`
  = help: type parameters must be constrained to match other types
  = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

error[E0038]: the trait `Foo` cannot be made into an object
 --> src/lib.rs:7:5
  |
7 |     Foo::from_integer(123)
  |     ^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
  |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 --> src/lib.rs:3:8
  |
1 | trait Foo : Bar {}
  |       --- this trait cannot be made into an object...
2 | trait Bar {
3 |     fn from_integer(x: i32) -> Self;
  |        ^^^^^^^^^^^^ ...because associated function `from_integer` has no `self` parameter
help: consider turning `from_integer` into a method by giving it a `&self` argument
  |
3 |     fn from_integer(&self, x: i32) -> Self;
  |                     ^^^^^^
help: alternatively, consider constraining `from_integer` so it does not apply to trait objects
  |
3 |     fn from_integer(x: i32) -> Self where Self: Sized;
  |                                     ^^^^^^^^^^^^^^^^^

error[E0277]: the size for values of type `dyn Foo` cannot be known at compilation time
 --> src/lib.rs:7:5
  |
7 |     Foo::from_integer(123)
  |     ^^^^^^^^^^^^^^^^^-----
  |     |
  |     doesn't have a size known at compile-time
  |     this returned value is of type `dyn Foo`
  |
  = help: the trait `Sized` is not implemented for `dyn Foo`
  = note: the return type of a function must have a statically known size

error: aborting due to 4 previous errors

It feels rather unlikely that someone wanted the trait type there, and it would be nice for name resolution to be able to find the supertrait function, like it does for methods. (And would fit well with rust-lang/rfcs#2845.)

@petrochenkov
Copy link

This looks similar to rust-lang/rust#65371 which is a hole in the implementation of bare_trait_objects.

@Mark-Simulacrum
Copy link
Member

Closing in favor of rust-lang/rust#83213, as discussed in today's planning meeting. That PR has the outcome of various discussions (and is currently in FCP).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
meeting-proposal Proposal for a lang team design meeting T-lang
Projects
None yet
Development

No branches or pull requests

7 participants