review comments
This commit is contained in:
parent
c305ac31c0
commit
d7a6212401
|
@ -25,7 +25,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc_hir::intravisit::Visitor;
|
|
||||||
use rustc_span::source_map::SourceMap;
|
use rustc_span::source_map::SourceMap;
|
||||||
use rustc_span::{ExpnKind, Span, DUMMY_SP};
|
use rustc_span::{ExpnKind, Span, DUMMY_SP};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -1411,34 +1410,3 @@ pub fn suggest_constraining_type_param(
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collect all the returned expressions within the input expression.
|
|
||||||
/// Used to point at the return spans when we want to suggest some change to them.
|
|
||||||
struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
|
|
||||||
|
|
||||||
impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
|
|
||||||
type Map = rustc::hir::map::Map<'v>;
|
|
||||||
|
|
||||||
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> {
|
|
||||||
hir::intravisit::NestedVisitorMap::None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
|
||||||
match ex.kind {
|
|
||||||
hir::ExprKind::Ret(Some(ex)) => self.0.push(ex),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
hir::intravisit::walk_expr(self, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_body(&mut self, body: &'v hir::Body<'v>) {
|
|
||||||
if body.generator_kind().is_none() {
|
|
||||||
if let hir::ExprKind::Block(block, None) = body.value.kind {
|
|
||||||
if let Some(expr) = block.expr {
|
|
||||||
self.0.push(expr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hir::intravisit::walk_body(self, body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -563,157 +563,159 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
let hir = self.tcx.hir();
|
let hir = self.tcx.hir();
|
||||||
let parent_node = hir.get_parent_node(obligation.cause.body_id);
|
let parent_node = hir.get_parent_node(obligation.cause.body_id);
|
||||||
let node = hir.find(parent_node);
|
let node = hir.find(parent_node);
|
||||||
if let Some(hir::Node::Item(hir::Item {
|
let (sig, body_id) = if let Some(hir::Node::Item(hir::Item {
|
||||||
kind: hir::ItemKind::Fn(sig, _, body_id), ..
|
kind: hir::ItemKind::Fn(sig, _, body_id),
|
||||||
|
..
|
||||||
})) = node
|
})) = node
|
||||||
{
|
{
|
||||||
let body = hir.body(*body_id);
|
(sig, body_id)
|
||||||
let trait_ref = self.resolve_vars_if_possible(trait_ref);
|
} else {
|
||||||
let ty = trait_ref.skip_binder().self_ty();
|
return false;
|
||||||
let is_object_safe;
|
};
|
||||||
match ty.kind {
|
let body = hir.body(*body_id);
|
||||||
ty::Dynamic(predicates, _) => {
|
let trait_ref = self.resolve_vars_if_possible(trait_ref);
|
||||||
// The `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
|
let ty = trait_ref.skip_binder().self_ty();
|
||||||
is_object_safe = predicates.principal_def_id().map_or(true, |def_id| {
|
let is_object_safe = match ty.kind {
|
||||||
!object_safety_violations(self.tcx, def_id).is_empty()
|
ty::Dynamic(predicates, _) => {
|
||||||
})
|
// If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
|
||||||
}
|
predicates
|
||||||
// We only want to suggest `impl Trait` to `dyn Trait`s.
|
.principal_def_id()
|
||||||
// For example, `fn foo() -> str` needs to be filtered out.
|
.map_or(true, |def_id| object_safety_violations(self.tcx, def_id).is_empty())
|
||||||
_ => return false,
|
|
||||||
}
|
}
|
||||||
|
// We only want to suggest `impl Trait` to `dyn Trait`s.
|
||||||
|
// For example, `fn foo() -> str` needs to be filtered out.
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
|
||||||
let ret_ty = if let hir::FunctionRetTy::Return(ret_ty) = sig.decl.output {
|
let ret_ty = if let hir::FunctionRetTy::Return(ret_ty) = sig.decl.output {
|
||||||
ret_ty
|
ret_ty
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use `TypeVisitor` instead of the output type directly to find the span of `ty` for
|
// Use `TypeVisitor` instead of the output type directly to find the span of `ty` for
|
||||||
// cases like `fn foo() -> (dyn Trait, i32) {}`.
|
// cases like `fn foo() -> (dyn Trait, i32) {}`.
|
||||||
// Recursively look for `TraitObject` types and if there's only one, use that span to
|
// Recursively look for `TraitObject` types and if there's only one, use that span to
|
||||||
// suggest `impl Trait`.
|
// suggest `impl Trait`.
|
||||||
|
|
||||||
// Visit to make sure there's a single `return` type 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.
|
// otherwise suggest using `Box<dyn Trait>` or an enum.
|
||||||
let mut visitor = ReturnsVisitor(vec![]);
|
let mut visitor = ReturnsVisitor(vec![]);
|
||||||
visitor.visit_body(&body);
|
visitor.visit_body(&body);
|
||||||
|
|
||||||
let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
|
let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
|
||||||
|
|
||||||
let mut all_returns_conform_to_trait = true;
|
let mut all_returns_conform_to_trait = true;
|
||||||
let mut all_returns_have_same_type = true;
|
let mut all_returns_have_same_type = true;
|
||||||
let mut last_ty = None;
|
let mut last_ty = None;
|
||||||
if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) {
|
if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) {
|
||||||
let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id);
|
let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id);
|
||||||
let param_env = ty::ParamEnv::empty();
|
let param_env = ty::ParamEnv::empty();
|
||||||
if let ty::Dynamic(predicates, _) = &ty_ret_ty.kind {
|
if let ty::Dynamic(predicates, _) = &ty_ret_ty.kind {
|
||||||
for expr in &visitor.0 {
|
for expr in &visitor.0 {
|
||||||
if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
|
if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
|
||||||
all_returns_have_same_type &=
|
all_returns_have_same_type &=
|
||||||
Some(returned_ty) == last_ty || last_ty.is_none();
|
Some(returned_ty) == last_ty || last_ty.is_none();
|
||||||
last_ty = Some(returned_ty);
|
last_ty = Some(returned_ty);
|
||||||
for predicate in predicates.iter() {
|
for predicate in predicates.iter() {
|
||||||
let pred = predicate.with_self_ty(self.tcx, returned_ty);
|
let pred = predicate.with_self_ty(self.tcx, returned_ty);
|
||||||
let obl = Obligation::new(cause.clone(), param_env, pred);
|
let obl = Obligation::new(cause.clone(), param_env, pred);
|
||||||
all_returns_conform_to_trait &= self.predicate_may_hold(&obl);
|
all_returns_conform_to_trait &= self.predicate_may_hold(&obl);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// We still want to verify whether all the return types conform to each other.
|
|
||||||
for expr in &visitor.0 {
|
|
||||||
let returned_ty = tables.node_type_opt(expr.hir_id);
|
|
||||||
all_returns_have_same_type &= last_ty == returned_ty || last_ty.is_none();
|
|
||||||
last_ty = returned_ty;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// We still want to verify whether all the return types conform to each other.
|
||||||
|
for expr in &visitor.0 {
|
||||||
|
let returned_ty = tables.node_type_opt(expr.hir_id);
|
||||||
|
all_returns_have_same_type &= last_ty == returned_ty || last_ty.is_none();
|
||||||
|
last_ty = returned_ty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (snippet, last_ty) =
|
let (snippet, last_ty) =
|
||||||
if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = (
|
if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = (
|
||||||
// Verify that we're dealing with a return `dyn Trait`
|
// Verify that we're dealing with a return `dyn Trait`
|
||||||
ret_ty.span.overlaps(span),
|
ret_ty.span.overlaps(span),
|
||||||
&ret_ty.kind,
|
&ret_ty.kind,
|
||||||
self.tcx.sess.source_map().span_to_snippet(ret_ty.span),
|
self.tcx.sess.source_map().span_to_snippet(ret_ty.span),
|
||||||
// If any of the return types does not conform to the trait, then we can't
|
// If any of the return types does not conform to the trait, then we can't
|
||||||
// suggest `impl Trait` nor trait objects, it is a type mismatch error.
|
// suggest `impl Trait` nor trait objects, it is a type mismatch error.
|
||||||
all_returns_conform_to_trait,
|
all_returns_conform_to_trait,
|
||||||
last_ty,
|
last_ty,
|
||||||
) {
|
) {
|
||||||
(snippet, last_ty)
|
(snippet, last_ty)
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
err.code(error_code!(E0746));
|
|
||||||
err.set_primary_message("return type cannot have an unboxed trait object");
|
|
||||||
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 trait_obj = if has_dyn { &snippet[4..] } else { &snippet[..] };
|
|
||||||
if all_returns_have_same_type {
|
|
||||||
// Suggest `-> impl Trait`.
|
|
||||||
err.span_suggestion(
|
|
||||||
ret_ty.span,
|
|
||||||
&format!(
|
|
||||||
"return `impl {1}` instead, as all return paths are of type `{}`, \
|
|
||||||
which implements `{1}`",
|
|
||||||
last_ty, trait_obj,
|
|
||||||
),
|
|
||||||
format!("impl {}", trait_obj),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
err.note(impl_trait_msg);
|
|
||||||
} else {
|
} else {
|
||||||
if is_object_safe {
|
return false;
|
||||||
// Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
|
};
|
||||||
// Get all the return values and collect their span and suggestion.
|
err.code(error_code!(E0746));
|
||||||
let mut suggestions = visitor
|
err.set_primary_message("return type cannot have an unboxed trait object");
|
||||||
.0
|
err.children.clear();
|
||||||
.iter()
|
let impl_trait_msg = "for information on `impl Trait`, see \
|
||||||
.map(|expr| {
|
<https://doc.rust-lang.org/book/ch10-02-traits.html\
|
||||||
(
|
#returning-types-that-implement-traits>";
|
||||||
expr.span,
|
let trait_obj_msg = "for information on trait objects, see \
|
||||||
format!(
|
<https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
|
||||||
"Box::new({})",
|
#using-trait-objects-that-allow-for-values-of-different-types>";
|
||||||
self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap()
|
let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
|
||||||
),
|
let trait_obj = if has_dyn { &snippet[4..] } else { &snippet[..] };
|
||||||
)
|
if all_returns_have_same_type {
|
||||||
})
|
// Suggest `-> impl Trait`.
|
||||||
.collect::<Vec<_>>();
|
err.span_suggestion(
|
||||||
// Add the suggestion for the return type.
|
ret_ty.span,
|
||||||
suggestions.push((
|
&format!(
|
||||||
ret_ty.span,
|
"return `impl {1}` instead, as all return paths are of type `{}`, \
|
||||||
format!("Box<{}{}>", if has_dyn { "" } else { "dyn " }, snippet),
|
which implements `{1}`",
|
||||||
));
|
last_ty, trait_obj,
|
||||||
err.multipart_suggestion(
|
),
|
||||||
|
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)`.
|
||||||
|
// Get all the return values and collect their span and suggestion.
|
||||||
|
let mut suggestions = visitor
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|expr| {
|
||||||
|
(
|
||||||
|
expr.span,
|
||||||
|
format!(
|
||||||
|
"Box::new({})",
|
||||||
|
self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
// Add the suggestion for the return type.
|
||||||
|
suggestions.push((
|
||||||
|
ret_ty.span,
|
||||||
|
format!("Box<{}{}>", if has_dyn { "" } else { "dyn " }, snippet),
|
||||||
|
));
|
||||||
|
err.multipart_suggestion(
|
||||||
"return a trait object instead",
|
"return a trait object instead",
|
||||||
suggestions,
|
suggestions,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
err.note(&format!(
|
|
||||||
"if trait `{}` was object safe, you could return a trait object",
|
|
||||||
trait_obj,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
err.note(&format!(
|
err.note(&format!(
|
||||||
"if all the returned values were of the same type you could use \
|
"if trait `{}` was object safe, you could return a trait object",
|
||||||
`impl {}` as the return type",
|
|
||||||
trait_obj,
|
trait_obj,
|
||||||
));
|
));
|
||||||
err.note(impl_trait_msg);
|
|
||||||
err.note(trait_obj_msg);
|
|
||||||
err.note("you can create a new `enum` with a variant for each returned type");
|
|
||||||
}
|
}
|
||||||
return true;
|
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");
|
||||||
}
|
}
|
||||||
false
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn point_at_returns_when_relevant(
|
crate fn point_at_returns_when_relevant(
|
||||||
|
@ -1686,6 +1688,8 @@ pub fn suggest_constraining_type_param(
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collect all the returned expressions within the input expression.
|
||||||
|
/// Used to point at the return spans when we want to suggest some change to them.
|
||||||
struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
|
struct ReturnsVisitor<'v>(Vec<&'v hir::Expr<'v>>);
|
||||||
|
|
||||||
impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
|
impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
|
||||||
|
|
|
@ -1171,7 +1171,7 @@ impl<'tcx> ObligationCause<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ObligationCauseCode<'tcx> {
|
impl ObligationCauseCode<'_> {
|
||||||
// Return the base obligation, ignoring derived obligations.
|
// Return the base obligation, ignoring derived obligations.
|
||||||
pub fn peel_derives(&self) -> &Self {
|
pub fn peel_derives(&self) -> &Self {
|
||||||
let mut base_cause = self;
|
let mut base_cause = self;
|
||||||
|
|
|
@ -12,8 +12,8 @@ impl T for S {
|
||||||
fn bar(&self) {}
|
fn bar(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Having the trait `T` as return type is invalid because bare traits do not
|
// Having the trait `T` as return type is invalid because
|
||||||
// have a statically known size:
|
// bare trait objects do not have a statically known size:
|
||||||
fn foo() -> dyn T {
|
fn foo() -> dyn T {
|
||||||
S(42)
|
S(42)
|
||||||
}
|
}
|
||||||
|
@ -32,15 +32,15 @@ If there is a single type involved, you can use [`impl Trait`]:
|
||||||
# fn bar(&self) {}
|
# fn bar(&self) {}
|
||||||
# }
|
# }
|
||||||
// The compiler will select `S(usize)` as the materialized return type of this
|
// The compiler will select `S(usize)` as the materialized return type of this
|
||||||
// function, but callers will only be able to access associated items from `T`.
|
// function, but callers will only know that the return type implements `T`.
|
||||||
fn foo() -> impl T {
|
fn foo() -> impl T {
|
||||||
S(42)
|
S(42)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If there are multiple types involved, the only way you care to interact with
|
If there are multiple types involved, the only way you care to interact with
|
||||||
them is through the trait's interface and having to rely on dynamic dispatch is
|
them is through the trait's interface, and having to rely on dynamic dispatch
|
||||||
acceptable, then you can use [trait objects] with `Box`, or other container
|
is acceptable, then you can use [trait objects] with `Box`, or other container
|
||||||
types like `Rc` or `Arc`:
|
types like `Rc` or `Arc`:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -68,7 +68,7 @@ use rustc_error_codes::*;
|
||||||
use rustc_errors::{struct_span_err, DiagnosticBuilder};
|
use rustc_errors::{struct_span_err, DiagnosticBuilder};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_span;
|
use rustc_span::{self, Span};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
@ -1352,41 +1352,50 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let (Some(sp), Some(return_sp)) = (fcx.ret_coercion_span.borrow().as_ref(), return_sp) {
|
if let (Some(sp), Some(return_sp)) = (fcx.ret_coercion_span.borrow().as_ref(), return_sp) {
|
||||||
err.span_label(return_sp, "expected because this return type...");
|
self.add_impl_trait_explanation(&mut err, fcx, expected, *sp, return_sp);
|
||||||
err.span_label( *sp, format!(
|
|
||||||
"...is found to be `{}` here",
|
|
||||||
fcx.resolve_vars_with_obligations(expected),
|
|
||||||
));
|
|
||||||
err.note("to return `impl Trait`, all returned values must be of the same type");
|
|
||||||
let snippet = fcx
|
|
||||||
.tcx
|
|
||||||
.sess
|
|
||||||
.source_map()
|
|
||||||
.span_to_snippet(return_sp)
|
|
||||||
.unwrap_or_else(|_| "dyn Trait".to_string());
|
|
||||||
let mut snippet_iter = snippet.split_whitespace();
|
|
||||||
let has_impl = snippet_iter.next().map_or(false, |s| s == "impl");
|
|
||||||
if has_impl {
|
|
||||||
err.help(&format!(
|
|
||||||
"you can instead return a trait object using `Box<dyn {}>`",
|
|
||||||
&snippet[5..]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
err.help("alternatively, create a new `enum` with a variant for each returned type");
|
|
||||||
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>";
|
|
||||||
err.note(impl_trait_msg);
|
|
||||||
if has_impl {
|
|
||||||
err.note(trait_obj_msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_impl_trait_explanation<'a>(
|
||||||
|
&self,
|
||||||
|
err: &mut DiagnosticBuilder<'a>,
|
||||||
|
fcx: &FnCtxt<'a, 'tcx>,
|
||||||
|
expected: Ty<'tcx>,
|
||||||
|
sp: Span,
|
||||||
|
return_sp: Span,
|
||||||
|
) {
|
||||||
|
err.span_label(return_sp, "expected because this return type...");
|
||||||
|
err.span_label(
|
||||||
|
sp,
|
||||||
|
format!("...is found to be `{}` here", fcx.resolve_vars_with_obligations(expected)),
|
||||||
|
);
|
||||||
|
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>";
|
||||||
|
err.note("to return `impl Trait`, all returned values must be of the same type");
|
||||||
|
err.note(impl_trait_msg);
|
||||||
|
let snippet = fcx
|
||||||
|
.tcx
|
||||||
|
.sess
|
||||||
|
.source_map()
|
||||||
|
.span_to_snippet(return_sp)
|
||||||
|
.unwrap_or_else(|_| "dyn Trait".to_string());
|
||||||
|
let mut snippet_iter = snippet.split_whitespace();
|
||||||
|
let has_impl = snippet_iter.next().map_or(false, |s| s == "impl");
|
||||||
|
if has_impl {
|
||||||
|
err.help(&format!(
|
||||||
|
"you can instead return a trait object using `Box<dyn {}>`",
|
||||||
|
&snippet[5..]
|
||||||
|
));
|
||||||
|
err.note(trait_obj_msg);
|
||||||
|
}
|
||||||
|
err.help("alternatively, create a new `enum` with a variant for each returned type");
|
||||||
|
}
|
||||||
|
|
||||||
fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
|
fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
|
||||||
if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id) {
|
if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id) {
|
||||||
if let hir::FunctionRetTy::Return(ty) = fn_decl.output {
|
if let hir::FunctionRetTy::Return(ty) = fn_decl.output {
|
||||||
|
|
|
@ -82,11 +82,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: if trait `Trait` was object safe, you could return a trait object
|
= 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>
|
||||||
= note: if all the returned values were of the same type you could use `impl Trait` as the return 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: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
= 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>
|
|
||||||
= note: you can create a new `enum` with a variant for each returned type
|
= note: you can create a new `enum` with a variant for each returned type
|
||||||
|
help: return a trait object instead
|
||||||
|
|
|
||||||
|
LL | fn bal() -> Box<dyn Trait> {
|
||||||
|
LL | if true {
|
||||||
|
LL | return Box::new(Struct);
|
||||||
|
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:27:13
|
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:27:13
|
||||||
|
|
|
@ -11,10 +11,10 @@ LL | 0_u32
|
||||||
| ^^^^^ expected `i32`, found `u32`
|
| ^^^^^ expected `i32`, found `u32`
|
||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= help: you can instead return a trait object using `Box<dyn Foo>`
|
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
|
= help: you can instead return a trait object using `Box<dyn Foo>`
|
||||||
= 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>
|
= 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: alternatively, create a new `enum` with a variant for each returned type
|
||||||
|
|
||||||
error[E0277]: cannot add `impl Foo` to `u32`
|
error[E0277]: cannot add `impl Foo` to `u32`
|
||||||
--> $DIR/equality.rs:24:11
|
--> $DIR/equality.rs:24:11
|
||||||
|
|
|
@ -11,10 +11,10 @@ LL | 1u32
|
||||||
| ^^^^ expected `i32`, found `u32`
|
| ^^^^ expected `i32`, found `u32`
|
||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
|
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
|
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
|
||||||
= 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>
|
= 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: alternatively, create a new `enum` with a variant for each returned type
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16
|
||||||
|
@ -29,10 +29,10 @@ LL | return 1u32;
|
||||||
| ^^^^ expected `i32`, found `u32`
|
| ^^^^ expected `i32`, found `u32`
|
||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
|
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
|
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
|
||||||
= 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>
|
= 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: alternatively, create a new `enum` with a variant for each returned type
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9
|
||||||
|
@ -47,10 +47,10 @@ LL | 1u32
|
||||||
| ^^^^ expected `i32`, found `u32`
|
| ^^^^ expected `i32`, found `u32`
|
||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
|
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
|
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
|
||||||
= 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>
|
= 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: alternatively, create a new `enum` with a variant for each returned type
|
||||||
|
|
||||||
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:31:9
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9
|
||||||
|
@ -77,10 +77,10 @@ LL | _ => 1u32,
|
||||||
| ^^^^ expected `i32`, found `u32`
|
| ^^^^ expected `i32`, found `u32`
|
||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
|
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
|
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
|
||||||
= 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>
|
= 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: alternatively, create a new `enum` with a variant for each returned type
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5
|
||||||
|
@ -97,10 +97,10 @@ LL | | }
|
||||||
| |_____^ expected `i32`, found `u32`
|
| |_____^ expected `i32`, found `u32`
|
||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
|
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
|
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
|
||||||
= 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>
|
= 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: alternatively, create a new `enum` with a variant for each returned type
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13
|
||||||
|
@ -115,10 +115,10 @@ LL | 1u32
|
||||||
| ^^^^ expected `i32`, found `u32`
|
| ^^^^ expected `i32`, found `u32`
|
||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
|
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
|
= help: you can instead return a trait object using `Box<dyn std::fmt::Display>`
|
||||||
= 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>
|
= 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: alternatively, create a new `enum` with a variant for each returned type
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue