Skip to content

Commit 22b9e96

Browse files
committed
Suggest assoc ty bound on bare dyn trait in eq constraint
1 parent d3d77a8 commit 22b9e96

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs

+38
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
6464
if self_ty.span.can_be_used_for_suggestions()
6565
&& !self.maybe_suggest_impl_trait(self_ty, &mut diag)
6666
{
67+
// FIXME: Only emit this suggestion if the trait is object safe.
6768
diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
6869
}
6970
// Check if the impl trait that we are considering is an impl of a local trait.
7071
self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag);
72+
self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag);
7173
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
7274
} else {
7375
let msg = "trait objects without an explicit `dyn` are deprecated";
@@ -153,6 +155,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
153155
fn maybe_suggest_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -> bool {
154156
let tcx = self.tcx();
155157
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
158+
// FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
159+
// and suggest `Trait0<Ty = impl Trait1>`.
156160
let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
157161
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
158162
(sig, generics, None)
@@ -260,4 +264,38 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
260264
}
261265
false
262266
}
267+
268+
fn maybe_suggest_assoc_ty_bound(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) {
269+
let mut parents = self.tcx().hir().parent_iter(self_ty.hir_id);
270+
271+
if let Some((_, hir::Node::TypeBinding(binding))) = parents.next()
272+
&& let hir::TypeBindingKind::Equality { term: hir::Term::Ty(obj_ty) } = binding.kind
273+
{
274+
if let Some((_, hir::Node::TraitRef(..))) = parents.next()
275+
&& let Some((_, hir::Node::Ty(ty))) = parents.next()
276+
&& let hir::TyKind::TraitObject(..) = ty.kind
277+
{
278+
// Assoc ty bounds aren't permitted inside trait object types.
279+
return;
280+
}
281+
282+
let lo = if binding.gen_args.span_ext.is_dummy() {
283+
binding.ident.span
284+
} else {
285+
binding.gen_args.span_ext
286+
};
287+
let hi = obj_ty.span;
288+
289+
if !lo.eq_ctxt(hi) {
290+
return;
291+
}
292+
293+
diag.span_suggestion_verbose(
294+
lo.between(hi),
295+
"you might have meant to write a bound here",
296+
": ",
297+
Applicability::MaybeIncorrect,
298+
);
299+
}
300+
}
263301
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Regression test for issue #105056.
2+
//@ edition: 2021
3+
4+
fn f(_: impl Trait<T = Copy>) {}
5+
//~^ ERROR trait objects must include the `dyn` keyword
6+
//~| HELP add `dyn` keyword before this trait
7+
//~| HELP you might have meant to write a bound here
8+
//~| ERROR the trait `Copy` cannot be made into an object
9+
10+
fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
11+
//~^ ERROR trait objects must include the `dyn` keyword
12+
//~| HELP add `dyn` keyword before this trait
13+
//~| HELP you might have meant to write a bound here
14+
//~| ERROR only auto traits can be used as additional traits in a trait object
15+
//~| HELP consider creating a new trait
16+
//~| ERROR the trait `Eq` cannot be made into an object
17+
18+
fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
19+
//~^ ERROR trait objects must include the `dyn` keyword
20+
//~| HELP add `dyn` keyword before this trait
21+
//~| HELP you might have meant to write a bound here
22+
23+
// Don't suggest assoc ty bound in trait object types, that's not valid:
24+
type Obj = dyn Trait<T = Clone>;
25+
//~^ ERROR trait objects must include the `dyn` keyword
26+
//~| HELP add `dyn` keyword before this trait
27+
28+
trait Trait { type T; }
29+
30+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
error[E0038]: the trait `Copy` cannot be made into an object
2+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:20
3+
|
4+
LL | fn f(_: impl Trait<T = Copy>) {}
5+
| ^^^^^^^^ `Copy` cannot be made into an object
6+
|
7+
= note: the trait cannot be made into an object because it requires `Self: Sized`
8+
= 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>
9+
10+
error[E0225]: only auto traits can be used as additional traits in a trait object
11+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:42
12+
|
13+
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
14+
| --------------- ^^ additional non-auto trait
15+
| |
16+
| first non-auto trait
17+
|
18+
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Debug + Eq {}`
19+
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
20+
21+
error[E0038]: the trait `Eq` cannot be made into an object
22+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24
23+
|
24+
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
25+
| ^^^^^^^^^^^^^^^^^^^^ `Eq` cannot be made into an object
26+
|
27+
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>
28+
--> $SRC_DIR/core/src/cmp.rs:LL:COL
29+
|
30+
= note: the trait cannot be made into an object because it uses `Self` as a type parameter
31+
32+
error[E0782]: trait objects must include the `dyn` keyword
33+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:24
34+
|
35+
LL | fn f(_: impl Trait<T = Copy>) {}
36+
| ^^^^
37+
|
38+
help: add `dyn` keyword before this trait
39+
|
40+
LL | fn f(_: impl Trait<T = dyn Copy>) {}
41+
| +++
42+
help: you might have meant to write a bound here
43+
|
44+
LL | fn f(_: impl Trait<T: Copy>) {}
45+
| ~
46+
47+
error[E0782]: trait objects must include the `dyn` keyword
48+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24
49+
|
50+
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
51+
| ^^^^^^^^^^^^^^^^^^^^
52+
|
53+
help: add `dyn` keyword before this trait
54+
|
55+
LL | fn g(_: impl Trait<T = dyn std::fmt::Debug + Eq>) {}
56+
| +++
57+
help: you might have meant to write a bound here
58+
|
59+
LL | fn g(_: impl Trait<T: std::fmt::Debug + Eq>) {}
60+
| ~
61+
62+
error[E0782]: trait objects must include the `dyn` keyword
63+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:18:26
64+
|
65+
LL | fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
66+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
67+
|
68+
help: add `dyn` keyword before this trait
69+
|
70+
LL | fn h(_: impl Trait<T<> = dyn 'static + for<'a> Fn(&'a ())>) {}
71+
| +++
72+
help: you might have meant to write a bound here
73+
|
74+
LL | fn h(_: impl Trait<T<>: 'static + for<'a> Fn(&'a ())>) {}
75+
| ~
76+
77+
error[E0782]: trait objects must include the `dyn` keyword
78+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:24:26
79+
|
80+
LL | type Obj = dyn Trait<T = Clone>;
81+
| ^^^^^
82+
|
83+
help: add `dyn` keyword before this trait
84+
|
85+
LL | type Obj = dyn Trait<T = dyn Clone>;
86+
| +++
87+
88+
error: aborting due to 7 previous errors
89+
90+
Some errors have detailed explanations: E0038, E0225, E0782.
91+
For more information about an error, try `rustc --explain E0038`.

0 commit comments

Comments
 (0)