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

Silence unnecessary "missing dyn" errors and tweak E0746 suggestions #122957

Open
wants to merge 21 commits into
base: master
Choose a base branch
from

Conversation

estebank
Copy link
Contributor

@estebank estebank commented Mar 23, 2024

Rework impl Trait and Box return type suggestions in E0746

  • If the return value types diverge, mention it and do not suggest impl Trait
  • If the returned dyn Trait is not object safe, mention it and do not suggest Box<dyn Trait> and boxing the returned values
  • If the function has arguments with borrowed types, suggest &dyn Trait
  • Tweak wording of E0782
error[E0746]: return type cannot have an unboxed trait object
  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:13:13
   |
LL | fn bap() -> Trait { Struct }
   |             ^^^^^ doesn't have a size known at compile-time
   |
help: return an `impl Trait` instead of a `dyn Trait`
   |
LL | fn bap() -> impl Trait { Struct }
   |             ++++
help: alternatively, box the return type to make a boxed trait object, and wrap all of the returned values in `Box::new`
   |
LL | fn bap() -> Box<dyn Trait> { Box::new(Struct) }
   |             +++++++      +   +++++++++      +
error[E0746]: return type cannot have an unboxed trait object
  --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:36:18
   |
LL | fn can(x: &A) -> dyn NotObjectSafe {
   |                  ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
help: trait `NotObjectSafe` is not object safe, so you can't return a boxed trait object `Box<dyn NotObjectSafe>`
  --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:36:22
   |
LL | fn can(x: &A) -> dyn NotObjectSafe {
   |                      ^^^^^^^^^^^^^
help: return an `impl Trait` instead of a `dyn Trait`
   |
LL | fn can(x: &A) -> impl NotObjectSafe {
   |                  ~~~~
help: alternatively, you might be able to borrow from the function's argument
   |
LL | fn can(x: &A) -> &dyn NotObjectSafe {
   |                  +
error[E0782]: trait objects must include the `dyn` keyword
  --> $DIR/not-on-bare-trait-2021.rs:12:19
   |
LL | fn bar(x: Foo) -> Foo {
   |                   ^^^
   |
help: use `impl Foo` to return an opaque type, as long as you return a single underlying type
   |
LL | fn bar(x: Foo) -> impl Foo {
   |                   ++++
help: alternatively, you can return a boxed trait object
   |
LL | fn bar(x: Foo) -> Box<dyn Foo> {
   |                   +++++++    +

Silence "missing dyn" error if "?Sized type" error is already emitted.

Account for type Alias = dyn Trait; in unsized return suggestion:

error[E0746]: return type cannot have an unboxed trait object
 --> tests/ui/unsized/issue-91801.rs:8:77
  |
8 | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Validator<'a> {
  |                                                                             ^^^^^^^^^^^^^ doesn't have a size known at compile-time
-Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs:566:39
  |
help: box the return type to make a boxed trait object, and wrap all of the returned values in `Box::new`
  |
8 | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box<Validator<'a>> {
  |                                                                             ++++             +
help: alternatively, you might be able to borrow from one of the function's arguments
  |
8 | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> &Validator<'a> {
  |                                                                             +

Use more complex logic for E0277 deduplication of FullfillmentErrors, accounting and customizing the span for SizedArgument obligations and functions with unsized return types. We only emit one unsized local error whenever possible.

Point at the let binding type or init expression instead of the pattern when possible for ?Sized errors.

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
  --> $DIR/unsized-locals-using-unsized-fn-params.rs:13:15
   |
LL |     let _foo: [u8] = *foo;
   |               ^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `[u8]`
   = note: all local variables must have a statically known size

Fix #121037. Fix #105753.

@rustbot
Copy link
Collaborator

rustbot commented Mar 23, 2024

r? @fee1-dead

rustbot has assigned @fee1-dead.
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

@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. labels Mar 23, 2024
@rustbot
Copy link
Collaborator

rustbot commented Mar 23, 2024

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

@rustbot
Copy link
Collaborator

rustbot commented Mar 23, 2024

HIR ty lowering was modified

cc @fmease

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@fee1-dead
Copy link
Member

I don't think I have the capacity to review this right now.

r? compiler

@rustbot rustbot assigned TaKO8Ki and unassigned fee1-dead Mar 24, 2024
@@ -206,6 +206,50 @@ impl<'tcx> FulfillmentError<'tcx> {
) -> FulfillmentError<'tcx> {
FulfillmentError { obligation, code, root_obligation }
}

pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span {
Copy link
Member

Choose a reason for hiding this comment

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

I feel like it's incredibly easy to forget to use this function over .obligation.cause.span - can you consider another solution that doesn't give devs more choices that cause subtle inconsistencies when used differently?

Copy link
Contributor Author

@estebank estebank Mar 30, 2024

Choose a reason for hiding this comment

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

The issue about forgetting to call the method is fair, but do notice that we're already duplicating logic to modify that span after the fact in the current code. I'm concerned about properly tracking the span from inception if that will require additional memory or have non-trivial runtime impact on non-diagnostic codepaths. I'll see what options we have available to us that don't have those problems.

The reason I wasn't too concerned about this approach is that the resulting behavior when forgetting to call this method is "just" a different span, in a different error, which tbqh felt "fine".

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 had to still use a closure for the deduplication logic (as it is very local to this one E0277 error for Sized locals), but otherwise the obligation span is now the one we want for all errors.

@estebank
Copy link
Contributor Author

estebank commented Apr 1, 2024

Apologies for dumping more commits to the same PR. Each commit is locally independent (they could be their own PRs), but each individual step is building a tiny bit more on the previous one. I believe that there are may be a handful of additional things that could be done here (particularly, reduce redundancy between E0038 and E0277), but likely nothing more that should be added to this one. If the load is too much, feel free to review as many commits in a row as you feel comfortable, and I'll split the rest to their own PR(s).

@estebank
Copy link
Contributor Author

estebank commented Apr 2, 2024

Blocker: this needs to compile-pass

error[E0277]: the size for values of type `str` cannot be known at compilation time
 --> f108.rs:2:16
  |
2 |     let ref x: str = *"";
  |                ^^^ doesn't have a size known at compile-time
  |
  = help: the trait `Sized` is not implemented for `str`
  = note: all local variables must have a statically known size
  = help: unsized locals are gated as an unstable feature
help: consider borrowing here
  |
2 |     let ref x: &str = *"";
  |                +

Thanks @eddyb for flagging this.

Edit: addressed in the last commit. Only the top level ref ident pattern in a let binding needs to be accounted for, as any other let binding type that isn't sized already fails on the type itself.

Comment on lines 46 to +49
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/suggest-borrow.rs:4:9
--> $DIR/suggest-borrow.rs:4:19
|
LL | let x: [u8] = &vec!(1, 2, 3)[..];
| ^ doesn't have a size known at compile-time
| ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is weird: it should point at the type, not the init expr. If I modify the test to make this the only thing here, then it does the right thing. I'm not too concerned because of the close locality but it is technically incorrect (as the expr has type &[u8], the binding is [u8]).

@rust-log-analyzer

This comment has been minimized.

…0746

* If the return value types diverge, mention it and do not suggest `impl Trait`
* If the returned `dyn Trait` is not object safe, mention it and do not suggest `Box<dyn Trait>` and boxing the returned values
* If the function has arguments with borrowed types, suggest `&dyn Trait`
* Tweak wording of `E0782`

```
error[E0746]: return type cannot have an unboxed trait object
  --> $DIR/dyn-trait-return-should-be-impl-trait.rs:13:13
   |
LL | fn bap() -> Trait { Struct }
   |             ^^^^^ doesn't have a size known at compile-time
   |
help: return an `impl Trait` instead of a `dyn Trait`
   |
LL | fn bap() -> impl Trait { Struct }
   |             ++++
help: alternatively, box the return type to make a boxed trait object, and wrap all of the returned values in `Box::new`
   |
LL | fn bap() -> Box<dyn Trait> { Box::new(Struct) }
   |             +++++++      +   +++++++++      +
```
```
error[E0746]: return type cannot have an unboxed trait object
  --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:36:18
   |
LL | fn can(x: &A) -> dyn NotObjectSafe {
   |                  ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
help: trait `NotObjectSafe` is not object safe, so you can't return a boxed trait object `Box<dyn NotObjectSafe>`
  --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:36:22
   |
LL | fn can(x: &A) -> dyn NotObjectSafe {
   |                      ^^^^^^^^^^^^^
help: return an `impl Trait` instead of a `dyn Trait`
   |
LL | fn can(x: &A) -> impl NotObjectSafe {
   |                  ~~~~
help: alternatively, you might be able to borrow from the function's argument
   |
LL | fn can(x: &A) -> &dyn NotObjectSafe {
   |                  +
```
```
error[E0782]: trait objects must include the `dyn` keyword
  --> $DIR/not-on-bare-trait-2021.rs:12:19
   |
LL | fn bar(x: Foo) -> Foo {
   |                   ^^^
   |
help: use `impl Foo` to return an opaque type, as long as you return a single underlying type
   |
LL | fn bar(x: Foo) -> impl Foo {
   |                   ++++
help: alternatively, you can return a boxed trait object
   |
LL | fn bar(x: Foo) -> Box<dyn Foo> {
   |                   +++++++    +
```
```
error[E0746]: return type cannot have an unboxed trait object
 --> tests/ui/unsized/issue-91801.rs:8:77
  |
8 | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Validator<'a> {
  |                                                                             ^^^^^^^^^^^^^ doesn't have a size known at compile-time
-Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs:566:39
  |
help: box the return type to make a boxed trait object, and wrap all of the returned values in `Box::new`
  |
8 | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box<Validator<'a>> {
  |                                                                             ++++             +
help: alternatively, you might be able to borrow from one of the function's arguments
  |
8 | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> &Validator<'a> {
  |                                                                             +
```
Use a method for caulculating deduplication and presentation span.
* Point at let binding type or init that is `?Sized`, as appropriate
* On `?Sized` binding *access*, do not emit an error as we will already have emitted one on the binding
…rate spans

```
error[E0277]: the size for values of type `X` cannot be known at compilation time
  --> $DIR/unsized6.rs:26:19
   |
LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
   |       - this type parameter needs to be `Sized`
...
LL |     let (y, z) = (*x3, 4);
   |                   ^^^ doesn't have a size known at compile-time
   |
   = note: all local variables must have a statically known size
   = help: unsized locals are gated as an unstable feature
help: consider removing the `?Sized` bound to make the type parameter `Sized`
   |
LL - fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
LL + fn f3<X>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
   |
```
```
error[E0277]: the size for values of type `dyn T` cannot be known at compilation time
  --> $DIR/unsized-binding.rs:12:28
   |
LL |     let Foo(a, b) = Foo(1, bar());
   |                            ^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `dyn T`
   = note: all local variables must have a statically known size
   = help: unsized locals are gated as an unstable feature
```
…of two

On stable, unify wording of unsized locals and unsized fn params so the deduplication machinery can trigger.

On nightly, mention the nightly feature to enable unsized locals or unsized fn params.
@estebank
Copy link
Contributor Author

r? @oli-obk

This is the PR we talked about earlier today. You can review each commit independently and I'll split them out to their own PR.

@rustbot rustbot assigned oli-obk and unassigned TaKO8Ki Apr 11, 2024
sugg,
Applicability::MaybeIncorrect,
);
let object_unsafe: Vec<_> = traits
Copy link
Contributor

Choose a reason for hiding this comment

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

The function is called suggest_impl_trait, but this doesn't do that. Needs a name update and doc update.

Please split up this function into three functions (impl Trait, Box<dyn Trait>, and &dyn Trait).

@wesleywiser wesleywiser 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 Jun 27, 2024
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.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

E0872 and E0746 should suggest "impl Trait" more prominently Too many dyn Trait is not Sized errors
9 participants