Rollup merge of #97812 - TaKO8Ki:suggest-to-swap-struct-and-trait, r=estebank
Suggest to swap a struct and a trait in trait impls closes #89590
This commit is contained in:
commit
640019ba6e
@ -513,6 +513,9 @@ struct DiagnosticMetadata<'ast> {
|
||||
|
||||
/// The current impl items (used to suggest).
|
||||
current_impl_items: Option<&'ast [P<AssocItem>]>,
|
||||
|
||||
/// When processing impl trait
|
||||
currently_processing_impl_trait: Option<(TraitRef, Ty)>,
|
||||
}
|
||||
|
||||
struct LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
@ -2087,18 +2090,22 @@ fn with_trait_items<T>(
|
||||
fn with_optional_trait_ref<T>(
|
||||
&mut self,
|
||||
opt_trait_ref: Option<&TraitRef>,
|
||||
self_type: &'ast Ty,
|
||||
f: impl FnOnce(&mut Self, Option<DefId>) -> T,
|
||||
) -> T {
|
||||
let mut new_val = None;
|
||||
let mut new_id = None;
|
||||
if let Some(trait_ref) = opt_trait_ref {
|
||||
let path: Vec<_> = Segment::from_path(&trait_ref.path);
|
||||
self.diagnostic_metadata.currently_processing_impl_trait =
|
||||
Some((trait_ref.clone(), self_type.clone()));
|
||||
let res = self.smart_resolve_path_fragment(
|
||||
None,
|
||||
&path,
|
||||
PathSource::Trait(AliasPossibility::No),
|
||||
Finalize::new(trait_ref.ref_id, trait_ref.path.span),
|
||||
);
|
||||
self.diagnostic_metadata.currently_processing_impl_trait = None;
|
||||
if let Some(def_id) = res.base_res().opt_def_id() {
|
||||
new_id = Some(def_id);
|
||||
new_val = Some((self.r.expect_module(def_id), trait_ref.clone()));
|
||||
@ -2139,7 +2146,7 @@ fn resolve_implementation(
|
||||
this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
|
||||
this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter(item_id), |this| {
|
||||
// Resolve the trait reference, if necessary.
|
||||
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
|
||||
this.with_optional_trait_ref(opt_trait_reference.as_ref(), self_type, |this, trait_id| {
|
||||
let item_def_id = this.r.local_def_id(item_id);
|
||||
|
||||
// Register the trait definitions from here.
|
||||
|
@ -146,6 +146,8 @@ pub(crate) fn smart_resolve_report_errors(
|
||||
let is_expected = &|res| source.is_expected(res);
|
||||
let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
|
||||
|
||||
debug!(?res, ?source);
|
||||
|
||||
// Make the base error.
|
||||
struct BaseError<'a> {
|
||||
msg: String,
|
||||
@ -250,6 +252,8 @@ struct BaseError<'a> {
|
||||
let mut err =
|
||||
self.r.session.struct_span_err_with_code(base_error.span, &base_error.msg, code);
|
||||
|
||||
self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
|
||||
|
||||
if let Some(sugg) = base_error.suggestion {
|
||||
err.span_suggestion_verbose(sugg.0, sugg.1, sugg.2, Applicability::MaybeIncorrect);
|
||||
}
|
||||
@ -692,6 +696,35 @@ fn detect_assoct_type_constraint_meant_as_path(&self, base_span: Span, err: &mut
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_swapping_misplaced_self_ty_and_trait(
|
||||
&mut self,
|
||||
err: &mut Diagnostic,
|
||||
source: PathSource<'_>,
|
||||
res: Option<Res>,
|
||||
span: Span,
|
||||
) {
|
||||
if let Some((trait_ref, self_ty)) =
|
||||
self.diagnostic_metadata.currently_processing_impl_trait.clone()
|
||||
&& let TyKind::Path(_, self_ty_path) = &self_ty.kind
|
||||
&& let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
|
||||
self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None)
|
||||
&& let ModuleKind::Def(DefKind::Trait, ..) = module.kind
|
||||
&& trait_ref.path.span == span
|
||||
&& let PathSource::Trait(_) = source
|
||||
&& let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res
|
||||
&& let Ok(self_ty_str) =
|
||||
self.r.session.source_map().span_to_snippet(self_ty.span)
|
||||
&& let Ok(trait_ref_str) =
|
||||
self.r.session.source_map().span_to_snippet(trait_ref.path.span)
|
||||
{
|
||||
err.multipart_suggestion(
|
||||
"`impl` items mention the trait being implemented first and the type it is being implemented for second",
|
||||
vec![(trait_ref.path.span, self_ty_str), (self_ty.span, trait_ref_str)],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_single_associated_item(
|
||||
&mut self,
|
||||
path: &[Segment],
|
||||
|
@ -333,7 +333,7 @@ impl<'a> FileNameDisplay<'a> {
|
||||
pub fn to_string_lossy(&self) -> Cow<'a, str> {
|
||||
match self.inner {
|
||||
FileName::Real(ref inner) => inner.to_string_lossy(self.display_pref),
|
||||
_ => Cow::from(format!("{}", self)),
|
||||
_ => Cow::from(self.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
// edition:2021
|
||||
|
||||
pub trait Trait<'a, T> {}
|
||||
|
||||
pub struct Struct<T>;
|
||||
pub enum Enum<T> {}
|
||||
|
||||
pub union Union<T> {
|
||||
f1: usize,
|
||||
}
|
||||
|
||||
impl<'a, T> Struct<T> for Trait<'a, T> {}
|
||||
//~^ ERROR expected trait, found struct `Struct`
|
||||
//~| ERROR trait objects must include the `dyn` keyword
|
||||
|
||||
impl<'a, T> Enum<T> for Trait<'a, T> {}
|
||||
//~^ ERROR expected trait, found enum `Enum`
|
||||
|
||||
impl<'a, T> Union<T> for Trait<'a, T> {}
|
||||
//~^ ERROR expected trait, found union `Union`
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,49 @@
|
||||
error[E0404]: expected trait, found struct `Struct`
|
||||
--> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:12:13
|
||||
|
|
||||
LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
|
||||
| ^^^^^^^^^ not a trait
|
||||
|
|
||||
help: `impl` items mention the trait being implemented first and the type it is being implemented for second
|
||||
|
|
||||
LL | impl<'a, T> Trait<'a, T> for Struct<T> {}
|
||||
| ~~~~~~~~~~~~ ~~~~~~~~~
|
||||
|
||||
error[E0404]: expected trait, found enum `Enum`
|
||||
--> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:16:13
|
||||
|
|
||||
LL | impl<'a, T> Enum<T> for Trait<'a, T> {}
|
||||
| ^^^^^^^ not a trait
|
||||
|
|
||||
help: `impl` items mention the trait being implemented first and the type it is being implemented for second
|
||||
|
|
||||
LL | impl<'a, T> Trait<'a, T> for Enum<T> {}
|
||||
| ~~~~~~~~~~~~ ~~~~~~~
|
||||
|
||||
error[E0404]: expected trait, found union `Union`
|
||||
--> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:19:13
|
||||
|
|
||||
LL | impl<'a, T> Union<T> for Trait<'a, T> {}
|
||||
| ^^^^^^^^ not a trait
|
||||
|
|
||||
help: `impl` items mention the trait being implemented first and the type it is being implemented for second
|
||||
|
|
||||
LL | impl<'a, T> Trait<'a, T> for Union<T> {}
|
||||
| ~~~~~~~~~~~~ ~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/suggest-swapping-self-ty-and-trait-edition-2021.rs:12:27
|
||||
|
|
||||
LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
help: add `dyn` keyword before this trait
|
||||
|
|
||||
LL - impl<'a, T> Struct<T> for Trait<'a, T> {}
|
||||
LL + impl<'a, T> Struct<T> for dyn Trait<'a, T> {}
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0404, E0782.
|
||||
For more information about an error, try `rustc --explain E0404`.
|
@ -0,0 +1,21 @@
|
||||
pub trait Trait<'a, T> {}
|
||||
|
||||
pub struct Struct<T>;
|
||||
pub enum Enum<T> {}
|
||||
|
||||
pub union Union<T> {
|
||||
f1: usize,
|
||||
}
|
||||
|
||||
impl<'a, T> Struct<T> for Trait<'a, T> {}
|
||||
//~^ ERROR expected trait, found struct `Struct`
|
||||
//~| WARNING trait objects without an explicit `dyn` are deprecated
|
||||
//~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||
|
||||
impl<'a, T> Enum<T> for Trait<'a, T> {}
|
||||
//~^ ERROR expected trait, found enum `Enum`
|
||||
|
||||
impl<'a, T> Union<T> for Trait<'a, T> {}
|
||||
//~^ ERROR expected trait, found union `Union`
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,51 @@
|
||||
error[E0404]: expected trait, found struct `Struct`
|
||||
--> $DIR/suggest-swapping-self-ty-and-trait.rs:10:13
|
||||
|
|
||||
LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
|
||||
| ^^^^^^^^^ not a trait
|
||||
|
|
||||
help: `impl` items mention the trait being implemented first and the type it is being implemented for second
|
||||
|
|
||||
LL | impl<'a, T> Trait<'a, T> for Struct<T> {}
|
||||
| ~~~~~~~~~~~~ ~~~~~~~~~
|
||||
|
||||
error[E0404]: expected trait, found enum `Enum`
|
||||
--> $DIR/suggest-swapping-self-ty-and-trait.rs:15:13
|
||||
|
|
||||
LL | impl<'a, T> Enum<T> for Trait<'a, T> {}
|
||||
| ^^^^^^^ not a trait
|
||||
|
|
||||
help: `impl` items mention the trait being implemented first and the type it is being implemented for second
|
||||
|
|
||||
LL | impl<'a, T> Trait<'a, T> for Enum<T> {}
|
||||
| ~~~~~~~~~~~~ ~~~~~~~
|
||||
|
||||
error[E0404]: expected trait, found union `Union`
|
||||
--> $DIR/suggest-swapping-self-ty-and-trait.rs:18:13
|
||||
|
|
||||
LL | impl<'a, T> Union<T> for Trait<'a, T> {}
|
||||
| ^^^^^^^^ not a trait
|
||||
|
|
||||
help: `impl` items mention the trait being implemented first and the type it is being implemented for second
|
||||
|
|
||||
LL | impl<'a, T> Trait<'a, T> for Union<T> {}
|
||||
| ~~~~~~~~~~~~ ~~~~~~~~
|
||||
|
||||
warning: trait objects without an explicit `dyn` are deprecated
|
||||
--> $DIR/suggest-swapping-self-ty-and-trait.rs:10:27
|
||||
|
|
||||
LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(bare_trait_objects)]` on by default
|
||||
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
|
||||
help: use `dyn`
|
||||
|
|
||||
LL - impl<'a, T> Struct<T> for Trait<'a, T> {}
|
||||
LL + impl<'a, T> Struct<T> for dyn Trait<'a, T> {}
|
||||
|
|
||||
|
||||
error: aborting due to 3 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0404`.
|
Loading…
Reference in New Issue
Block a user