Simplify suggestion when returning bare dyn trait

This commit is contained in:
Michael Goulet 2023-05-18 01:47:55 +00:00
parent e9e1bbc7a8
commit 795fdf7d61
11 changed files with 173 additions and 363 deletions

View File

@ -885,7 +885,7 @@ fn report_selection_error(
return; return;
} }
if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) { if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
err.emit(); err.emit();
return; return;
} }

View File

@ -30,9 +30,9 @@
use rustc_middle::ty::error::TypeError::{self, Sorts}; use rustc_middle::ty::error::TypeError::{self, Sorts};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind,
GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts, GeneratorDiagnosticData, GeneratorInteriorTypeCause, InferTy, InternalSubsts, IsSuggestable,
IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeSuperFoldable, TypeVisitableExt, TypeckResults, TypeVisitableExt, TypeckResults,
}; };
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::symbol::{sym, Ident, Symbol};
@ -261,7 +261,6 @@ fn suggest_semicolon_removal(
fn suggest_impl_trait( fn suggest_impl_trait(
&self, &self,
err: &mut Diagnostic, err: &mut Diagnostic,
span: Span,
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool; ) -> bool;
@ -1792,215 +1791,66 @@ fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Spa
fn suggest_impl_trait( fn suggest_impl_trait(
&self, &self,
err: &mut Diagnostic, err: &mut Diagnostic,
span: Span,
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool { ) -> bool {
match obligation.cause.code().peel_derives() { let ObligationCauseCode::SizedReturnType = obligation.cause.code() else {
// Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`.
ObligationCauseCode::SizedReturnType => {}
_ => return false,
}
let hir = self.tcx.hir();
let fn_hir_id = hir.local_def_id_to_hir_id(obligation.cause.body_id);
let node = hir.find_by_def_id(obligation.cause.body_id);
let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(sig, _, body_id),
..
})) = node
else {
return false; return false;
}; };
let body = hir.body(*body_id); let ty::Dynamic(_, _, ty::Dyn) = trait_pred.self_ty().skip_binder().kind() else {
let trait_pred = self.resolve_vars_if_possible(trait_pred);
let ty = trait_pred.skip_binder().self_ty();
let is_object_safe = match ty.kind() {
ty::Dynamic(predicates, _, ty::Dyn) => {
// If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
predicates
.principal_def_id()
.map_or(true, |def_id| self.tcx.check_is_object_safe(def_id))
}
// We only want to suggest `impl Trait` to `dyn Trait`s.
// For example, `fn foo() -> str` needs to be filtered out.
_ => return false,
};
let hir::FnRetTy::Return(ret_ty) = sig.decl.output else {
return false; return false;
}; };
// Use `TypeVisitor` instead of the output type directly to find the span of `ty` for
// cases like `fn foo() -> (dyn Trait, i32) {}`.
// Recursively look for `TraitObject` types and if there's only one, use that span to
// suggest `impl Trait`.
// Visit to make sure there's a single `return` type to suggest `impl Trait`,
// otherwise suggest using `Box<dyn Trait>` or an enum.
let mut visitor = ReturnsVisitor::default();
visitor.visit_body(&body);
let typeck_results = self.typeck_results.as_ref().unwrap();
let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; };
let ret_types = visitor
.returns
.iter()
.filter_map(|expr| Some((expr.span, typeck_results.node_type_opt(expr.hir_id)?)))
.map(|(expr_span, ty)| (expr_span, self.resolve_vars_if_possible(ty)));
let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold(
(None, true, true),
|(last_ty, mut same, only_never_return): (std::option::Option<Ty<'_>>, bool, bool),
(_, ty)| {
let ty = self.resolve_vars_if_possible(ty);
same &=
!matches!(ty.kind(), ty::Error(_))
&& last_ty.map_or(true, |last_ty| {
// FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes
// *after* in the dependency graph.
match (ty.kind(), last_ty.kind()) {
(Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_)))
| (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_)))
| (Infer(InferTy::FreshIntTy(_)), Infer(InferTy::FreshIntTy(_)))
| (
Infer(InferTy::FreshFloatTy(_)),
Infer(InferTy::FreshFloatTy(_)),
) => true,
_ => ty == last_ty,
}
});
(Some(ty), same, only_never_return && matches!(ty.kind(), ty::Never))
},
);
let mut spans_and_needs_box = vec![];
match liberated_sig.output().kind() {
ty::Dynamic(predicates, _, ty::Dyn) => {
let cause = ObligationCause::misc(ret_ty.span, obligation.cause.body_id);
let param_env = ty::ParamEnv::empty();
if !only_never_return {
for (expr_span, return_ty) in ret_types {
let self_ty_satisfies_dyn_predicates = |self_ty| {
predicates.iter().all(|predicate| {
let pred = predicate.with_self_ty(self.tcx, self_ty);
let obl = Obligation::new(self.tcx, cause.clone(), param_env, pred);
self.predicate_may_hold(&obl)
})
};
if let ty::Adt(def, substs) = return_ty.kind()
&& def.is_box()
&& self_ty_satisfies_dyn_predicates(substs.type_at(0))
{
spans_and_needs_box.push((expr_span, false));
} else if self_ty_satisfies_dyn_predicates(return_ty) {
spans_and_needs_box.push((expr_span, true));
} else {
return false;
}
}
}
}
_ => return false,
};
let sm = self.tcx.sess.source_map();
if !ret_ty.span.overlaps(span) {
return false;
}
let snippet = if let hir::TyKind::TraitObject(..) = ret_ty.kind {
if let Ok(snippet) = sm.span_to_snippet(ret_ty.span) {
snippet
} else {
return false;
}
} else {
// Substitute the type, so we can print a fixup given `type Alias = dyn Trait`
let name = liberated_sig.output().to_string();
let name =
name.strip_prefix('(').and_then(|name| name.strip_suffix(')')).unwrap_or(&name);
if !name.starts_with("dyn ") {
return false;
}
name.to_owned()
};
err.code(error_code!(E0746)); err.code(error_code!(E0746));
err.set_primary_message("return type cannot have an unboxed trait object"); err.set_primary_message("return type cannot have an unboxed trait object");
err.children.clear(); err.children.clear();
let impl_trait_msg = "for information on `impl Trait`, see \
<https://doc.rust-lang.org/book/ch10-02-traits.html\
#returning-types-that-implement-traits>";
let trait_obj_msg = "for information on trait objects, see \
<https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
#using-trait-objects-that-allow-for-values-of-different-types>";
let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn"); let span = obligation.cause.span;
let trait_obj = if has_dyn { &snippet[4..] } else { &snippet }; if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
if only_never_return { && snip.starts_with("dyn ")
// No return paths, probably using `panic!()` or similar. {
// Suggest `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`.
suggest_trait_object_return_type_alternatives(
err,
ret_ty.span,
trait_obj,
is_object_safe,
);
} else if let (Some(last_ty), true) = (last_ty, all_returns_have_same_type) {
// Suggest `-> impl Trait`.
err.span_suggestion( err.span_suggestion(
ret_ty.span, span.with_hi(span.lo() + BytePos(4)),
format!( "return an `impl Trait` instead of a `dyn Trait`, \
"use `impl {1}` as the return type, as all return paths are of type `{}`, \ if all returned values are the same type",
which implements `{1}`", "impl ",
last_ty, trait_obj,
),
format!("impl {}", trait_obj),
Applicability::MachineApplicable,
);
err.note(impl_trait_msg);
} else {
if is_object_safe {
// Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
err.multipart_suggestion(
"return a boxed trait object instead",
vec![
(ret_ty.span.shrink_to_lo(), "Box<".to_string()),
(span.shrink_to_hi(), ">".to_string()),
],
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
for (span, needs_box) in spans_and_needs_box { }
if needs_box {
err.multipart_suggestion( let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(obligation.cause.body_id));
"... and box this value",
let mut visitor = ReturnsVisitor::default();
visitor.visit_body(&body);
let mut sugg =
vec![(span.shrink_to_lo(), "Box<".to_string()), (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);
if !span.can_be_used_for_suggestions() {
vec![]
} else if let hir::ExprKind::Call(path, ..) = expr.kind
&& let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, method)) = path.kind
&& method.ident.name == sym::new
&& let hir::TyKind::Path(hir::QPath::Resolved(.., box_path)) = ty.kind
&& box_path.res.opt_def_id().is_some_and(|def_id| Some(def_id) == self.tcx.lang_items().owned_box())
{
// Don't box `Box::new`
vec![]
} else {
vec![ vec![
(span.shrink_to_lo(), "Box::new(".to_string()), (span.shrink_to_lo(), "Box::new(".to_string()),
(span.shrink_to_hi(), ")".to_string()), (span.shrink_to_hi(), ")".to_string()),
], ]
}
}));
err.multipart_suggestion(
"box the return type, and wrap all of the returned values in `Box::new`",
sugg,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
}
}
} else {
// This is currently not possible to trigger because E0038 takes precedence, but
// leave it in for completeness in case anything changes in an earlier stage.
err.note(format!(
"if trait `{}` were object-safe, you could return a trait object",
trait_obj,
));
}
err.note(trait_obj_msg);
err.note(format!(
"if all the returned values were of the same type you could use `impl {}` as the \
return type",
trait_obj,
));
err.note(impl_trait_msg);
err.note("you can create a new `enum` with a variant for each returned type");
}
true true
} }
@ -4139,37 +3989,6 @@ fn next_type_param_name(&self, name: Option<&str>) -> String {
} }
} }
fn suggest_trait_object_return_type_alternatives(
err: &mut Diagnostic,
ret_ty: Span,
trait_obj: &str,
is_object_safe: bool,
) {
err.span_suggestion(
ret_ty,
format!(
"use `impl {}` as the return type if all return paths have the same type but you \
want to expose only the trait in the signature",
trait_obj,
),
format!("impl {}", trait_obj),
Applicability::MaybeIncorrect,
);
if is_object_safe {
err.multipart_suggestion(
format!(
"use a boxed trait object if all return paths implement trait `{}`",
trait_obj,
),
vec![
(ret_ty.shrink_to_lo(), "Box<".to_string()),
(ret_ty.shrink_to_hi(), ">".to_string()),
],
Applicability::MaybeIncorrect,
);
}
}
/// Collect the spans that we see the generic param `param_did` /// Collect the spans that we see the generic param `param_did`
struct ReplaceImplTraitVisitor<'a> { struct ReplaceImplTraitVisitor<'a> {
ty_spans: &'a mut Vec<Span>, ty_spans: &'a mut Vec<Span>,

View File

@ -1,18 +0,0 @@
// run-rustfix
#![allow(dead_code)]
struct Struct;
trait Trait {}
impl Trait for Struct {}
impl Trait for u32 {}
fn foo() -> impl Trait { Struct }
//~^ ERROR E0746
fn bar() -> impl Trait { //~ ERROR E0746
if true {
return 0;
}
42
}
fn main() {}

View File

@ -1,5 +1,5 @@
// run-rustfix
#![allow(dead_code)] #![allow(dead_code)]
struct Struct; struct Struct;
trait Trait {} trait Trait {}
impl Trait for Struct {} impl Trait for Struct {}

View File

@ -4,11 +4,14 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn foo() -> dyn Trait { Struct } LL | fn foo() -> dyn Trait { Struct }
| ^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait`
| |
LL | fn foo() -> impl Trait { Struct } LL | fn foo() -> impl Trait { Struct }
| ~~~~~~~~~~ | ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
|
LL | fn foo() -> Box<dyn Trait> { Box::new(Struct) }
| ++++ + +++++++++ +
error[E0746]: return type cannot have an unboxed trait object error[E0746]: return type cannot have an unboxed trait object
--> $DIR/E0746.rs:11:13 --> $DIR/E0746.rs:11:13
@ -16,11 +19,18 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bar() -> dyn Trait { LL | fn bar() -> dyn Trait {
| ^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait`
| |
LL | fn bar() -> impl Trait { LL | fn bar() -> impl Trait {
| ~~~~~~~~~~ | ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn bar() -> Box<dyn Trait> {
LL | if true {
LL ~ return Box::new(0);
LL | }
LL ~ Box::new(42)
|
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View File

@ -46,11 +46,10 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bap() -> Trait { Struct } LL | fn bap() -> Trait { Struct }
| ^^^^^ doesn't have a size known at compile-time | ^^^^^ doesn't have a size known at compile-time
| |
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> help: box the return type, and wrap all of the returned values in `Box::new`
help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait`
| |
LL | fn bap() -> impl Trait { Struct } LL | fn bap() -> Box<Trait> { Box::new(Struct) }
| ~~~~~~~~~~ | ++++ + +++++++++ +
error[E0746]: return type cannot have an unboxed trait object error[E0746]: return type cannot have an unboxed trait object
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:15:13 --> $DIR/dyn-trait-return-should-be-impl-trait.rs:15:13
@ -58,11 +57,14 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn ban() -> dyn Trait { Struct } LL | fn ban() -> dyn Trait { Struct }
| ^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: use `impl Trait` as the return type, as all return paths are of type `Struct`, which implements `Trait`
| |
LL | fn ban() -> impl Trait { Struct } LL | fn ban() -> impl Trait { Struct }
| ~~~~~~~~~~ | ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
|
LL | fn ban() -> Box<dyn Trait> { Box::new(Struct) }
| ++++ + +++++++++ +
error[E0746]: return type cannot have an unboxed trait object error[E0746]: return type cannot have an unboxed trait object
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:17:13 --> $DIR/dyn-trait-return-should-be-impl-trait.rs:17:13
@ -70,14 +72,14 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bak() -> dyn Trait { unimplemented!() } LL | fn bak() -> dyn Trait { unimplemented!() }
| ^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^ doesn't have a size known at compile-time
| |
help: use `impl Trait` as the return type if all return paths have the same type but you want to expose only the trait in the signature help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
| |
LL | fn bak() -> impl Trait { unimplemented!() } LL | fn bak() -> impl Trait { unimplemented!() }
| ~~~~~~~~~~ | ~~~~
help: use a boxed trait object if all return paths implement trait `Trait` help: box the return type, and wrap all of the returned values in `Box::new`
| |
LL | fn bak() -> Box<dyn Trait> { unimplemented!() } LL | fn bak() -> Box<dyn Trait> { Box::new(unimplemented!()) }
| ++++ + | ++++ + +++++++++ +
error[E0746]: return type cannot have an unboxed trait object error[E0746]: return type cannot have an unboxed trait object
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13 --> $DIR/dyn-trait-return-should-be-impl-trait.rs:19:13
@ -85,22 +87,18 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bal() -> dyn Trait { LL | fn bal() -> dyn Trait {
| ^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
= note: if all the returned values were of the same type you could use `impl Trait` as the return type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= note: you can create a new `enum` with a variant for each returned type
help: return a boxed trait object instead
| |
LL | fn bal() -> Box<dyn Trait> { LL | fn bal() -> impl Trait {
| ++++ + | ~~~~
help: ... and box this value help: box the return type, and wrap all of the returned values in `Box::new`
| |
LL | return Box::new(Struct); LL ~ fn bal() -> Box<dyn Trait> {
| +++++++++ + LL | if true {
help: ... and box this value LL ~ return Box::new(Struct);
LL | }
LL ~ Box::new(42)
| |
LL | Box::new(42)
| +++++++++ +
error[E0308]: `if` and `else` have incompatible types error[E0308]: `if` and `else` have incompatible types
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:29:9 --> $DIR/dyn-trait-return-should-be-impl-trait.rs:29:9
@ -120,22 +118,18 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bax() -> dyn Trait { LL | fn bax() -> dyn Trait {
| ^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
= note: if all the returned values were of the same type you could use `impl Trait` as the return type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= note: you can create a new `enum` with a variant for each returned type
help: return a boxed trait object instead
| |
LL | fn bax() -> Box<dyn Trait> { LL | fn bax() -> impl Trait {
| ++++ + | ~~~~
help: ... and box this value help: box the return type, and wrap all of the returned values in `Box::new`
| |
LL | Box::new(Struct) LL ~ fn bax() -> Box<dyn Trait> {
| +++++++++ + LL | if true {
help: ... and box this value LL ~ Box::new(Struct)
LL | } else {
LL ~ Box::new(42)
| |
LL | Box::new(42)
| +++++++++ +
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:34:16 --> $DIR/dyn-trait-return-should-be-impl-trait.rs:34:16
@ -279,11 +273,18 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bat() -> dyn Trait { LL | fn bat() -> dyn Trait {
| ^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait`
| |
LL | fn bat() -> impl Trait { LL | fn bat() -> impl Trait {
| ~~~~~~~~~~ | ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn bat() -> Box<dyn Trait> {
LL | if true {
LL ~ return Box::new(0);
LL | }
LL ~ Box::new(42)
|
error[E0746]: return type cannot have an unboxed trait object error[E0746]: return type cannot have an unboxed trait object
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:66:13 --> $DIR/dyn-trait-return-should-be-impl-trait.rs:66:13
@ -291,11 +292,18 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn bay() -> dyn Trait { LL | fn bay() -> dyn Trait {
| ^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: use `impl Trait` as the return type, as all return paths are of type `{integer}`, which implements `Trait`
| |
LL | fn bay() -> impl Trait { LL | fn bay() -> impl Trait {
| ~~~~~~~~~~ | ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
|
LL ~ fn bay() -> Box<dyn Trait> {
LL | if true {
LL ~ Box::new(0)
LL | } else {
LL ~ Box::new(42)
|
error: aborting due to 20 previous errors error: aborting due to 20 previous errors

View File

@ -171,22 +171,20 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn hat() -> dyn std::fmt::Display { LL | fn hat() -> dyn std::fmt::Display {
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
= note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= note: you can create a new `enum` with a variant for each returned type
help: return a boxed trait object instead
| |
LL | fn hat() -> Box<dyn std::fmt::Display> { LL | fn hat() -> impl std::fmt::Display {
| ++++ + | ~~~~
help: ... and box this value help: box the return type, and wrap all of the returned values in `Box::new`
| |
LL | return Box::new(0i32); LL ~ fn hat() -> Box<dyn std::fmt::Display> {
| +++++++++ + LL | match 13 {
help: ... and box this value LL | 0 => {
LL ~ return Box::new(0i32);
LL | }
LL | _ => {
LL ~ Box::new(1u32)
| |
LL | Box::new(1u32)
| +++++++++ +
error[E0308]: `match` arms have incompatible types error[E0308]: `match` arms have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:80:14 --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:80:14
@ -211,26 +209,18 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn pug() -> dyn std::fmt::Display { LL | fn pug() -> dyn std::fmt::Display {
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
= note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= note: you can create a new `enum` with a variant for each returned type
help: return a boxed trait object instead
| |
LL | fn pug() -> Box<dyn std::fmt::Display> { LL | fn pug() -> impl std::fmt::Display {
| ++++ + | ~~~~
help: ... and box this value help: box the return type, and wrap all of the returned values in `Box::new`
| |
LL | 0 => Box::new(0i32), LL ~ fn pug() -> Box<dyn std::fmt::Display> {
| +++++++++ + LL | match 13 {
help: ... and box this value LL ~ 0 => Box::new(0i32),
LL ~ 1 => Box::new(1u32),
LL ~ _ => Box::new(2u32),
| |
LL | 1 => Box::new(1u32),
| +++++++++ +
help: ... and box this value
|
LL | _ => Box::new(2u32),
| +++++++++ +
error[E0308]: `if` and `else` have incompatible types error[E0308]: `if` and `else` have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:89:9 --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:89:9
@ -255,22 +245,18 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn man() -> dyn std::fmt::Display { LL | fn man() -> dyn std::fmt::Display {
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
= note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= note: you can create a new `enum` with a variant for each returned type
help: return a boxed trait object instead
| |
LL | fn man() -> Box<dyn std::fmt::Display> { LL | fn man() -> impl std::fmt::Display {
| ++++ + | ~~~~
help: ... and box this value help: box the return type, and wrap all of the returned values in `Box::new`
| |
LL | Box::new(0i32) LL ~ fn man() -> Box<dyn std::fmt::Display> {
| +++++++++ + LL | if false {
help: ... and box this value LL ~ Box::new(0i32)
LL | } else {
LL ~ Box::new(1u32)
| |
LL | Box::new(1u32)
| +++++++++ +
error: aborting due to 14 previous errors error: aborting due to 14 previous errors

View File

@ -4,14 +4,18 @@ error[E0746]: return type cannot have an unboxed trait object
LL | dyn AbstractRenderer LL | dyn AbstractRenderer
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
| |
help: use `impl AbstractRenderer` as the return type if all return paths have the same type but you want to expose only the trait in the signature help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
| |
LL | impl AbstractRenderer LL | impl AbstractRenderer
| ~~~~
help: box the return type, and wrap all of the returned values in `Box::new`
| |
help: use a boxed trait object if all return paths implement trait `AbstractRenderer` LL ~ Box<dyn AbstractRenderer>
LL |
LL | {
LL | match 0 {
LL ~ _ => Box::new(unimplemented!())
| |
LL | Box<dyn AbstractRenderer>
| ++++ +
error: aborting due to previous error error: aborting due to previous error

View File

@ -23,18 +23,17 @@ 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 { 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 | ^^^^^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types> help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
= note: if all the returned values were of the same type you could use `impl Fn() + 'a` as the return type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= note: you can create a new `enum` with a variant for each returned type
help: return a boxed trait object instead
| |
LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> Box<dyn Fn() + 'a> { LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> impl Fn() + 'a {
| ++++ + | ~~~~
help: ... and box this value help: 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 |
LL | if a % 2 == 0 {
LL ~ Box::new(move || println!("{a}"))
| |
LL | Box::new(move || println!("{a}"))
| +++++++++ +
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View File

@ -4,11 +4,10 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Validator<'a> { LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Validator<'a> {
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> help: box the return type, and wrap all of the returned values in `Box::new`
help: use `impl Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a` as the return type, as all return paths are of type `Box<[closure@$DIR/issue-91801.rs:10:21: 10:70]>`, which implements `Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a`
| |
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> impl Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a { LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box<Validator<'a>> {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ++++ +
error: aborting due to previous error error: aborting due to previous error

View File

@ -4,11 +4,14 @@ error[E0746]: return type cannot have an unboxed trait object
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> dyn Foo<'a> { LL | fn or<'a>(first: &'static dyn Foo<'a>) -> dyn Foo<'a> {
| ^^^^^^^^^^^ doesn't have a size known at compile-time | ^^^^^^^^^^^ doesn't have a size known at compile-time
| |
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
help: use `impl Foo<'a>` as the return type, as all return paths are of type `Box<_>`, which implements `Foo<'a>`
| |
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> impl Foo<'a> { 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`
|
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> Box<dyn Foo<'a>> {
| ++++ +
error: aborting due to previous error error: aborting due to previous error