Simplify suggestion when returning bare dyn trait
This commit is contained in:
parent
e9e1bbc7a8
commit
795fdf7d61
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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>,
|
||||||
|
@ -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() {}
|
|
@ -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 {}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user