Skip to content

Commit 640019b

Browse files
authored
Rollup merge of rust-lang#97812 - TaKO8Ki:suggest-to-swap-struct-and-trait, r=estebank
Suggest to swap a struct and a trait in trait impls closes rust-lang#89590
2 parents 59c2ff5 + 5639e52 commit 640019b

7 files changed

+185
-2
lines changed

compiler/rustc_resolve/src/late.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,9 @@ struct DiagnosticMetadata<'ast> {
513513

514514
/// The current impl items (used to suggest).
515515
current_impl_items: Option<&'ast [P<AssocItem>]>,
516+
517+
/// When processing impl trait
518+
currently_processing_impl_trait: Option<(TraitRef, Ty)>,
516519
}
517520

518521
struct LateResolutionVisitor<'a, 'b, 'ast> {
@@ -2087,18 +2090,22 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
20872090
fn with_optional_trait_ref<T>(
20882091
&mut self,
20892092
opt_trait_ref: Option<&TraitRef>,
2093+
self_type: &'ast Ty,
20902094
f: impl FnOnce(&mut Self, Option<DefId>) -> T,
20912095
) -> T {
20922096
let mut new_val = None;
20932097
let mut new_id = None;
20942098
if let Some(trait_ref) = opt_trait_ref {
20952099
let path: Vec<_> = Segment::from_path(&trait_ref.path);
2100+
self.diagnostic_metadata.currently_processing_impl_trait =
2101+
Some((trait_ref.clone(), self_type.clone()));
20962102
let res = self.smart_resolve_path_fragment(
20972103
None,
20982104
&path,
20992105
PathSource::Trait(AliasPossibility::No),
21002106
Finalize::new(trait_ref.ref_id, trait_ref.path.span),
21012107
);
2108+
self.diagnostic_metadata.currently_processing_impl_trait = None;
21022109
if let Some(def_id) = res.base_res().opt_def_id() {
21032110
new_id = Some(def_id);
21042111
new_val = Some((self.r.expect_module(def_id), trait_ref.clone()));
@@ -2139,7 +2146,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
21392146
this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
21402147
this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter(item_id), |this| {
21412148
// Resolve the trait reference, if necessary.
2142-
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
2149+
this.with_optional_trait_ref(opt_trait_reference.as_ref(), self_type, |this, trait_id| {
21432150
let item_def_id = this.r.local_def_id(item_id);
21442151

21452152
// Register the trait definitions from here.

compiler/rustc_resolve/src/late/diagnostics.rs

+33
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
146146
let is_expected = &|res| source.is_expected(res);
147147
let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
148148

149+
debug!(?res, ?source);
150+
149151
// Make the base error.
150152
struct BaseError<'a> {
151153
msg: String,
@@ -250,6 +252,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
250252
let mut err =
251253
self.r.session.struct_span_err_with_code(base_error.span, &base_error.msg, code);
252254

255+
self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
256+
253257
if let Some(sugg) = base_error.suggestion {
254258
err.span_suggestion_verbose(sugg.0, sugg.1, sugg.2, Applicability::MaybeIncorrect);
255259
}
@@ -692,6 +696,35 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
692696
}
693697
}
694698

699+
fn suggest_swapping_misplaced_self_ty_and_trait(
700+
&mut self,
701+
err: &mut Diagnostic,
702+
source: PathSource<'_>,
703+
res: Option<Res>,
704+
span: Span,
705+
) {
706+
if let Some((trait_ref, self_ty)) =
707+
self.diagnostic_metadata.currently_processing_impl_trait.clone()
708+
&& let TyKind::Path(_, self_ty_path) = &self_ty.kind
709+
&& let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
710+
self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None)
711+
&& let ModuleKind::Def(DefKind::Trait, ..) = module.kind
712+
&& trait_ref.path.span == span
713+
&& let PathSource::Trait(_) = source
714+
&& let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res
715+
&& let Ok(self_ty_str) =
716+
self.r.session.source_map().span_to_snippet(self_ty.span)
717+
&& let Ok(trait_ref_str) =
718+
self.r.session.source_map().span_to_snippet(trait_ref.path.span)
719+
{
720+
err.multipart_suggestion(
721+
"`impl` items mention the trait being implemented first and the type it is being implemented for second",
722+
vec![(trait_ref.path.span, self_ty_str), (self_ty.span, trait_ref_str)],
723+
Applicability::MaybeIncorrect,
724+
);
725+
}
726+
}
727+
695728
fn get_single_associated_item(
696729
&mut self,
697730
path: &[Segment],

compiler/rustc_span/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ impl<'a> FileNameDisplay<'a> {
333333
pub fn to_string_lossy(&self) -> Cow<'a, str> {
334334
match self.inner {
335335
FileName::Real(ref inner) => inner.to_string_lossy(self.display_pref),
336-
_ => Cow::from(format!("{}", self)),
336+
_ => Cow::from(self.to_string()),
337337
}
338338
}
339339
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// edition:2021
2+
3+
pub trait Trait<'a, T> {}
4+
5+
pub struct Struct<T>;
6+
pub enum Enum<T> {}
7+
8+
pub union Union<T> {
9+
f1: usize,
10+
}
11+
12+
impl<'a, T> Struct<T> for Trait<'a, T> {}
13+
//~^ ERROR expected trait, found struct `Struct`
14+
//~| ERROR trait objects must include the `dyn` keyword
15+
16+
impl<'a, T> Enum<T> for Trait<'a, T> {}
17+
//~^ ERROR expected trait, found enum `Enum`
18+
19+
impl<'a, T> Union<T> for Trait<'a, T> {}
20+
//~^ ERROR expected trait, found union `Union`
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
error[E0404]: expected trait, found struct `Struct`
2+
--> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:12:13
3+
|
4+
LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
5+
| ^^^^^^^^^ not a trait
6+
|
7+
help: `impl` items mention the trait being implemented first and the type it is being implemented for second
8+
|
9+
LL | impl<'a, T> Trait<'a, T> for Struct<T> {}
10+
| ~~~~~~~~~~~~ ~~~~~~~~~
11+
12+
error[E0404]: expected trait, found enum `Enum`
13+
--> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:16:13
14+
|
15+
LL | impl<'a, T> Enum<T> for Trait<'a, T> {}
16+
| ^^^^^^^ not a trait
17+
|
18+
help: `impl` items mention the trait being implemented first and the type it is being implemented for second
19+
|
20+
LL | impl<'a, T> Trait<'a, T> for Enum<T> {}
21+
| ~~~~~~~~~~~~ ~~~~~~~
22+
23+
error[E0404]: expected trait, found union `Union`
24+
--> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:19:13
25+
|
26+
LL | impl<'a, T> Union<T> for Trait<'a, T> {}
27+
| ^^^^^^^^ not a trait
28+
|
29+
help: `impl` items mention the trait being implemented first and the type it is being implemented for second
30+
|
31+
LL | impl<'a, T> Trait<'a, T> for Union<T> {}
32+
| ~~~~~~~~~~~~ ~~~~~~~~
33+
34+
error[E0782]: trait objects must include the `dyn` keyword
35+
--> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:12:27
36+
|
37+
LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
38+
| ^^^^^^^^^^^^
39+
|
40+
help: add `dyn` keyword before this trait
41+
|
42+
LL - impl<'a, T> Struct<T> for Trait<'a, T> {}
43+
LL + impl<'a, T> Struct<T> for dyn Trait<'a, T> {}
44+
|
45+
46+
error: aborting due to 4 previous errors
47+
48+
Some errors have detailed explanations: E0404, E0782.
49+
For more information about an error, try `rustc --explain E0404`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
pub trait Trait<'a, T> {}
2+
3+
pub struct Struct<T>;
4+
pub enum Enum<T> {}
5+
6+
pub union Union<T> {
7+
f1: usize,
8+
}
9+
10+
impl<'a, T> Struct<T> for Trait<'a, T> {}
11+
//~^ ERROR expected trait, found struct `Struct`
12+
//~| WARNING trait objects without an explicit `dyn` are deprecated
13+
//~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
14+
15+
impl<'a, T> Enum<T> for Trait<'a, T> {}
16+
//~^ ERROR expected trait, found enum `Enum`
17+
18+
impl<'a, T> Union<T> for Trait<'a, T> {}
19+
//~^ ERROR expected trait, found union `Union`
20+
21+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
error[E0404]: expected trait, found struct `Struct`
2+
--> $DIR/suggest-swapping-self-ty-and-trait.rs:10:13
3+
|
4+
LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
5+
| ^^^^^^^^^ not a trait
6+
|
7+
help: `impl` items mention the trait being implemented first and the type it is being implemented for second
8+
|
9+
LL | impl<'a, T> Trait<'a, T> for Struct<T> {}
10+
| ~~~~~~~~~~~~ ~~~~~~~~~
11+
12+
error[E0404]: expected trait, found enum `Enum`
13+
--> $DIR/suggest-swapping-self-ty-and-trait.rs:15:13
14+
|
15+
LL | impl<'a, T> Enum<T> for Trait<'a, T> {}
16+
| ^^^^^^^ not a trait
17+
|
18+
help: `impl` items mention the trait being implemented first and the type it is being implemented for second
19+
|
20+
LL | impl<'a, T> Trait<'a, T> for Enum<T> {}
21+
| ~~~~~~~~~~~~ ~~~~~~~
22+
23+
error[E0404]: expected trait, found union `Union`
24+
--> $DIR/suggest-swapping-self-ty-and-trait.rs:18:13
25+
|
26+
LL | impl<'a, T> Union<T> for Trait<'a, T> {}
27+
| ^^^^^^^^ not a trait
28+
|
29+
help: `impl` items mention the trait being implemented first and the type it is being implemented for second
30+
|
31+
LL | impl<'a, T> Trait<'a, T> for Union<T> {}
32+
| ~~~~~~~~~~~~ ~~~~~~~~
33+
34+
warning: trait objects without an explicit `dyn` are deprecated
35+
--> $DIR/suggest-swapping-self-ty-and-trait.rs:10:27
36+
|
37+
LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
38+
| ^^^^^^^^^^^^
39+
|
40+
= note: `#[warn(bare_trait_objects)]` on by default
41+
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
42+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
43+
help: use `dyn`
44+
|
45+
LL - impl<'a, T> Struct<T> for Trait<'a, T> {}
46+
LL + impl<'a, T> Struct<T> for dyn Trait<'a, T> {}
47+
|
48+
49+
error: aborting due to 3 previous errors; 1 warning emitted
50+
51+
For more information about this error, try `rustc --explain E0404`.

0 commit comments

Comments
 (0)