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

More accurate suggestion for -> Box<dyn Trait> or -> impl Trait #127987

Merged
merged 1 commit into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1793,25 +1793,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
err.children.clear();

let span = obligation.cause.span;
if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
let body = self.tcx.hir().body_owned_by(obligation.cause.body_id);

let mut visitor = ReturnsVisitor::default();
visitor.visit_body(&body);

let (pre, impl_span) = if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
&& snip.starts_with("dyn ")
{
err.span_suggestion(
span.with_hi(span.lo() + BytePos(4)),
"return an `impl Trait` instead of a `dyn Trait`, \
if all returned values are the same type",
("", span.with_hi(span.lo() + BytePos(4)))
} else {
("dyn ", span.shrink_to_lo())
};
let alternatively = if visitor
.returns
.iter()
.map(|expr| self.typeck_results.as_ref().unwrap().expr_ty_adjusted_opt(expr))
.collect::<FxHashSet<_>>()
.len()
<= 1
{
err.span_suggestion_verbose(
impl_span,
"consider returning an `impl Trait` instead of a `dyn Trait`",
"impl ",
Applicability::MaybeIncorrect,
);
}

let body = self.tcx.hir().body_owned_by(obligation.cause.body_id);

let mut visitor = ReturnsVisitor::default();
visitor.visit_body(&body);
"alternatively, "
} else {
err.help("if there were a single returned type, you could use `impl Trait` instead");
""
};

let mut sugg =
vec![(span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string())];
let mut sugg = vec![
(span.shrink_to_lo(), format!("Box<{pre}")),
(span.shrink_to_hi(), ">".to_string()),
];
sugg.extend(visitor.returns.into_iter().flat_map(|expr| {
let span =
expr.span.find_ancestor_in_same_ctxt(obligation.cause.span).unwrap_or(expr.span);
Expand All @@ -1837,7 +1854,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}));

err.multipart_suggestion(
"box the return type, and wrap all of the returned values in `Box::new`",
format!(
"{alternatively}box the return type, and wrap all of the returned values in \
`Box::new`",
),
sugg,
Applicability::MaybeIncorrect,
);
Expand Down
9 changes: 3 additions & 6 deletions tests/ui/error-codes/E0746.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn foo() -> dyn Trait { Struct }
| ^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL | fn foo() -> impl Trait { Struct }
| ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL | fn foo() -> Box<dyn Trait> { Box::new(Struct) }
| ++++ + +++++++++ +
Expand All @@ -19,10 +19,7 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bar() -> dyn Trait {
| ^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
LL | fn bar() -> impl Trait {
| ~~~~
= help: if there were a single returned type, you could use `impl Trait` instead
help: box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn bar() -> Box<dyn Trait> {
Expand Down
38 changes: 15 additions & 23 deletions tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,26 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bap() -> Trait { Struct }
| ^^^^^ doesn't have a size known at compile-time
|
help: box the return type, and wrap all of the returned values in `Box::new`
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL | fn bap() -> impl Trait { Struct }
| ++++
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL | fn bap() -> Box<Trait> { Box::new(Struct) }
| ++++ + +++++++++ +
LL | fn bap() -> Box<dyn Trait> { Box::new(Struct) }
| +++++++ + +++++++++ +

error[E0746]: return type cannot have an unboxed trait object
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:15:13
|
LL | fn ban() -> dyn Trait { Struct }
| ^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL | fn ban() -> impl Trait { Struct }
| ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL | fn ban() -> Box<dyn Trait> { Box::new(Struct) }
| ++++ + +++++++++ +
Expand All @@ -74,11 +78,11 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bak() -> dyn Trait { unimplemented!() }
| ^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL | fn bak() -> impl Trait { unimplemented!() }
| ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL | fn bak() -> Box<dyn Trait> { Box::new(unimplemented!()) }
| ++++ + +++++++++ +
Expand All @@ -89,10 +93,7 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bal() -> dyn Trait {
| ^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
LL | fn bal() -> impl Trait {
| ~~~~
= help: if there were a single returned type, you could use `impl Trait` instead
help: box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn bal() -> Box<dyn Trait> {
Expand All @@ -108,10 +109,7 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bax() -> dyn Trait {
| ^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
LL | fn bax() -> impl Trait {
| ~~~~
= help: if there were a single returned type, you could use `impl Trait` instead
help: box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn bax() -> Box<dyn Trait> {
Expand Down Expand Up @@ -263,10 +261,7 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bat() -> dyn Trait {
| ^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
LL | fn bat() -> impl Trait {
| ~~~~
= help: if there were a single returned type, you could use `impl Trait` instead
help: box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn bat() -> Box<dyn Trait> {
Expand All @@ -282,10 +277,7 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bay() -> dyn Trait {
| ^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
LL | fn bay() -> impl Trait {
| ~~~~
= help: if there were a single returned type, you could use `impl Trait` instead
help: box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn bay() -> Box<dyn Trait> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,7 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn car() -> dyn NotObjectSafe {
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
LL | fn car() -> impl NotObjectSafe {
| ~~~~
= help: if there were a single returned type, you could use `impl Trait` instead
help: box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn car() -> Box<dyn NotObjectSafe> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,11 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn hat() -> dyn std::fmt::Display {
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL | fn hat() -> impl std::fmt::Display {
| ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn hat() -> Box<dyn std::fmt::Display> {
LL | match 13 {
Expand All @@ -192,11 +192,11 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn pug() -> dyn std::fmt::Display {
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL | fn pug() -> impl std::fmt::Display {
| ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn pug() -> Box<dyn std::fmt::Display> {
LL | match 13 {
Expand All @@ -211,10 +211,7 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn man() -> dyn std::fmt::Display {
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
LL | fn man() -> impl std::fmt::Display {
| ~~~~
= help: if there were a single returned type, you could use `impl Trait` instead
help: box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn man() -> Box<dyn std::fmt::Display> {
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/issues/issue-18107.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ error[E0746]: return type cannot have an unboxed trait object
LL | dyn AbstractRenderer
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL | impl AbstractRenderer
| ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ Box<dyn AbstractRenderer>
LL |
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/unsized/box-instead-of-dyn-fn.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> dyn Fn() + 'a {
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> impl Fn() + 'a {
| ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> Box<dyn Fn() + 'a> {
LL |
Expand Down
10 changes: 7 additions & 3 deletions tests/ui/unsized/issue-91801.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Validator<'a> {
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
help: box the return type, and wrap all of the returned values in `Box::new`
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box<Validator<'a>> {
| ++++ +
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> impl Validator<'a> {
| ++++
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box<dyn Validator<'a>> {
| +++++++ +

error: aborting due to 1 previous error

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/unsized/issue-91803.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> dyn Foo<'a> {
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> impl Foo<'a> {
| ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> Box<dyn Foo<'a>> {
| ++++ +
Expand Down
Loading