Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b65d9d3

Browse files
committedJan 9, 2024
Account for traits using self-trait by name without dyn
Fix #119652.
1 parent 4bdb7cb commit b65d9d3

5 files changed

+222
-9
lines changed
 

‎compiler/rustc_hir_analysis/src/astconv/lint.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
7878
fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) -> bool {
7979
let tcx = self.tcx();
8080
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
81-
let (hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. })
82-
| hir::Node::TraitItem(hir::TraitItem {
83-
kind: hir::TraitItemKind::Fn(sig, _),
84-
generics,
85-
..
86-
})) = tcx.hir_node_by_def_id(parent_id)
87-
else {
88-
return false;
81+
let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
82+
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
83+
(sig, generics, None)
84+
}
85+
hir::Node::TraitItem(hir::TraitItem {
86+
kind: hir::TraitItemKind::Fn(sig, _),
87+
generics,
88+
owner_id,
89+
..
90+
}) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
91+
_ => return false,
8992
};
9093
let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
9194
return false;
@@ -94,7 +97,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
9497
let is_object_safe = match self_ty.kind {
9598
hir::TyKind::TraitObject(objects, ..) => {
9699
objects.iter().all(|o| match o.trait_ref.path.res {
97-
Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id),
100+
Res::Def(DefKind::Trait, id) => {
101+
// When we're dealing with a recursive trait, we don't want to downgrade
102+
// the error, so we consider them to be object safe always. (#119652)
103+
tcx.check_is_object_safe(id) || Some(id) == owner
104+
}
98105
_ => false,
99106
})
100107
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// edition:2021
2+
#![allow(bare_trait_objects)]
3+
trait A: Sized {
4+
fn f(a: A) -> A;
5+
//~^ ERROR trait objects must include the `dyn` keyword
6+
//~| ERROR trait objects must include the `dyn` keyword
7+
}
8+
trait B {
9+
fn f(a: B) -> B;
10+
//~^ ERROR trait objects must include the `dyn` keyword
11+
//~| ERROR trait objects must include the `dyn` keyword
12+
}
13+
trait C {
14+
fn f(&self, a: C) -> C;
15+
//~^ ERROR trait objects must include the `dyn` keyword
16+
//~| ERROR trait objects must include the `dyn` keyword
17+
}
18+
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
error[E0782]: trait objects must include the `dyn` keyword
2+
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13
3+
|
4+
LL | fn f(a: A) -> A;
5+
| ^
6+
|
7+
help: use a new generic type parameter, constrained by `A`
8+
|
9+
LL | fn f<T: A>(a: T) -> A;
10+
| ++++++ ~
11+
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
12+
|
13+
LL | fn f(a: impl A) -> A;
14+
| ++++
15+
help: alternatively, use a trait object to accept any type that implements `A`, accessing its methods at runtime using dynamic dispatch
16+
|
17+
LL | fn f(a: &dyn A) -> A;
18+
| ++++
19+
20+
error[E0782]: trait objects must include the `dyn` keyword
21+
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:19
22+
|
23+
LL | fn f(a: A) -> A;
24+
| ^
25+
|
26+
help: use `impl A` to return an opaque type, as long as you return a single underlying type
27+
|
28+
LL | fn f(a: A) -> impl A;
29+
| ++++
30+
help: alternatively, you can return an owned trait object
31+
|
32+
LL | fn f(a: A) -> Box<dyn A>;
33+
| +++++++ +
34+
35+
error[E0782]: trait objects must include the `dyn` keyword
36+
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:9:13
37+
|
38+
LL | fn f(a: B) -> B;
39+
| ^
40+
|
41+
help: use a new generic type parameter, constrained by `B`
42+
|
43+
LL | fn f<T: B>(a: T) -> B;
44+
| ++++++ ~
45+
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
46+
|
47+
LL | fn f(a: impl B) -> B;
48+
| ++++
49+
help: alternatively, use a trait object to accept any type that implements `B`, accessing its methods at runtime using dynamic dispatch
50+
|
51+
LL | fn f(a: &dyn B) -> B;
52+
| ++++
53+
54+
error[E0782]: trait objects must include the `dyn` keyword
55+
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:9:19
56+
|
57+
LL | fn f(a: B) -> B;
58+
| ^
59+
|
60+
help: use `impl B` to return an opaque type, as long as you return a single underlying type
61+
|
62+
LL | fn f(a: B) -> impl B;
63+
| ++++
64+
help: alternatively, you can return an owned trait object
65+
|
66+
LL | fn f(a: B) -> Box<dyn B>;
67+
| +++++++ +
68+
69+
error[E0782]: trait objects must include the `dyn` keyword
70+
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:14:20
71+
|
72+
LL | fn f(&self, a: C) -> C;
73+
| ^
74+
|
75+
help: use a new generic type parameter, constrained by `C`
76+
|
77+
LL | fn f<T: C>(&self, a: T) -> C;
78+
| ++++++ ~
79+
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
80+
|
81+
LL | fn f(&self, a: impl C) -> C;
82+
| ++++
83+
help: alternatively, use a trait object to accept any type that implements `C`, accessing its methods at runtime using dynamic dispatch
84+
|
85+
LL | fn f(&self, a: &dyn C) -> C;
86+
| ++++
87+
88+
error[E0782]: trait objects must include the `dyn` keyword
89+
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:14:26
90+
|
91+
LL | fn f(&self, a: C) -> C;
92+
| ^
93+
|
94+
help: use `impl C` to return an opaque type, as long as you return a single underlying type
95+
|
96+
LL | fn f(&self, a: C) -> impl C;
97+
| ++++
98+
help: alternatively, you can return an owned trait object
99+
|
100+
LL | fn f(&self, a: C) -> Box<dyn C>;
101+
| +++++++ +
102+
103+
error: aborting due to 6 previous errors
104+
105+
For more information about this error, try `rustc --explain E0782`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// edition:2021
2+
#![allow(bare_trait_objects)]
3+
trait A: Sized {
4+
fn f(a: dyn A) -> dyn A;
5+
//~^ ERROR associated item referring to unboxed trait object for its own trait
6+
//~| ERROR the trait `A` cannot be made into an object
7+
}
8+
trait B {
9+
fn f(a: dyn B) -> dyn B;
10+
//~^ ERROR associated item referring to unboxed trait object for its own trait
11+
//~| ERROR the trait `B` cannot be made into an object
12+
}
13+
trait C {
14+
fn f(&self, a: dyn C) -> dyn C;
15+
}
16+
17+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
error: associated item referring to unboxed trait object for its own trait
2+
--> $DIR/object-unsafe-trait-should-use-self-2021.rs:4:13
3+
|
4+
LL | trait A: Sized {
5+
| - in this trait
6+
LL | fn f(a: dyn A) -> dyn A;
7+
| ^^^^^ ^^^^^
8+
|
9+
help: you might have meant to use `Self` to refer to the implementing type
10+
|
11+
LL | fn f(a: Self) -> Self;
12+
| ~~~~ ~~~~
13+
14+
error[E0038]: the trait `A` cannot be made into an object
15+
--> $DIR/object-unsafe-trait-should-use-self-2021.rs:4:13
16+
|
17+
LL | fn f(a: dyn A) -> dyn A;
18+
| ^^^^^ `A` cannot be made into an object
19+
|
20+
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>
21+
--> $DIR/object-unsafe-trait-should-use-self-2021.rs:3:10
22+
|
23+
LL | trait A: Sized {
24+
| - ^^^^^ ...because it requires `Self: Sized`
25+
| |
26+
| this trait cannot be made into an object...
27+
28+
error: associated item referring to unboxed trait object for its own trait
29+
--> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:13
30+
|
31+
LL | trait B {
32+
| - in this trait
33+
LL | fn f(a: dyn B) -> dyn B;
34+
| ^^^^^ ^^^^^
35+
|
36+
help: you might have meant to use `Self` to refer to the implementing type
37+
|
38+
LL | fn f(a: Self) -> Self;
39+
| ~~~~ ~~~~
40+
41+
error[E0038]: the trait `B` cannot be made into an object
42+
--> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:13
43+
|
44+
LL | fn f(a: dyn B) -> dyn B;
45+
| ^^^^^ `B` cannot be made into an object
46+
|
47+
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>
48+
--> $DIR/object-unsafe-trait-should-use-self-2021.rs:9:8
49+
|
50+
LL | trait B {
51+
| - this trait cannot be made into an object...
52+
LL | fn f(a: dyn B) -> dyn B;
53+
| ^ ...because associated function `f` has no `self` parameter
54+
help: consider turning `f` into a method by giving it a `&self` argument
55+
|
56+
LL | fn f(&self, a: dyn B) -> dyn B;
57+
| ++++++
58+
help: alternatively, consider constraining `f` so it does not apply to trait objects
59+
|
60+
LL | fn f(a: dyn B) -> dyn B where Self: Sized;
61+
| +++++++++++++++++
62+
63+
error: aborting due to 4 previous errors
64+
65+
For more information about this error, try `rustc --explain E0038`.

0 commit comments

Comments
 (0)
Please sign in to comment.