Skip to content

Commit 16fe4ce

Browse files
committed
Don't assume traits used as type are trait objs
1 parent e6c46db commit 16fe4ce

File tree

59 files changed

+607
-679
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+607
-679
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs

+25-28
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_ast::TraitObjectSyntax;
22
use rustc_errors::codes::*;
3-
use rustc_errors::{Diag, EmissionGuarantee, StashKey};
3+
use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, StashKey, Suggestions};
44
use rustc_hir as hir;
55
use rustc_hir::def::{DefKind, Res};
66
use rustc_lint_defs::Applicability;
@@ -15,13 +15,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
1515
///
1616
/// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`.
1717
/// In edition 2021 and onward we emit a hard error for them.
18-
pub(super) fn prohibit_or_lint_bare_trait_object_ty(&self, self_ty: &hir::Ty<'_>) {
18+
pub(super) fn prohibit_or_lint_bare_trait_object_ty(
19+
&self,
20+
self_ty: &hir::Ty<'_>,
21+
) -> Option<ErrorGuaranteed> {
1922
let tcx = self.tcx();
2023

2124
let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
2225
self_ty.kind
2326
else {
24-
return;
27+
return None;
2528
};
2629

2730
let in_path = match tcx.parent_hir_node(self_ty.hir_id) {
@@ -70,8 +73,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
7073
}
7174

7275
if self_ty.span.edition().at_least_rust_2021() {
73-
let msg = "trait objects must include the `dyn` keyword";
74-
let label = "add `dyn` keyword before this trait";
76+
let msg = "expected a type, found a trait";
77+
let label = "you can add the `dyn` keyword if you want a trait object";
7578
let mut diag =
7679
rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg);
7780
if self_ty.span.can_be_used_for_suggestions()
@@ -83,7 +86,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
8386
// Check if the impl trait that we are considering is an impl of a local trait.
8487
self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag);
8588
self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag);
86-
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
89+
// In case there is an associate type with the same name
90+
// Add the suggestion to this error
91+
if let Some(mut sugg) =
92+
tcx.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion)
93+
&& let Suggestions::Enabled(ref mut s1) = diag.suggestions
94+
&& let Suggestions::Enabled(ref mut s2) = sugg.suggestions
95+
{
96+
s1.append(s2);
97+
sugg.cancel();
98+
}
99+
diag.stash(self_ty.span, StashKey::TraitMissingMethod)
87100
} else {
88101
tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, |lint| {
89102
lint.primary_message("trait objects without an explicit `dyn` are deprecated");
@@ -96,6 +109,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
96109
}
97110
self.maybe_suggest_blanket_trait_impl(self_ty, lint);
98111
});
112+
None
99113
}
100114
}
101115

@@ -174,41 +188,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
174188
// 1. Independent functions
175189
// 2. Functions inside trait blocks
176190
// 3. Functions inside impl blocks
177-
let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
191+
let (sig, generics) = match tcx.hir_node_by_def_id(parent_id) {
178192
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
179-
(sig, generics, None)
193+
(sig, generics)
180194
}
181195
hir::Node::TraitItem(hir::TraitItem {
182196
kind: hir::TraitItemKind::Fn(sig, _),
183197
generics,
184-
owner_id,
185198
..
186-
}) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
199+
}) => (sig, generics),
187200
hir::Node::ImplItem(hir::ImplItem {
188201
kind: hir::ImplItemKind::Fn(sig, _),
189202
generics,
190-
owner_id,
191203
..
192-
}) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
204+
}) => (sig, generics),
193205
_ => return false,
194206
};
195207
let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
196208
return false;
197209
};
198210
let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
199-
let mut is_downgradable = true;
200-
201211
// Check if trait object is safe for suggesting dynamic dispatch.
202212
let is_dyn_compatible = match self_ty.kind {
203213
hir::TyKind::TraitObject(objects, ..) => {
204214
objects.iter().all(|(o, _)| match o.trait_ref.path.res {
205-
Res::Def(DefKind::Trait, id) => {
206-
if Some(id) == owner {
207-
// For recursive traits, don't downgrade the error. (#119652)
208-
is_downgradable = false;
209-
}
210-
tcx.is_dyn_compatible(id)
211-
}
215+
Res::Def(DefKind::Trait, id) => tcx.is_dyn_compatible(id),
212216
_ => false,
213217
})
214218
}
@@ -255,9 +259,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
255259
suggestion,
256260
Applicability::MachineApplicable,
257261
);
258-
} else if is_downgradable {
259-
// We'll emit the dyn-compatibility error already, with a structured suggestion.
260-
diag.downgrade_to_delayed_bug();
261262
}
262263
return true;
263264
}
@@ -281,10 +282,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
281282
);
282283
if !is_dyn_compatible {
283284
diag.note(format!("`{trait_name}` it is dyn-incompatible, so it can't be `dyn`"));
284-
if is_downgradable {
285-
// We'll emit the dyn-compatibility error already, with a structured suggestion.
286-
diag.downgrade_to_delayed_bug();
287-
}
288285
} else {
289286
// No ampersand in suggestion if it's borrowed already
290287
let (dyn_str, paren_dyn_str) =

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -2063,13 +2063,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
20632063
)
20642064
}
20652065
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
2066-
self.prohibit_or_lint_bare_trait_object_ty(hir_ty);
2067-
2068-
let repr = match repr {
2069-
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
2070-
TraitObjectSyntax::DynStar => ty::DynStar,
2071-
};
2072-
self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr)
2066+
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
2067+
// Don't continue with type analysis if the `dyn` keyword is missing
2068+
// It generates confusing errors, especially if the user meant to use another
2069+
// keyword like `impl`
2070+
Ty::new_error(tcx, guar)
2071+
} else {
2072+
let repr = match repr {
2073+
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
2074+
TraitObjectSyntax::DynStar => ty::DynStar,
2075+
};
2076+
self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr)
2077+
}
20732078
}
20742079
// If we encounter a fully qualified path with RTN generics, then it must have
20752080
// *not* gone through `lower_ty_maybe_return_type_notation`, and therefore

tests/crashes/120241-2.rs

-10
This file was deleted.

tests/crashes/120241.rs

-13
This file was deleted.

tests/crashes/120482.rs

-13
This file was deleted.

tests/crashes/125512.rs

-10
This file was deleted.

tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,24 @@
22
//@ edition: 2021
33

44
fn f(_: impl Trait<T = Copy>) {}
5-
//~^ ERROR trait objects must include the `dyn` keyword
6-
//~| HELP add `dyn` keyword before this trait
5+
//~^ ERROR expected a type, found a trait
6+
//~| HELP you can add the `dyn` keyword if you want a trait object
77
//~| HELP you might have meant to write a bound here
8-
//~| ERROR the trait `Copy` cannot be made into an object
98

109
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
10+
//~^ ERROR expected a type, found a trait
11+
//~| HELP you can add the `dyn` keyword if you want a trait object
1312
//~| 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
1713

1814
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
15+
//~^ ERROR expected a type, found a trait
16+
//~| HELP you can add the `dyn` keyword if you want a trait object
2117
//~| HELP you might have meant to write a bound here
2218

2319
// Don't suggest assoc ty bound in trait object types, that's not valid:
2420
type Obj = dyn Trait<T = Clone>;
25-
//~^ ERROR trait objects must include the `dyn` keyword
26-
//~| HELP add `dyn` keyword before this trait
21+
//~^ ERROR expected a type, found a trait
22+
//~| HELP you can add the `dyn` keyword if you want a trait object
2723

2824
trait Trait { type T; }
2925

Original file line numberDiff line numberDiff line change
@@ -1,41 +1,10 @@
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 "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>
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 "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>
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
1+
error[E0782]: expected a type, found a trait
332
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:24
343
|
354
LL | fn f(_: impl Trait<T = Copy>) {}
365
| ^^^^
376
|
38-
help: add `dyn` keyword before this trait
7+
help: you can add the `dyn` keyword if you want a trait object
398
|
409
LL | fn f(_: impl Trait<T = dyn Copy>) {}
4110
| +++
@@ -44,13 +13,13 @@ help: you might have meant to write a bound here
4413
LL | fn f(_: impl Trait<T: Copy>) {}
4514
| ~
4615

47-
error[E0782]: trait objects must include the `dyn` keyword
48-
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24
16+
error[E0782]: expected a type, found a trait
17+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:9:24
4918
|
5019
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
5120
| ^^^^^^^^^^^^^^^^^^^^
5221
|
53-
help: add `dyn` keyword before this trait
22+
help: you can add the `dyn` keyword if you want a trait object
5423
|
5524
LL | fn g(_: impl Trait<T = dyn std::fmt::Debug + Eq>) {}
5625
| +++
@@ -59,13 +28,13 @@ help: you might have meant to write a bound here
5928
LL | fn g(_: impl Trait<T: std::fmt::Debug + Eq>) {}
6029
| ~
6130

62-
error[E0782]: trait objects must include the `dyn` keyword
63-
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:18:26
31+
error[E0782]: expected a type, found a trait
32+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:14:26
6433
|
6534
LL | fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
6635
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6736
|
68-
help: add `dyn` keyword before this trait
37+
help: you can add the `dyn` keyword if you want a trait object
6938
|
7039
LL | fn h(_: impl Trait<T<> = dyn 'static + for<'a> Fn(&'a ())>) {}
7140
| +++
@@ -74,18 +43,17 @@ help: you might have meant to write a bound here
7443
LL | fn h(_: impl Trait<T<>: 'static + for<'a> Fn(&'a ())>) {}
7544
| ~
7645

77-
error[E0782]: trait objects must include the `dyn` keyword
78-
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:24:26
46+
error[E0782]: expected a type, found a trait
47+
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:20:26
7948
|
8049
LL | type Obj = dyn Trait<T = Clone>;
8150
| ^^^^^
8251
|
83-
help: add `dyn` keyword before this trait
52+
help: you can add the `dyn` keyword if you want a trait object
8453
|
8554
LL | type Obj = dyn Trait<T = dyn Clone>;
8655
| +++
8756

88-
error: aborting due to 7 previous errors
57+
error: aborting due to 4 previous errors
8958

90-
Some errors have detailed explanations: E0038, E0225, E0782.
91-
For more information about an error, try `rustc --explain E0038`.
59+
For more information about this error, try `rustc --explain E0782`.

tests/ui/const-generics/generic_const_exprs/expected-type-of-closure-body-to-be-a-closure-or-coroutine-ice-113776.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@ fn f<T>(
1414
1
1515
}],
1616
) -> impl Iterator<Item = SubAssign> {
17-
//~^ ERROR the type parameter `Rhs` must be explicitly specified
17+
//~^ ERROR expected a type, found a trait
1818
//~| ERROR `()` is not an iterator
19-
//~| ERROR trait objects must include the `dyn` keyword
20-
//~| ERROR the type parameter `Rhs` must be explicitly specified [E0393]
2119
}
2220

2321
pub fn main() {}

0 commit comments

Comments
 (0)