Rollup merge of #131273 - estebank:issue-131051, r=compiler-errors
Account for `impl Trait {` when `impl Trait for Type {` was intended On editions where bare traits are never allowed, detect if the user has written `impl Trait` with no type, silence any dyn-compatibility errors, and provide a structured suggestion for the potentially missing type: ``` error[E0782]: trait objects must include the `dyn` keyword --> $DIR/missing-for-type-in-impl.rs:8:6 | LL | impl Foo<i64> { | ^^^^^^^^ | help: add `dyn` keyword before this trait | LL | impl dyn Foo<i64> { | +++ help: you might have intended to implement this trait for a given type | LL | impl Foo<i64> for /* Type */ { | ++++++++++++++ ``` CC #131051.
This commit is contained in:
commit
08689af7b4
@ -108,17 +108,20 @@ fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
|
|||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
|
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
|
||||||
if let hir::Node::Item(hir::Item {
|
if let hir::Node::Item(hir::Item {
|
||||||
kind:
|
kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }),
|
||||||
hir::ItemKind::Impl(hir::Impl {
|
|
||||||
self_ty: impl_self_ty,
|
|
||||||
of_trait: Some(of_trait_ref),
|
|
||||||
generics,
|
|
||||||
..
|
|
||||||
}),
|
|
||||||
..
|
..
|
||||||
}) = tcx.hir_node_by_def_id(parent_id)
|
}) = tcx.hir_node_by_def_id(parent_id)
|
||||||
&& self_ty.hir_id == impl_self_ty.hir_id
|
&& self_ty.hir_id == impl_self_ty.hir_id
|
||||||
{
|
{
|
||||||
|
let Some(of_trait_ref) = of_trait else {
|
||||||
|
diag.span_suggestion_verbose(
|
||||||
|
impl_self_ty.span.shrink_to_hi(),
|
||||||
|
"you might have intended to implement this trait for a given type",
|
||||||
|
format!(" for /* Type */"),
|
||||||
|
Applicability::HasPlaceholders,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
|
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use core::ops::ControlFlow;
|
use core::ops::ControlFlow;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use rustc_ast::TraitObjectSyntax;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::unord::UnordSet;
|
use rustc_data_structures::unord::UnordSet;
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
@ -573,7 +574,26 @@ pub fn report_selection_error(
|
|||||||
|
|
||||||
ty::PredicateKind::DynCompatible(trait_def_id) => {
|
ty::PredicateKind::DynCompatible(trait_def_id) => {
|
||||||
let violations = self.tcx.dyn_compatibility_violations(trait_def_id);
|
let violations = self.tcx.dyn_compatibility_violations(trait_def_id);
|
||||||
report_dyn_incompatibility(self.tcx, span, None, trait_def_id, violations)
|
let mut err = report_dyn_incompatibility(
|
||||||
|
self.tcx,
|
||||||
|
span,
|
||||||
|
None,
|
||||||
|
trait_def_id,
|
||||||
|
violations,
|
||||||
|
);
|
||||||
|
if let hir::Node::Item(item) =
|
||||||
|
self.tcx.hir_node_by_def_id(obligation.cause.body_id)
|
||||||
|
&& let hir::ItemKind::Impl(impl_) = item.kind
|
||||||
|
&& let None = impl_.of_trait
|
||||||
|
&& let hir::TyKind::TraitObject(_, _, syntax) = impl_.self_ty.kind
|
||||||
|
&& let TraitObjectSyntax::None = syntax
|
||||||
|
&& impl_.self_ty.span.edition().at_least_rust_2021()
|
||||||
|
{
|
||||||
|
// Silence the dyn-compatibility error in favor of the missing dyn on
|
||||||
|
// self type error. #131051.
|
||||||
|
err.downgrade_to_delayed_bug();
|
||||||
|
}
|
||||||
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
|
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
|
||||||
|
74
tests/ui/traits/missing-for-type-in-impl.e2015.stderr
Normal file
74
tests/ui/traits/missing-for-type-in-impl.e2015.stderr
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
warning: trait objects without an explicit `dyn` are deprecated
|
||||||
|
--> $DIR/missing-for-type-in-impl.rs:8:6
|
||||||
|
|
|
||||||
|
LL | impl Foo<i64> {
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= 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: if this is a dyn-compatible trait, use `dyn`
|
||||||
|
|
|
||||||
|
LL | impl dyn Foo<i64> {
|
||||||
|
| +++
|
||||||
|
help: you might have intended to implement this trait for a given type
|
||||||
|
|
|
||||||
|
LL | impl Foo<i64> for /* Type */ {
|
||||||
|
| ++++++++++++++
|
||||||
|
|
||||||
|
warning: trait objects without an explicit `dyn` are deprecated
|
||||||
|
--> $DIR/missing-for-type-in-impl.rs:8:6
|
||||||
|
|
|
||||||
|
LL | impl Foo<i64> {
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= 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: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
help: if this is a dyn-compatible trait, use `dyn`
|
||||||
|
|
|
||||||
|
LL | impl dyn Foo<i64> {
|
||||||
|
| +++
|
||||||
|
help: you might have intended to implement this trait for a given type
|
||||||
|
|
|
||||||
|
LL | impl Foo<i64> for /* Type */ {
|
||||||
|
| ++++++++++++++
|
||||||
|
|
||||||
|
error[E0038]: the trait `Foo` cannot be made into an object
|
||||||
|
--> $DIR/missing-for-type-in-impl.rs:8:6
|
||||||
|
|
|
||||||
|
LL | impl Foo<i64> {
|
||||||
|
| ^^^^^^^^ `Foo` cannot be made into an object
|
||||||
|
|
|
||||||
|
note: for a trait to be "dyn-compatible" 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>
|
||||||
|
--> $DIR/missing-for-type-in-impl.rs:4:8
|
||||||
|
|
|
||||||
|
LL | trait Foo<T> {
|
||||||
|
| --- this trait cannot be made into an object...
|
||||||
|
LL | fn id(me: T) -> T;
|
||||||
|
| ^^ ...because associated function `id` has no `self` parameter
|
||||||
|
help: consider turning `id` into a method by giving it a `&self` argument
|
||||||
|
|
|
||||||
|
LL | fn id(&self, me: T) -> T;
|
||||||
|
| ++++++
|
||||||
|
help: alternatively, consider constraining `id` so it does not apply to trait objects
|
||||||
|
|
|
||||||
|
LL | fn id(me: T) -> T where Self: Sized;
|
||||||
|
| +++++++++++++++++
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `i64: Foo<i64>` is not satisfied
|
||||||
|
--> $DIR/missing-for-type-in-impl.rs:19:19
|
||||||
|
|
|
||||||
|
LL | let x: i64 = <i64 as Foo<i64>>::id(10);
|
||||||
|
| ^^^ the trait `Foo<i64>` is not implemented for `i64`
|
||||||
|
|
|
||||||
|
help: this trait has no implementations, consider adding one
|
||||||
|
--> $DIR/missing-for-type-in-impl.rs:3:1
|
||||||
|
|
|
||||||
|
LL | trait Foo<T> {
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors; 2 warnings emitted
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0038, E0277.
|
||||||
|
For more information about an error, try `rustc --explain E0038`.
|
31
tests/ui/traits/missing-for-type-in-impl.e2021.stderr
Normal file
31
tests/ui/traits/missing-for-type-in-impl.e2021.stderr
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
error[E0277]: the trait bound `i64: Foo<i64>` is not satisfied
|
||||||
|
--> $DIR/missing-for-type-in-impl.rs:19:19
|
||||||
|
|
|
||||||
|
LL | let x: i64 = <i64 as Foo<i64>>::id(10);
|
||||||
|
| ^^^ the trait `Foo<i64>` is not implemented for `i64`
|
||||||
|
|
|
||||||
|
help: this trait has no implementations, consider adding one
|
||||||
|
--> $DIR/missing-for-type-in-impl.rs:3:1
|
||||||
|
|
|
||||||
|
LL | trait Foo<T> {
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0782]: trait objects must include the `dyn` keyword
|
||||||
|
--> $DIR/missing-for-type-in-impl.rs:8:6
|
||||||
|
|
|
||||||
|
LL | impl Foo<i64> {
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
help: add `dyn` keyword before this trait
|
||||||
|
|
|
||||||
|
LL | impl dyn Foo<i64> {
|
||||||
|
| +++
|
||||||
|
help: you might have intended to implement this trait for a given type
|
||||||
|
|
|
||||||
|
LL | impl Foo<i64> for /* Type */ {
|
||||||
|
| ++++++++++++++
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0277, E0782.
|
||||||
|
For more information about an error, try `rustc --explain E0277`.
|
22
tests/ui/traits/missing-for-type-in-impl.rs
Normal file
22
tests/ui/traits/missing-for-type-in-impl.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
//@revisions: e2021 e2015
|
||||||
|
//@[e2021]edition: 2021
|
||||||
|
trait Foo<T> {
|
||||||
|
fn id(me: T) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* note the "missing" for ... (in this case for i64, in order for this to compile) */
|
||||||
|
impl Foo<i64> {
|
||||||
|
//[e2021]~^ ERROR trait objects must include the `dyn` keyword
|
||||||
|
//[e2015]~^^ WARNING trait objects without an explicit `dyn` are deprecated
|
||||||
|
//[e2015]~| WARNING trait objects without an explicit `dyn` are deprecated
|
||||||
|
//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||||
|
//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||||
|
//[e2015]~| ERROR the trait `Foo` cannot be made into an object
|
||||||
|
fn id(me: i64) -> i64 {me}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x: i64 = <i64 as Foo<i64>>::id(10);
|
||||||
|
//~^ ERROR the trait bound `i64: Foo<i64>` is not satisfied
|
||||||
|
println!("{}", x);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user