parent
771966ba29
commit
78ef94618b
4 changed files with 98 additions and 25 deletions
|
@ -1,6 +1,7 @@
|
|||
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;
|
||||
|
@ -90,15 +91,29 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
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
|
||||
{
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!("use `impl {trait_name}` to return an opaque type, as long as you return a single underlying type"),
|
||||
impl_sugg,
|
||||
Applicability::MachineApplicable,
|
||||
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",
|
||||
);
|
||||
if tcx.check_is_object_safe(def_id) {
|
||||
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![
|
||||
|
@ -111,25 +126,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
return true;
|
||||
}
|
||||
for ty in sig.decl.inputs {
|
||||
if ty.hir_id == self_ty.hir_id {
|
||||
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 !tcx.check_is_object_safe(def_id) {
|
||||
diag.note(format!("it is not object safe, so it can't be `dyn`"));
|
||||
}
|
||||
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`"));
|
||||
} else {
|
||||
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
|
||||
// There are more than one trait bound, we need surrounding parentheses.
|
||||
vec![
|
||||
|
@ -147,8 +163,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
11
tests/ui/object-safety/bare-trait-dont-suggest-dyn.fixed
Normal file
11
tests/ui/object-safety/bare-trait-dont-suggest-dyn.fixed
Normal file
|
@ -0,0 +1,11 @@
|
|||
// run-rustfix
|
||||
#![deny(bare_trait_objects)]
|
||||
fn ord_prefer_dot(s: String) -> impl Ord {
|
||||
//~^ ERROR trait objects without an explicit `dyn` are deprecated
|
||||
//~| ERROR the trait `Ord` cannot be made into an object
|
||||
//~| WARNING this is accepted in the current edition (Rust 2015)
|
||||
(s.starts_with("."), s)
|
||||
}
|
||||
fn main() {
|
||||
let _ = ord_prefer_dot(String::new());
|
||||
}
|
11
tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs
Normal file
11
tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
// run-rustfix
|
||||
#![deny(bare_trait_objects)]
|
||||
fn ord_prefer_dot(s: String) -> Ord {
|
||||
//~^ ERROR trait objects without an explicit `dyn` are deprecated
|
||||
//~| ERROR the trait `Ord` cannot be made into an object
|
||||
//~| WARNING this is accepted in the current edition (Rust 2015)
|
||||
(s.starts_with("."), s)
|
||||
}
|
||||
fn main() {
|
||||
let _ = ord_prefer_dot(String::new());
|
||||
}
|
35
tests/ui/object-safety/bare-trait-dont-suggest-dyn.stderr
Normal file
35
tests/ui/object-safety/bare-trait-dont-suggest-dyn.stderr
Normal file
|
@ -0,0 +1,35 @@
|
|||
error: trait objects without an explicit `dyn` are deprecated
|
||||
--> $DIR/bare-trait-dont-suggest-dyn.rs:3:33
|
||||
|
|
||||
LL | fn ord_prefer_dot(s: String) -> Ord {
|
||||
| ^^^
|
||||
|
|
||||
= 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: the lint level is defined here
|
||||
--> $DIR/bare-trait-dont-suggest-dyn.rs:2:9
|
||||
|
|
||||
LL | #![deny(bare_trait_objects)]
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
help: `Ord` is not object safe, use `impl Ord` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn ord_prefer_dot(s: String) -> impl Ord {
|
||||
| ++++
|
||||
|
||||
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
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0038`.
|
Loading…
Add table
Reference in a new issue