Rollup merge of #119148 - estebank:bare-traits, r=davidtwco
Tweak suggestions for bare trait used as a type ``` error[E0782]: trait objects must include the `dyn` keyword --> $DIR/not-on-bare-trait-2021.rs:11:11 | LL | fn bar(x: Foo) -> Foo { | ^^^ | help: use a generic type parameter, constrained by the trait `Foo` | LL | fn bar<T: Foo>(x: T) -> Foo { | ++++++++ ~ help: you can also use `impl Foo`, but users won't be able to specify the type paramer when calling the `fn`, having to rely exclusively on type inference | LL | fn bar(x: impl Foo) -> Foo { | ++++ help: alternatively, use a trait object to accept any type that implements `Foo`, accessing its methods at runtime using dynamic dispatch | LL | fn bar(x: &dyn Foo) -> Foo { | ++++ error[E0782]: trait objects must include the `dyn` keyword --> $DIR/not-on-bare-trait-2021.rs:11:19 | LL | fn bar(x: Foo) -> Foo { | ^^^ | help: use `impl Foo` to return an opaque type, as long as you return a single underlying type | LL | fn bar(x: Foo) -> impl Foo { | ++++ help: alternatively, you can return an owned trait object | LL | fn bar(x: Foo) -> Box<dyn Foo> { | +++++++ + ``` Fix #119525: ``` error[E0038]: the trait `Ord` cannot be made into an object --> $DIR/bare-trait-dont-suggest-dyn.rs:3:33 | LL | fn ord_prefer_dot(s: String) -> Ord { | ^^^ `Ord` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: the trait cannot be made into an object because it uses `Self` as a type parameter ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: the trait cannot be made into an object because it uses `Self` as a type parameter help: consider using an opaque type instead | LL | fn ord_prefer_dot(s: String) -> impl Ord { | ++++ ```
This commit is contained in:
commit
f41ad1bc9c
22 changed files with 412 additions and 75 deletions
|
@ -605,7 +605,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
let violations =
|
let violations =
|
||||||
object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
|
object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
|
||||||
if !violations.is_empty() {
|
if !violations.is_empty() {
|
||||||
report_object_safety_error(tcx, *span, trait_def_id, &violations).emit();
|
report_object_safety_error(tcx, *span, None, trait_def_id, &violations).emit();
|
||||||
object_safety_violations = true;
|
object_safety_violations = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use rustc_ast::TraitObjectSyntax;
|
use rustc_ast::TraitObjectSyntax;
|
||||||
use rustc_errors::{Diagnostic, StashKey};
|
use rustc_errors::{Diagnostic, StashKey};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
|
use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
|
||||||
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
|
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
|
||||||
|
|
||||||
use super::AstConv;
|
use super::AstConv;
|
||||||
|
@ -32,32 +34,146 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
}
|
}
|
||||||
let of_trait_span = of_trait_ref.path.span;
|
let of_trait_span = of_trait_ref.path.span;
|
||||||
// make sure that we are not calling unwrap to abort during the compilation
|
// make sure that we are not calling unwrap to abort during the compilation
|
||||||
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
|
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
// check if the trait has generics, to make a correct suggestion
|
|
||||||
let param_name = generics.params.next_type_param_name(None);
|
|
||||||
|
|
||||||
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
|
let Ok(impl_trait_name) = self.tcx().sess.source_map().span_to_snippet(self_ty.span)
|
||||||
(span, format!(", {param_name}: {impl_trait_name}"))
|
else {
|
||||||
} else {
|
return;
|
||||||
(generics.span, format!("<{param_name}: {impl_trait_name}>"))
|
};
|
||||||
|
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name);
|
||||||
|
if sugg.is_empty() {
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
diag.multipart_suggestion(
|
diag.multipart_suggestion(
|
||||||
format!(
|
format!(
|
||||||
"alternatively use a blanket \
|
"alternatively use a blanket implementation to implement `{of_trait_name}` for \
|
||||||
implementation to implement `{of_trait_name}` for \
|
|
||||||
all types that also implement `{impl_trait_name}`"
|
all types that also implement `{impl_trait_name}`"
|
||||||
),
|
),
|
||||||
vec![(self_ty.span, param_name), add_generic_sugg],
|
sugg,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_generic_param_suggestion(
|
||||||
|
&self,
|
||||||
|
generics: &hir::Generics<'_>,
|
||||||
|
self_ty_span: Span,
|
||||||
|
impl_trait_name: &str,
|
||||||
|
) -> Vec<(Span, String)> {
|
||||||
|
// check if the trait has generics, to make a correct suggestion
|
||||||
|
let param_name = generics.params.next_type_param_name(None);
|
||||||
|
|
||||||
|
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
|
||||||
|
(span, format!(", {param_name}: {impl_trait_name}"))
|
||||||
|
} else {
|
||||||
|
(generics.span, format!("<{param_name}: {impl_trait_name}>"))
|
||||||
|
};
|
||||||
|
vec![(self_ty_span, param_name), add_generic_sugg]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make sure that we are in the condition to suggest `impl Trait`.
|
||||||
|
fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) -> bool {
|
||||||
|
let tcx = self.tcx();
|
||||||
|
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
|
||||||
|
let (hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. })
|
||||||
|
| hir::Node::TraitItem(hir::TraitItem {
|
||||||
|
kind: hir::TraitItemKind::Fn(sig, _),
|
||||||
|
generics,
|
||||||
|
..
|
||||||
|
})) = tcx.hir_node_by_def_id(parent_id)
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
|
||||||
|
let is_object_safe = match self_ty.kind {
|
||||||
|
hir::TyKind::TraitObject(objects, ..) => {
|
||||||
|
objects.iter().all(|o| match o.trait_ref.path.res {
|
||||||
|
Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id),
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if let hir::FnRetTy::Return(ty) = sig.decl.output
|
||||||
|
&& ty.hir_id == self_ty.hir_id
|
||||||
|
{
|
||||||
|
let pre = if !is_object_safe {
|
||||||
|
format!("`{trait_name}` is not object safe, ")
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
let msg = format!(
|
||||||
|
"{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
|
||||||
|
single underlying type",
|
||||||
|
);
|
||||||
|
diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);
|
||||||
|
if is_object_safe {
|
||||||
|
diag.multipart_suggestion_verbose(
|
||||||
|
"alternatively, you can return an owned trait object",
|
||||||
|
vec![
|
||||||
|
(ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
|
||||||
|
(ty.span.shrink_to_hi(), ">".to_string()),
|
||||||
|
],
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// We'll emit the object safety error already, with a structured suggestion.
|
||||||
|
diag.downgrade_to_delayed_bug();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for ty in sig.decl.inputs {
|
||||||
|
if ty.hir_id != self_ty.hir_id {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name);
|
||||||
|
if !sugg.is_empty() {
|
||||||
|
diag.multipart_suggestion_verbose(
|
||||||
|
format!("use a new generic type parameter, constrained by `{trait_name}`"),
|
||||||
|
sugg,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
diag.multipart_suggestion_verbose(
|
||||||
|
"you can also use an opaque type, but users won't be able to specify the type \
|
||||||
|
parameter when calling the `fn`, having to rely exclusively on type inference",
|
||||||
|
impl_sugg,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if !is_object_safe {
|
||||||
|
diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
|
||||||
|
// We'll emit the object safety error already, with a structured suggestion.
|
||||||
|
diag.downgrade_to_delayed_bug();
|
||||||
|
} else {
|
||||||
|
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
|
||||||
|
// There are more than one trait bound, we need surrounding parentheses.
|
||||||
|
vec![
|
||||||
|
(self_ty.span.shrink_to_lo(), "&(dyn ".to_string()),
|
||||||
|
(self_ty.span.shrink_to_hi(), ")".to_string()),
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
vec![(self_ty.span.shrink_to_lo(), "&dyn ".to_string())]
|
||||||
|
};
|
||||||
|
diag.multipart_suggestion_verbose(
|
||||||
|
format!(
|
||||||
|
"alternatively, use a trait object to accept any type that implements \
|
||||||
|
`{trait_name}`, accessing its methods at runtime using dynamic dispatch",
|
||||||
|
),
|
||||||
|
sugg,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
|
pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
|
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
|
||||||
|
@ -98,7 +214,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
let label = "add `dyn` keyword before this trait";
|
let label = "add `dyn` keyword before this trait";
|
||||||
let mut diag =
|
let mut diag =
|
||||||
rustc_errors::struct_span_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg);
|
rustc_errors::struct_span_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg);
|
||||||
if self_ty.span.can_be_used_for_suggestions() {
|
if self_ty.span.can_be_used_for_suggestions()
|
||||||
|
&& !self.maybe_lint_impl_trait(self_ty, &mut diag)
|
||||||
|
{
|
||||||
diag.multipart_suggestion_verbose(
|
diag.multipart_suggestion_verbose(
|
||||||
label,
|
label,
|
||||||
sugg,
|
sugg,
|
||||||
|
@ -116,11 +234,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
self_ty.span,
|
self_ty.span,
|
||||||
msg,
|
msg,
|
||||||
|lint| {
|
|lint| {
|
||||||
lint.multipart_suggestion_verbose(
|
if self_ty.span.can_be_used_for_suggestions()
|
||||||
"use `dyn`",
|
&& !self.maybe_lint_impl_trait(self_ty, lint)
|
||||||
sugg,
|
{
|
||||||
Applicability::MachineApplicable,
|
lint.multipart_suggestion_verbose(
|
||||||
);
|
"use `dyn`",
|
||||||
|
sugg,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
self.maybe_lint_blanket_trait_impl(self_ty, lint);
|
self.maybe_lint_blanket_trait_impl(self_ty, lint);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -140,6 +140,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
let reported = report_object_safety_error(
|
let reported = report_object_safety_error(
|
||||||
tcx,
|
tcx,
|
||||||
span,
|
span,
|
||||||
|
Some(hir_id),
|
||||||
item.trait_ref().def_id(),
|
item.trait_ref().def_id(),
|
||||||
&object_safety_violations,
|
&object_safety_violations,
|
||||||
)
|
)
|
||||||
|
|
|
@ -73,7 +73,8 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||||
let inputs_fn = fn_sig.inputs().iter().copied();
|
let inputs_fn = fn_sig.inputs().iter().copied();
|
||||||
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
|
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
|
||||||
// Check the pattern.
|
// Check the pattern.
|
||||||
let ty_span = try { inputs_hir?.get(idx)?.span };
|
let ty: Option<&hir::Ty<'_>> = try { inputs_hir?.get(idx)? };
|
||||||
|
let ty_span = ty.map(|ty| ty.span);
|
||||||
fcx.check_pat_top(param.pat, param_ty, ty_span, None, None);
|
fcx.check_pat_top(param.pat, param_ty, ty_span, None, None);
|
||||||
|
|
||||||
// Check that argument is Sized.
|
// Check that argument is Sized.
|
||||||
|
@ -81,14 +82,14 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||||
fcx.require_type_is_sized(
|
fcx.require_type_is_sized(
|
||||||
param_ty,
|
param_ty,
|
||||||
param.pat.span,
|
param.pat.span,
|
||||||
// ty_span == binding_span iff this is a closure parameter with no type ascription,
|
// ty.span == binding_span iff this is a closure parameter with no type ascription,
|
||||||
// or if it's an implicit `self` parameter
|
// or if it's an implicit `self` parameter
|
||||||
traits::SizedArgumentType(
|
traits::SizedArgumentType(
|
||||||
if ty_span == Some(param.span) && tcx.is_closure_or_coroutine(fn_def_id.into())
|
if ty_span == Some(param.span) && tcx.is_closure_or_coroutine(fn_def_id.into())
|
||||||
{
|
{
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
ty_span
|
ty.map(|ty| ty.hir_id)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -60,7 +60,7 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
|
||||||
// parameters are special cases of patterns, but we want to handle them as
|
// parameters are special cases of patterns, but we want to handle them as
|
||||||
// *distinct* cases. so track when we are hitting a pattern *within* an fn
|
// *distinct* cases. so track when we are hitting a pattern *within* an fn
|
||||||
// parameter.
|
// parameter.
|
||||||
outermost_fn_param_pat: Option<Span>,
|
outermost_fn_param_pat: Option<(Span, hir::HirId)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
|
||||||
|
@ -131,7 +131,8 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
|
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
|
||||||
let old_outermost_fn_param_pat = self.outermost_fn_param_pat.replace(param.ty_span);
|
let old_outermost_fn_param_pat =
|
||||||
|
self.outermost_fn_param_pat.replace((param.ty_span, param.hir_id));
|
||||||
intravisit::walk_param(self, param);
|
intravisit::walk_param(self, param);
|
||||||
self.outermost_fn_param_pat = old_outermost_fn_param_pat;
|
self.outermost_fn_param_pat = old_outermost_fn_param_pat;
|
||||||
}
|
}
|
||||||
|
@ -141,7 +142,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
|
||||||
if let PatKind::Binding(_, _, ident, _) = p.kind {
|
if let PatKind::Binding(_, _, ident, _) = p.kind {
|
||||||
let var_ty = self.assign(p.span, p.hir_id, None);
|
let var_ty = self.assign(p.span, p.hir_id, None);
|
||||||
|
|
||||||
if let Some(ty_span) = self.outermost_fn_param_pat {
|
if let Some((ty_span, hir_id)) = self.outermost_fn_param_pat {
|
||||||
if !self.fcx.tcx.features().unsized_fn_params {
|
if !self.fcx.tcx.features().unsized_fn_params {
|
||||||
self.fcx.require_type_is_sized(
|
self.fcx.require_type_is_sized(
|
||||||
var_ty,
|
var_ty,
|
||||||
|
@ -154,7 +155,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(ty_span)
|
Some(hir_id)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,9 +2,10 @@ use super::ObjectSafetyViolation;
|
||||||
|
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_errors::{struct_span_err, DiagnosticBuilder, MultiSpan};
|
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, MultiSpan};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
|
use rustc_hir::intravisit::Map;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -42,6 +43,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
pub fn report_object_safety_error<'tcx>(
|
pub fn report_object_safety_error<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
hir_id: Option<hir::HirId>,
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
violations: &[ObjectSafetyViolation],
|
violations: &[ObjectSafetyViolation],
|
||||||
) -> DiagnosticBuilder<'tcx> {
|
) -> DiagnosticBuilder<'tcx> {
|
||||||
|
@ -59,6 +61,24 @@ pub fn report_object_safety_error<'tcx>(
|
||||||
);
|
);
|
||||||
err.span_label(span, format!("`{trait_str}` cannot be made into an object"));
|
err.span_label(span, format!("`{trait_str}` cannot be made into an object"));
|
||||||
|
|
||||||
|
if let Some(hir_id) = hir_id
|
||||||
|
&& let Some(hir::Node::Ty(ty)) = tcx.hir().find(hir_id)
|
||||||
|
&& let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind
|
||||||
|
{
|
||||||
|
let mut hir_id = hir_id;
|
||||||
|
while let hir::Node::Ty(ty) = tcx.hir().get_parent(hir_id) {
|
||||||
|
hir_id = ty.hir_id;
|
||||||
|
}
|
||||||
|
if tcx.hir().get_parent(hir_id).fn_sig().is_some() {
|
||||||
|
// Do not suggest `impl Trait` when dealing with things like super-traits.
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
ty.span.until(trait_ref.span),
|
||||||
|
"consider using an opaque type instead",
|
||||||
|
"impl ",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
let mut reported_violations = FxIndexSet::default();
|
let mut reported_violations = FxIndexSet::default();
|
||||||
let mut multi_span = vec![];
|
let mut multi_span = vec![];
|
||||||
let mut messages = vec![];
|
let mut messages = vec![];
|
||||||
|
|
|
@ -289,7 +289,7 @@ pub enum ObligationCauseCode<'tcx> {
|
||||||
/// Type of each variable must be `Sized`.
|
/// Type of each variable must be `Sized`.
|
||||||
VariableType(hir::HirId),
|
VariableType(hir::HirId),
|
||||||
/// Argument type must be `Sized`.
|
/// Argument type must be `Sized`.
|
||||||
SizedArgumentType(Option<Span>),
|
SizedArgumentType(Option<hir::HirId>),
|
||||||
/// Return type must be `Sized`.
|
/// Return type must be `Sized`.
|
||||||
SizedReturnType,
|
SizedReturnType,
|
||||||
/// Yield type must be `Sized`.
|
/// Yield type must be `Sized`.
|
||||||
|
|
|
@ -19,11 +19,10 @@ use rustc_errors::{
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::{Map, Visitor};
|
||||||
use rustc_hir::is_range_literal;
|
use rustc_hir::is_range_literal;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Node};
|
use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node};
|
||||||
use rustc_hir::{Expr, HirId};
|
|
||||||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
|
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
|
||||||
|
@ -3200,35 +3199,80 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
err.help("unsized locals are gated as an unstable feature");
|
err.help("unsized locals are gated as an unstable feature");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObligationCauseCode::SizedArgumentType(ty_span) => {
|
ObligationCauseCode::SizedArgumentType(hir_id) => {
|
||||||
if let Some(span) = ty_span {
|
let mut ty = None;
|
||||||
if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
|
let borrowed_msg = "function arguments must have a statically known size, borrowed \
|
||||||
&& let ty::ClauseKind::Trait(trait_pred) = clause
|
types always have a known size";
|
||||||
&& let ty::Dynamic(..) = trait_pred.self_ty().kind()
|
if let Some(hir_id) = hir_id
|
||||||
{
|
&& let Some(hir::Node::Param(param)) = self.tcx.hir().find(hir_id)
|
||||||
let span = if let Ok(snippet) =
|
&& let Some(item) = self.tcx.hir().find_parent(hir_id)
|
||||||
self.tcx.sess.source_map().span_to_snippet(span)
|
&& let Some(decl) = item.fn_decl()
|
||||||
&& snippet.starts_with("dyn ")
|
&& let Some(t) = decl.inputs.iter().find(|t| param.ty_span.contains(t.span))
|
||||||
{
|
{
|
||||||
let pos = snippet.len() - snippet[3..].trim_start().len();
|
// We use `contains` because the type might be surrounded by parentheses,
|
||||||
span.with_hi(span.lo() + BytePos(pos as u32))
|
// which makes `ty_span` and `t.span` disagree with each other, but one
|
||||||
} else {
|
// fully contains the other: `foo: (dyn Foo + Bar)`
|
||||||
span.shrink_to_lo()
|
// ^-------------^
|
||||||
};
|
// ||
|
||||||
err.span_suggestion_verbose(
|
// |t.span
|
||||||
span,
|
// param._ty_span
|
||||||
"you can use `impl Trait` as the argument type",
|
ty = Some(t);
|
||||||
"impl ".to_string(),
|
} else if let Some(hir_id) = hir_id
|
||||||
Applicability::MaybeIncorrect,
|
&& let Some(hir::Node::Ty(t)) = self.tcx.hir().find(hir_id)
|
||||||
);
|
{
|
||||||
|
ty = Some(t);
|
||||||
|
}
|
||||||
|
if let Some(ty) = ty {
|
||||||
|
match ty.kind {
|
||||||
|
hir::TyKind::TraitObject(traits, _, _) => {
|
||||||
|
let (span, kw) = match traits {
|
||||||
|
[first, ..] if first.span.lo() == ty.span.lo() => {
|
||||||
|
// Missing `dyn` in front of trait object.
|
||||||
|
(ty.span.shrink_to_lo(), "dyn ")
|
||||||
|
}
|
||||||
|
[first, ..] => (ty.span.until(first.span), ""),
|
||||||
|
[] => span_bug!(ty.span, "trait object with no traits: {ty:?}"),
|
||||||
|
};
|
||||||
|
let needs_parens = traits.len() != 1;
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
span,
|
||||||
|
"you can use `impl Trait` as the argument type",
|
||||||
|
"impl ".to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
let sugg = if !needs_parens {
|
||||||
|
vec![(span.shrink_to_lo(), format!("&{kw}"))]
|
||||||
|
} else {
|
||||||
|
vec![
|
||||||
|
(span.shrink_to_lo(), format!("&({kw}")),
|
||||||
|
(ty.span.shrink_to_hi(), ")".to_string()),
|
||||||
|
]
|
||||||
|
};
|
||||||
|
err.multipart_suggestion_verbose(
|
||||||
|
borrowed_msg,
|
||||||
|
sugg,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
hir::TyKind::Slice(_ty) => {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
ty.span.shrink_to_lo(),
|
||||||
|
"function arguments must have a statically known size, borrowed \
|
||||||
|
slices always have a known size",
|
||||||
|
"&",
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
hir::TyKind::Path(_) => {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
ty.span.shrink_to_lo(),
|
||||||
|
borrowed_msg,
|
||||||
|
"&",
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
err.span_suggestion_verbose(
|
|
||||||
span.shrink_to_lo(),
|
|
||||||
"function arguments must have a statically known size, borrowed types \
|
|
||||||
always have a known size",
|
|
||||||
"&",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
err.note("all function arguments must have a statically known size");
|
err.note("all function arguments must have a statically known size");
|
||||||
}
|
}
|
||||||
|
|
|
@ -816,7 +816,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
|
|
||||||
ty::PredicateKind::ObjectSafe(trait_def_id) => {
|
ty::PredicateKind::ObjectSafe(trait_def_id) => {
|
||||||
let violations = self.tcx.object_safety_violations(trait_def_id);
|
let violations = self.tcx.object_safety_violations(trait_def_id);
|
||||||
report_object_safety_error(self.tcx, span, trait_def_id, violations)
|
report_object_safety_error(self.tcx, span, None, trait_def_id, violations)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
|
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
|
||||||
|
@ -924,7 +924,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
|
|
||||||
TraitNotObjectSafe(did) => {
|
TraitNotObjectSafe(did) => {
|
||||||
let violations = self.tcx.object_safety_violations(did);
|
let violations = self.tcx.object_safety_violations(did);
|
||||||
report_object_safety_error(self.tcx, span, did, violations)
|
report_object_safety_error(self.tcx, span, None, did, violations)
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => {
|
SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => {
|
||||||
|
|
|
@ -6,7 +6,7 @@ LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| x }]> {
|
||||||
|
|
|
|
||||||
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
|
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
|
||||||
= help: unsized fn params are gated as an unstable feature
|
= help: unsized fn params are gated as an unstable feature
|
||||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
help: function arguments must have a statically known size, borrowed slices always have a known size
|
||||||
|
|
|
|
||||||
LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: &[u8]| x }]> {
|
LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: &[u8]| x }]> {
|
||||||
| +
|
| +
|
||||||
|
|
|
@ -323,6 +323,10 @@ LL | || Output = <Self as SVec>::Item> as SVec>::Item,
|
||||||
LL | |
|
LL | |
|
||||||
LL | | > {
|
LL | | > {
|
||||||
| |__^ ...because it uses `Self` as a type parameter
|
| |__^ ...because it uses `Self` as a type parameter
|
||||||
|
help: consider using an opaque type instead
|
||||||
|
|
|
||||||
|
LL | pub fn next<'a, T>(s: &'a mut impl SVec<Item = T, Output = T>) {
|
||||||
|
| ~~~~
|
||||||
|
|
||||||
error[E0107]: missing generics for associated type `SVec::Item`
|
error[E0107]: missing generics for associated type `SVec::Item`
|
||||||
--> $DIR/issue-105742.rs:15:21
|
--> $DIR/issue-105742.rs:15:21
|
||||||
|
|
|
@ -29,8 +29,8 @@ LL | fn bar(x: impl Foo) {
|
||||||
| ++++
|
| ++++
|
||||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
|
||||||
LL | fn bar(x: &Foo) {
|
LL | fn bar(x: &dyn Foo) {
|
||||||
| +
|
| ++++
|
||||||
|
|
||||||
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
|
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
|
||||||
--> $DIR/feature-gate-unsized_fn_params.rs:25:8
|
--> $DIR/feature-gate-unsized_fn_params.rs:25:8
|
||||||
|
@ -40,7 +40,7 @@ LL | fn qux(_: [()]) {}
|
||||||
|
|
|
|
||||||
= help: the trait `Sized` is not implemented for `[()]`
|
= help: the trait `Sized` is not implemented for `[()]`
|
||||||
= help: unsized fn params are gated as an unstable feature
|
= help: unsized fn params are gated as an unstable feature
|
||||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
help: function arguments must have a statically known size, borrowed slices always have a known size
|
||||||
|
|
|
|
||||||
LL | fn qux(_: &[()]) {}
|
LL | fn qux(_: &[()]) {}
|
||||||
| +
|
| +
|
||||||
|
|
9
tests/ui/object-safety/bare-trait-dont-suggest-dyn.fixed
Normal file
9
tests/ui/object-safety/bare-trait-dont-suggest-dyn.fixed
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// run-rustfix
|
||||||
|
#![deny(bare_trait_objects)]
|
||||||
|
fn ord_prefer_dot(s: String) -> impl Ord {
|
||||||
|
//~^ ERROR the trait `Ord` cannot be made into an object
|
||||||
|
(s.starts_with("."), s)
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let _ = ord_prefer_dot(String::new());
|
||||||
|
}
|
9
tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs
Normal file
9
tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// run-rustfix
|
||||||
|
#![deny(bare_trait_objects)]
|
||||||
|
fn ord_prefer_dot(s: String) -> Ord {
|
||||||
|
//~^ ERROR the trait `Ord` cannot be made into an object
|
||||||
|
(s.starts_with("."), s)
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let _ = ord_prefer_dot(String::new());
|
||||||
|
}
|
21
tests/ui/object-safety/bare-trait-dont-suggest-dyn.stderr
Normal file
21
tests/ui/object-safety/bare-trait-dont-suggest-dyn.stderr
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
error[E0038]: the trait `Ord` cannot be made into an object
|
||||||
|
--> $DIR/bare-trait-dont-suggest-dyn.rs:3:33
|
||||||
|
|
|
||||||
|
LL | fn ord_prefer_dot(s: String) -> Ord {
|
||||||
|
| ^^^ `Ord` cannot be made into an object
|
||||||
|
|
|
||||||
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||||
|
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||||
|
|
|
||||||
|
= note: the trait cannot be made into an object because it uses `Self` as a type parameter
|
||||||
|
::: $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||||
|
|
|
||||||
|
= note: the trait cannot be made into an object because it uses `Self` as a type parameter
|
||||||
|
help: consider using an opaque type instead
|
||||||
|
|
|
||||||
|
LL | fn ord_prefer_dot(s: String) -> impl Ord {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0038`.
|
|
@ -11,6 +11,10 @@ LL | trait Baz : Bar<Self> {
|
||||||
| --- ^^^^^^^^^ ...because it uses `Self` as a type parameter
|
| --- ^^^^^^^^^ ...because it uses `Self` as a type parameter
|
||||||
| |
|
| |
|
||||||
| this trait cannot be made into an object...
|
| this trait cannot be made into an object...
|
||||||
|
help: consider using an opaque type instead
|
||||||
|
|
|
||||||
|
LL | fn make_baz<T:Baz>(t: &T) -> &impl Baz {
|
||||||
|
| ~~~~
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,6 @@ LL | fn foo(_x: K) {}
|
||||||
|
|
|
|
||||||
= help: the trait `Sized` is not implemented for `(dyn I + 'static)`
|
= help: the trait `Sized` is not implemented for `(dyn I + 'static)`
|
||||||
= help: unsized fn params are gated as an unstable feature
|
= help: unsized fn params are gated as an unstable feature
|
||||||
help: you can use `impl Trait` as the argument type
|
|
||||||
|
|
|
||||||
LL | fn foo(_x: impl K) {}
|
|
||||||
| ++++
|
|
||||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
|
||||||
LL | fn foo(_x: &K) {}
|
LL | fn foo(_x: &K) {}
|
||||||
|
|
17
tests/ui/traits/bound/not-on-bare-trait-2021.rs
Normal file
17
tests/ui/traits/bound/not-on-bare-trait-2021.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// edition:2021
|
||||||
|
trait Foo {
|
||||||
|
fn dummy(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should emit the less confusing error, not the more confusing one.
|
||||||
|
|
||||||
|
fn foo(_x: Foo + Send) {
|
||||||
|
//~^ ERROR trait objects must include the `dyn` keyword
|
||||||
|
}
|
||||||
|
fn bar(x: Foo) -> Foo {
|
||||||
|
//~^ ERROR trait objects must include the `dyn` keyword
|
||||||
|
//~| ERROR trait objects must include the `dyn` keyword
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
56
tests/ui/traits/bound/not-on-bare-trait-2021.stderr
Normal file
56
tests/ui/traits/bound/not-on-bare-trait-2021.stderr
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
error[E0782]: trait objects must include the `dyn` keyword
|
||||||
|
--> $DIR/not-on-bare-trait-2021.rs:8:12
|
||||||
|
|
|
||||||
|
LL | fn foo(_x: Foo + Send) {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use a new generic type parameter, constrained by `Foo + Send`
|
||||||
|
|
|
||||||
|
LL | fn foo<T: Foo + Send>(_x: T) {
|
||||||
|
| +++++++++++++++ ~
|
||||||
|
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||||
|
|
|
||||||
|
LL | fn foo(_x: impl Foo + Send) {
|
||||||
|
| ++++
|
||||||
|
help: alternatively, use a trait object to accept any type that implements `Foo + Send`, accessing its methods at runtime using dynamic dispatch
|
||||||
|
|
|
||||||
|
LL | fn foo(_x: &(dyn Foo + Send)) {
|
||||||
|
| +++++ +
|
||||||
|
|
||||||
|
error[E0782]: trait objects must include the `dyn` keyword
|
||||||
|
--> $DIR/not-on-bare-trait-2021.rs:11:11
|
||||||
|
|
|
||||||
|
LL | fn bar(x: Foo) -> Foo {
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
help: use a new generic type parameter, constrained by `Foo`
|
||||||
|
|
|
||||||
|
LL | fn bar<T: Foo>(x: T) -> Foo {
|
||||||
|
| ++++++++ ~
|
||||||
|
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||||
|
|
|
||||||
|
LL | fn bar(x: impl Foo) -> Foo {
|
||||||
|
| ++++
|
||||||
|
help: alternatively, use a trait object to accept any type that implements `Foo`, accessing its methods at runtime using dynamic dispatch
|
||||||
|
|
|
||||||
|
LL | fn bar(x: &dyn Foo) -> Foo {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error[E0782]: trait objects must include the `dyn` keyword
|
||||||
|
--> $DIR/not-on-bare-trait-2021.rs:11:19
|
||||||
|
|
|
||||||
|
LL | fn bar(x: Foo) -> Foo {
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
help: use `impl Foo` to return an opaque type, as long as you return a single underlying type
|
||||||
|
|
|
||||||
|
LL | fn bar(x: Foo) -> impl Foo {
|
||||||
|
| ++++
|
||||||
|
help: alternatively, you can return an owned trait object
|
||||||
|
|
|
||||||
|
LL | fn bar(x: Foo) -> Box<dyn Foo> {
|
||||||
|
| +++++++ +
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0782`.
|
|
@ -9,5 +9,8 @@ fn foo(_x: Foo + Send) {
|
||||||
//~| WARN trait objects without an explicit `dyn` are deprecated
|
//~| WARN trait objects without an explicit `dyn` are deprecated
|
||||||
//~| WARN this is accepted in the current edition
|
//~| WARN this is accepted in the current edition
|
||||||
}
|
}
|
||||||
|
fn bar(_x: (dyn Foo + Send)) {
|
||||||
|
//~^ ERROR the size for values of type
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -7,10 +7,18 @@ LL | fn foo(_x: Foo + Send) {
|
||||||
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
|
||||||
= note: `#[warn(bare_trait_objects)]` on by default
|
= note: `#[warn(bare_trait_objects)]` on by default
|
||||||
help: use `dyn`
|
help: use a new generic type parameter, constrained by `Foo + Send`
|
||||||
|
|
|
|
||||||
LL | fn foo(_x: dyn Foo + Send) {
|
LL | fn foo<T: Foo + Send>(_x: T) {
|
||||||
| +++
|
| +++++++++++++++ ~
|
||||||
|
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||||
|
|
|
||||||
|
LL | fn foo(_x: impl Foo + Send) {
|
||||||
|
| ++++
|
||||||
|
help: alternatively, use a trait object to accept any type that implements `Foo + Send`, accessing its methods at runtime using dynamic dispatch
|
||||||
|
|
|
||||||
|
LL | fn foo(_x: &(dyn Foo + Send)) {
|
||||||
|
| +++++ +
|
||||||
|
|
||||||
error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time
|
error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time
|
||||||
--> $DIR/not-on-bare-trait.rs:7:8
|
--> $DIR/not-on-bare-trait.rs:7:8
|
||||||
|
@ -26,9 +34,26 @@ LL | fn foo(_x: impl Foo + Send) {
|
||||||
| ++++
|
| ++++
|
||||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
|
||||||
LL | fn foo(_x: &Foo + Send) {
|
LL | fn foo(_x: &(dyn Foo + Send)) {
|
||||||
| +
|
| +++++ +
|
||||||
|
|
||||||
error: aborting due to 1 previous error; 1 warning emitted
|
error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time
|
||||||
|
--> $DIR/not-on-bare-trait.rs:12:8
|
||||||
|
|
|
||||||
|
LL | fn bar(_x: (dyn Foo + Send)) {
|
||||||
|
| ^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)`
|
||||||
|
= help: unsized fn params are gated as an unstable feature
|
||||||
|
help: you can use `impl Trait` as the argument type
|
||||||
|
|
|
||||||
|
LL | fn bar(_x: (impl Foo + Send)) {
|
||||||
|
| ~~~~
|
||||||
|
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||||
|
|
|
||||||
|
LL | fn bar(_x: (&(dyn Foo + Send))) {
|
||||||
|
| ++ +
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors; 1 warning emitted
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
|
|
@ -14,6 +14,10 @@ LL | pub trait Bar: Foo<Assoc=()> {
|
||||||
| | | ...because it uses `Self` as a type parameter
|
| | | ...because it uses `Self` as a type parameter
|
||||||
| | ...because it uses `Self` as a type parameter
|
| | ...because it uses `Self` as a type parameter
|
||||||
| this trait cannot be made into an object...
|
| this trait cannot be made into an object...
|
||||||
|
help: consider using an opaque type instead
|
||||||
|
|
|
||||||
|
LL | impl Bar
|
||||||
|
| ~~~~
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue