Skip to content

Commit 08689af

Browse files
Rollup merge of rust-lang#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 rust-lang#131051.
2 parents 3078b23 + e057c43 commit 08689af

File tree

5 files changed

+158
-8
lines changed

5 files changed

+158
-8
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
108108
let tcx = self.tcx();
109109
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
110110
if let hir::Node::Item(hir::Item {
111-
kind:
112-
hir::ItemKind::Impl(hir::Impl {
113-
self_ty: impl_self_ty,
114-
of_trait: Some(of_trait_ref),
115-
generics,
116-
..
117-
}),
111+
kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }),
118112
..
119113
}) = tcx.hir_node_by_def_id(parent_id)
120114
&& self_ty.hir_id == impl_self_ty.hir_id
121115
{
116+
let Some(of_trait_ref) = of_trait else {
117+
diag.span_suggestion_verbose(
118+
impl_self_ty.span.shrink_to_hi(),
119+
"you might have intended to implement this trait for a given type",
120+
format!(" for /* Type */"),
121+
Applicability::HasPlaceholders,
122+
);
123+
return;
124+
};
122125
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
123126
return;
124127
}

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use core::ops::ControlFlow;
22
use std::borrow::Cow;
33

4+
use rustc_ast::TraitObjectSyntax;
45
use rustc_data_structures::fx::FxHashMap;
56
use rustc_data_structures::unord::UnordSet;
67
use rustc_errors::codes::*;
@@ -573,7 +574,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
573574

574575
ty::PredicateKind::DynCompatible(trait_def_id) => {
575576
let violations = self.tcx.dyn_compatibility_violations(trait_def_id);
576-
report_dyn_incompatibility(self.tcx, span, None, trait_def_id, violations)
577+
let mut err = report_dyn_incompatibility(
578+
self.tcx,
579+
span,
580+
None,
581+
trait_def_id,
582+
violations,
583+
);
584+
if let hir::Node::Item(item) =
585+
self.tcx.hir_node_by_def_id(obligation.cause.body_id)
586+
&& let hir::ItemKind::Impl(impl_) = item.kind
587+
&& let None = impl_.of_trait
588+
&& let hir::TyKind::TraitObject(_, _, syntax) = impl_.self_ty.kind
589+
&& let TraitObjectSyntax::None = syntax
590+
&& impl_.self_ty.span.edition().at_least_rust_2021()
591+
{
592+
// Silence the dyn-compatibility error in favor of the missing dyn on
593+
// self type error. #131051.
594+
err.downgrade_to_delayed_bug();
595+
}
596+
err
577597
}
578598

579599
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
warning: trait objects without an explicit `dyn` are deprecated
2+
--> $DIR/missing-for-type-in-impl.rs:8:6
3+
|
4+
LL | impl Foo<i64> {
5+
| ^^^^^^^^
6+
|
7+
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
8+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
9+
= note: `#[warn(bare_trait_objects)]` on by default
10+
help: if this is a dyn-compatible trait, use `dyn`
11+
|
12+
LL | impl dyn Foo<i64> {
13+
| +++
14+
help: you might have intended to implement this trait for a given type
15+
|
16+
LL | impl Foo<i64> for /* Type */ {
17+
| ++++++++++++++
18+
19+
warning: trait objects without an explicit `dyn` are deprecated
20+
--> $DIR/missing-for-type-in-impl.rs:8:6
21+
|
22+
LL | impl Foo<i64> {
23+
| ^^^^^^^^
24+
|
25+
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
26+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
27+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
28+
help: if this is a dyn-compatible trait, use `dyn`
29+
|
30+
LL | impl dyn Foo<i64> {
31+
| +++
32+
help: you might have intended to implement this trait for a given type
33+
|
34+
LL | impl Foo<i64> for /* Type */ {
35+
| ++++++++++++++
36+
37+
error[E0038]: the trait `Foo` cannot be made into an object
38+
--> $DIR/missing-for-type-in-impl.rs:8:6
39+
|
40+
LL | impl Foo<i64> {
41+
| ^^^^^^^^ `Foo` cannot be made into an object
42+
|
43+
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>
44+
--> $DIR/missing-for-type-in-impl.rs:4:8
45+
|
46+
LL | trait Foo<T> {
47+
| --- this trait cannot be made into an object...
48+
LL | fn id(me: T) -> T;
49+
| ^^ ...because associated function `id` has no `self` parameter
50+
help: consider turning `id` into a method by giving it a `&self` argument
51+
|
52+
LL | fn id(&self, me: T) -> T;
53+
| ++++++
54+
help: alternatively, consider constraining `id` so it does not apply to trait objects
55+
|
56+
LL | fn id(me: T) -> T where Self: Sized;
57+
| +++++++++++++++++
58+
59+
error[E0277]: the trait bound `i64: Foo<i64>` is not satisfied
60+
--> $DIR/missing-for-type-in-impl.rs:19:19
61+
|
62+
LL | let x: i64 = <i64 as Foo<i64>>::id(10);
63+
| ^^^ the trait `Foo<i64>` is not implemented for `i64`
64+
|
65+
help: this trait has no implementations, consider adding one
66+
--> $DIR/missing-for-type-in-impl.rs:3:1
67+
|
68+
LL | trait Foo<T> {
69+
| ^^^^^^^^^^^^
70+
71+
error: aborting due to 2 previous errors; 2 warnings emitted
72+
73+
Some errors have detailed explanations: E0038, E0277.
74+
For more information about an error, try `rustc --explain E0038`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error[E0277]: the trait bound `i64: Foo<i64>` is not satisfied
2+
--> $DIR/missing-for-type-in-impl.rs:19:19
3+
|
4+
LL | let x: i64 = <i64 as Foo<i64>>::id(10);
5+
| ^^^ the trait `Foo<i64>` is not implemented for `i64`
6+
|
7+
help: this trait has no implementations, consider adding one
8+
--> $DIR/missing-for-type-in-impl.rs:3:1
9+
|
10+
LL | trait Foo<T> {
11+
| ^^^^^^^^^^^^
12+
13+
error[E0782]: trait objects must include the `dyn` keyword
14+
--> $DIR/missing-for-type-in-impl.rs:8:6
15+
|
16+
LL | impl Foo<i64> {
17+
| ^^^^^^^^
18+
|
19+
help: add `dyn` keyword before this trait
20+
|
21+
LL | impl dyn Foo<i64> {
22+
| +++
23+
help: you might have intended to implement this trait for a given type
24+
|
25+
LL | impl Foo<i64> for /* Type */ {
26+
| ++++++++++++++
27+
28+
error: aborting due to 2 previous errors
29+
30+
Some errors have detailed explanations: E0277, E0782.
31+
For more information about an error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@revisions: e2021 e2015
2+
//@[e2021]edition: 2021
3+
trait Foo<T> {
4+
fn id(me: T) -> T;
5+
}
6+
7+
/* note the "missing" for ... (in this case for i64, in order for this to compile) */
8+
impl Foo<i64> {
9+
//[e2021]~^ ERROR trait objects must include the `dyn` keyword
10+
//[e2015]~^^ WARNING trait objects without an explicit `dyn` are deprecated
11+
//[e2015]~| WARNING trait objects without an explicit `dyn` are deprecated
12+
//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
13+
//[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
14+
//[e2015]~| ERROR the trait `Foo` cannot be made into an object
15+
fn id(me: i64) -> i64 {me}
16+
}
17+
18+
fn main() {
19+
let x: i64 = <i64 as Foo<i64>>::id(10);
20+
//~^ ERROR the trait bound `i64: Foo<i64>` is not satisfied
21+
println!("{}", x);
22+
}

0 commit comments

Comments
 (0)