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 =
|
||||
object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use rustc_ast::TraitObjectSyntax;
|
||||
use rustc_errors::{Diagnostic, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
|
||||
|
||||
use super::AstConv;
|
||||
|
@ -32,32 +34,146 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
let of_trait_span = of_trait_ref.path.span;
|
||||
// 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 {
|
||||
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() {
|
||||
(span, format!(", {param_name}: {impl_trait_name}"))
|
||||
} else {
|
||||
(generics.span, format!("<{param_name}: {impl_trait_name}>"))
|
||||
let Ok(impl_trait_name) = self.tcx().sess.source_map().span_to_snippet(self_ty.span)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name);
|
||||
if sugg.is_empty() {
|
||||
return;
|
||||
};
|
||||
diag.multipart_suggestion(
|
||||
format!(
|
||||
"alternatively use a blanket \
|
||||
implementation to implement `{of_trait_name}` for \
|
||||
"alternatively use a blanket implementation to implement `{of_trait_name}` for \
|
||||
all types that also implement `{impl_trait_name}`"
|
||||
),
|
||||
vec![(self_ty.span, param_name), add_generic_sugg],
|
||||
sugg,
|
||||
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) {
|
||||
let tcx = self.tcx();
|
||||
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 mut diag =
|
||||
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(
|
||||
label,
|
||||
sugg,
|
||||
|
@ -116,11 +234,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
self_ty.span,
|
||||
msg,
|
||||
|lint| {
|
||||
lint.multipart_suggestion_verbose(
|
||||
"use `dyn`",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
if self_ty.span.can_be_used_for_suggestions()
|
||||
&& !self.maybe_lint_impl_trait(self_ty, lint)
|
||||
{
|
||||
lint.multipart_suggestion_verbose(
|
||||
"use `dyn`",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
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(
|
||||
tcx,
|
||||
span,
|
||||
Some(hir_id),
|
||||
item.trait_ref().def_id(),
|
||||
&object_safety_violations,
|
||||
)
|
||||
|
|
|
@ -73,7 +73,8 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
let inputs_fn = fn_sig.inputs().iter().copied();
|
||||
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
|
||||
// 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);
|
||||
|
||||
// Check that argument is Sized.
|
||||
|
@ -81,14 +82,14 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
fcx.require_type_is_sized(
|
||||
param_ty,
|
||||
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
|
||||
traits::SizedArgumentType(
|
||||
if ty_span == Some(param.span) && tcx.is_closure_or_coroutine(fn_def_id.into())
|
||||
{
|
||||
None
|
||||
} 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
|
||||
// *distinct* cases. so track when we are hitting a pattern *within* an fn
|
||||
// parameter.
|
||||
outermost_fn_param_pat: Option<Span>,
|
||||
outermost_fn_param_pat: Option<(Span, hir::HirId)>,
|
||||
}
|
||||
|
||||
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>) {
|
||||
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);
|
||||
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 {
|
||||
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 {
|
||||
self.fcx.require_type_is_sized(
|
||||
var_ty,
|
||||
|
@ -154,7 +155,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
|
|||
{
|
||||
None
|
||||
} else {
|
||||
Some(ty_span)
|
||||
Some(hir_id)
|
||||
},
|
||||
),
|
||||
);
|
||||
|
|
|
@ -2,9 +2,10 @@ use super::ObjectSafetyViolation;
|
|||
|
||||
use crate::infer::InferCtxt;
|
||||
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::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::Map;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
@ -42,6 +43,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
pub fn report_object_safety_error<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
hir_id: Option<hir::HirId>,
|
||||
trait_def_id: DefId,
|
||||
violations: &[ObjectSafetyViolation],
|
||||
) -> 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"));
|
||||
|
||||
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 multi_span = vec![];
|
||||
let mut messages = vec![];
|
||||
|
|
|
@ -289,7 +289,7 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
/// Type of each variable must be `Sized`.
|
||||
VariableType(hir::HirId),
|
||||
/// Argument type must be `Sized`.
|
||||
SizedArgumentType(Option<Span>),
|
||||
SizedArgumentType(Option<hir::HirId>),
|
||||
/// Return type must be `Sized`.
|
||||
SizedReturnType,
|
||||
/// Yield type must be `Sized`.
|
||||
|
|
|
@ -19,11 +19,10 @@ use rustc_errors::{
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
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::lang_items::LangItem;
|
||||
use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Node};
|
||||
use rustc_hir::{Expr, HirId};
|
||||
use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node};
|
||||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
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");
|
||||
}
|
||||
}
|
||||
ObligationCauseCode::SizedArgumentType(ty_span) => {
|
||||
if let Some(span) = ty_span {
|
||||
if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
|
||||
&& let ty::ClauseKind::Trait(trait_pred) = clause
|
||||
&& let ty::Dynamic(..) = trait_pred.self_ty().kind()
|
||||
{
|
||||
let span = if let Ok(snippet) =
|
||||
self.tcx.sess.source_map().span_to_snippet(span)
|
||||
&& snippet.starts_with("dyn ")
|
||||
{
|
||||
let pos = snippet.len() - snippet[3..].trim_start().len();
|
||||
span.with_hi(span.lo() + BytePos(pos as u32))
|
||||
} else {
|
||||
span.shrink_to_lo()
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
"you can use `impl Trait` as the argument type",
|
||||
"impl ".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
ObligationCauseCode::SizedArgumentType(hir_id) => {
|
||||
let mut ty = None;
|
||||
let borrowed_msg = "function arguments must have a statically known size, borrowed \
|
||||
types always have a known size";
|
||||
if let Some(hir_id) = hir_id
|
||||
&& let Some(hir::Node::Param(param)) = self.tcx.hir().find(hir_id)
|
||||
&& let Some(item) = self.tcx.hir().find_parent(hir_id)
|
||||
&& let Some(decl) = item.fn_decl()
|
||||
&& let Some(t) = decl.inputs.iter().find(|t| param.ty_span.contains(t.span))
|
||||
{
|
||||
// We use `contains` because the type might be surrounded by parentheses,
|
||||
// which makes `ty_span` and `t.span` disagree with each other, but one
|
||||
// fully contains the other: `foo: (dyn Foo + Bar)`
|
||||
// ^-------------^
|
||||
// ||
|
||||
// |t.span
|
||||
// param._ty_span
|
||||
ty = Some(t);
|
||||
} else if let Some(hir_id) = hir_id
|
||||
&& 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 {
|
||||
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) => {
|
||||
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)) => {
|
||||
|
@ -924,7 +924,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
|
||||
TraitNotObjectSafe(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) => {
|
||||
|
|
|
@ -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: 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 }]> {
|
||||
| +
|
||||
|
|
|
@ -323,6 +323,10 @@ LL | || Output = <Self as SVec>::Item> as SVec>::Item,
|
|||
LL | |
|
||||
LL | | > {
|
||||
| |__^ ...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`
|
||||
--> $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
|
||||
|
|
||||
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
|
||||
--> $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: 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(_: &[()]) {}
|
||||
| +
|
||||
|
|
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
|
||||
| |
|
||||
| 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
|
||||
|
||||
|
|
|
@ -6,10 +6,6 @@ LL | fn foo(_x: K) {}
|
|||
|
|
||||
= help: the trait `Sized` is not implemented for `(dyn I + 'static)`
|
||||
= 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
|
||||
|
|
||||
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 this is accepted in the current edition
|
||||
}
|
||||
fn bar(_x: (dyn Foo + Send)) {
|
||||
//~^ ERROR the size for values of type
|
||||
}
|
||||
|
||||
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!
|
||||
= 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
|
||||
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
|
||||
--> $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
|
||||
|
|
||||
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`.
|
||||
|
|
|
@ -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
|
||||
| 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
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue