More accurately handle suggestions
* Confirm the path segment being modified is an `enum` * Check whether type has type param before suggesting changing `Self` * Wording changes * Add clarifying comments * Suggest removing args from `Self` if the type doesn't have type params
This commit is contained in:
parent
9b2d80a197
commit
532671b8ee
@ -1803,52 +1803,84 @@ pub fn associated_path_to_ty(
|
|||||||
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
|
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
|
||||||
self.prohibit_generics(slice::from_ref(assoc_segment).iter(), |err| {
|
self.prohibit_generics(slice::from_ref(assoc_segment).iter(), |err| {
|
||||||
err.note("enum variants can't have type parameters");
|
err.note("enum variants can't have type parameters");
|
||||||
let type_name = tcx.opt_item_name(adt_def.did());
|
let type_name = tcx.item_name(adt_def.did());
|
||||||
let the_enum = type_name.map(|n| format!("enum `{n}`")).unwrap_or_else(|| "the enum".to_string());
|
let msg = format!(
|
||||||
let msg = format!("you might have meant to specity type parameters on {the_enum}");
|
"you might have meant to specity type parameters on enum \
|
||||||
|
`{type_name}`"
|
||||||
|
);
|
||||||
let Some(args) = assoc_segment.args else { return; };
|
let Some(args) = assoc_segment.args else { return; };
|
||||||
|
// Get the span of the generics args *including* the leading `::`.
|
||||||
let args_span = assoc_segment.ident.span.shrink_to_hi().to(args.span_ext);
|
let args_span = assoc_segment.ident.span.shrink_to_hi().to(args.span_ext);
|
||||||
|
if tcx.generics_of(adt_def.did()).count() == 0 {
|
||||||
|
// FIXME(estebank): we could also verify that the arguments being
|
||||||
|
// work for the `enum`, instead of just looking if it takes *any*.
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
args_span,
|
||||||
|
&format!("{type_name} doesn't have type parameters"),
|
||||||
|
String::new(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
|
let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
|
||||||
err.note(&msg);
|
err.note(&msg);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let (qself_sugg_span, is_self) = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind {
|
let (qself_sugg_span, is_self) = if let hir::TyKind::Path(
|
||||||
|
hir::QPath::Resolved(_, ref path)
|
||||||
|
) = qself.kind {
|
||||||
// If the path segment already has type params, we want to overwrite
|
// If the path segment already has type params, we want to overwrite
|
||||||
// them.
|
// them.
|
||||||
match &path.segments[..] {
|
match &path.segments[..] {
|
||||||
[.., segment, _] => (
|
// `segment` is the previous to last element on the path,
|
||||||
segment.ident.span.shrink_to_hi().to(segment.args.map_or(
|
// which would normally be the `enum` itself, while the last
|
||||||
segment.ident.span.shrink_to_hi(),
|
// `_` `PathSegment` corresponds to the variant.
|
||||||
|
[.., hir::PathSegment {
|
||||||
|
ident,
|
||||||
|
args,
|
||||||
|
res: Some(Res::Def(DefKind::Enum, _)),
|
||||||
|
..
|
||||||
|
}, _] => (
|
||||||
|
// We need to include the `::` in `Type::Variant::<Args>`
|
||||||
|
// to point the span to `::<Args>`, not just `<Args>`.
|
||||||
|
ident.span.shrink_to_hi().to(args.map_or(
|
||||||
|
ident.span.shrink_to_hi(),
|
||||||
|a| a.span_ext)),
|
|a| a.span_ext)),
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
[segment] => (
|
[segment] => (
|
||||||
|
// We need to include the `::` in `Type::Variant::<Args>`
|
||||||
|
// to point the span to `::<Args>`, not just `<Args>`.
|
||||||
segment.ident.span.shrink_to_hi().to(segment.args.map_or(
|
segment.ident.span.shrink_to_hi().to(segment.args.map_or(
|
||||||
segment.ident.span.shrink_to_hi(),
|
segment.ident.span.shrink_to_hi(),
|
||||||
|a| a.span_ext)),
|
|a| a.span_ext)),
|
||||||
kw::SelfUpper == segment.ident.name,
|
kw::SelfUpper == segment.ident.name,
|
||||||
),
|
),
|
||||||
_ => unreachable!(),
|
_ => {
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err.note(&msg);
|
err.note(&msg);
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
let Some(type_name) = type_name else {
|
}
|
||||||
|
} else {
|
||||||
err.note(&msg);
|
err.note(&msg);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let suggestion = vec![
|
let suggestion = vec![
|
||||||
if is_self {
|
if is_self {
|
||||||
// Account for people writing `Self::Variant::<Args>`, where
|
// Account for people writing `Self::Variant::<Args>`, where
|
||||||
// `Self` is the enum.
|
// `Self` is the enum, and suggest replacing `Self` with the
|
||||||
|
// appropriate type: `Type::<Args>::Variant`.
|
||||||
(qself.span, format!("{type_name}{snippet}"))
|
(qself.span, format!("{type_name}{snippet}"))
|
||||||
} else {
|
} else {
|
||||||
(qself_sugg_span, snippet)
|
(qself_sugg_span, snippet)
|
||||||
},
|
},
|
||||||
(args_span, String::new()),
|
(args_span, String::new()),
|
||||||
];
|
];
|
||||||
err.multipart_suggestion_verbose(&msg, suggestion, Applicability::MaybeIncorrect);
|
err.multipart_suggestion_verbose(
|
||||||
|
&msg,
|
||||||
|
suggestion,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
|
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
|
||||||
} else {
|
} else {
|
||||||
@ -2369,8 +2401,6 @@ pub fn res_to_ty(
|
|||||||
// Try to evaluate any array length constants.
|
// Try to evaluate any array length constants.
|
||||||
let ty = tcx.at(span).type_of(def_id);
|
let ty = tcx.at(span).type_of(def_id);
|
||||||
let span_of_impl = tcx.span_of_impl(def_id);
|
let span_of_impl = tcx.span_of_impl(def_id);
|
||||||
// TODO: confirm that `def_id`'s type accepts type params at all before suggesting
|
|
||||||
// using that instead.
|
|
||||||
self.prohibit_generics(path.segments.iter(), |err| {
|
self.prohibit_generics(path.segments.iter(), |err| {
|
||||||
let def_id = match *ty.kind() {
|
let def_id = match *ty.kind() {
|
||||||
ty::Adt(self_def, _) => self_def.did(),
|
ty::Adt(self_def, _) => self_def.did(),
|
||||||
@ -2379,22 +2409,41 @@ pub fn res_to_ty(
|
|||||||
|
|
||||||
let type_name = tcx.item_name(def_id);
|
let type_name = tcx.item_name(def_id);
|
||||||
let span_of_ty = tcx.def_ident_span(def_id);
|
let span_of_ty = tcx.def_ident_span(def_id);
|
||||||
|
let generics = tcx.generics_of(def_id).count();
|
||||||
|
|
||||||
let msg = format!("the `Self` type is `{ty}`");
|
let msg = format!("`Self` is of type `{ty}`");
|
||||||
if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
|
if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
|
||||||
let i_sp = tcx.sess.source_map().guess_head_span(i_sp);
|
let i_sp = tcx.sess.source_map().guess_head_span(i_sp);
|
||||||
let mut span: MultiSpan = vec![t_sp].into();
|
let mut span: MultiSpan = vec![t_sp].into();
|
||||||
span.push_span_label(
|
span.push_span_label(
|
||||||
i_sp,
|
i_sp,
|
||||||
&format!("`Self` is `{type_name}` in this `impl`"),
|
&format!("`Self` is or type `{type_name}` in this `impl`"),
|
||||||
|
);
|
||||||
|
let mut postfix = "";
|
||||||
|
if generics == 0 {
|
||||||
|
postfix = ", which doesn't have type parameters";
|
||||||
|
}
|
||||||
|
span.push_span_label(
|
||||||
|
t_sp,
|
||||||
|
&format!("`Self` corresponds to this type{postfix}"),
|
||||||
);
|
);
|
||||||
span.push_span_label(t_sp, "`Self` corresponds to this type");
|
|
||||||
err.span_note(span, &msg);
|
err.span_note(span, &msg);
|
||||||
} else {
|
} else {
|
||||||
err.note(&msg);
|
err.note(&msg);
|
||||||
}
|
}
|
||||||
for segment in path.segments {
|
for segment in path.segments {
|
||||||
if let Some(_args) = segment.args && segment.ident.name == kw::SelfUpper {
|
if let Some(args) = segment.args && segment.ident.name == kw::SelfUpper {
|
||||||
|
if generics == 0 {
|
||||||
|
// FIXME(estebank): we could also verify that the arguments being
|
||||||
|
// work for the `enum`, instead of just looking if it takes *any*.
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
segment.ident.span.shrink_to_hi().to(args.span_ext),
|
||||||
|
"the `Self` type doesn't accept type parameters",
|
||||||
|
String::new(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
segment.ident.span,
|
segment.ident.span,
|
||||||
format!(
|
format!(
|
||||||
@ -2407,6 +2456,7 @@ pub fn res_to_ty(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// HACK(min_const_generics): Forbid generic `Self` types
|
// HACK(min_const_generics): Forbid generic `Self` types
|
||||||
// here as we can't easily do that during nameres.
|
// here as we can't easily do that during nameres.
|
||||||
|
@ -34,18 +34,19 @@ error[E0109]: type arguments are not allowed for this type
|
|||||||
LL | let z = Self::<u8> {};
|
LL | let z = Self::<u8> {};
|
||||||
| ^^ type argument not allowed
|
| ^^ type argument not allowed
|
||||||
|
|
|
|
||||||
note: the `Self` type is `S`
|
note: `Self` is of type `S`
|
||||||
--> $DIR/struct-path-self.rs:1:8
|
--> $DIR/struct-path-self.rs:1:8
|
||||||
|
|
|
|
||||||
LL | struct S;
|
LL | struct S;
|
||||||
| ^ `Self` corresponds to this type
|
| ^ `Self` corresponds to this type, which doesn't have type parameters
|
||||||
...
|
...
|
||||||
LL | impl Tr for S {
|
LL | impl Tr for S {
|
||||||
| ------------- `Self` is `S` in this `impl`
|
| ------------- `Self` is or type `S` in this `impl`
|
||||||
help: the `Self` type doesn't accept type parameters, use the concrete type's name `S` instead if you want to specify its type parameters
|
help: the `Self` type doesn't accept type parameters
|
||||||
|
|
|
||||||
|
LL - let z = Self::<u8> {};
|
||||||
|
LL + let z = Self {};
|
||||||
|
|
|
|
||||||
LL | let z = S::<u8> {};
|
|
||||||
| ~
|
|
||||||
|
|
||||||
error[E0109]: type arguments are not allowed for this type
|
error[E0109]: type arguments are not allowed for this type
|
||||||
--> $DIR/struct-path-self.rs:30:24
|
--> $DIR/struct-path-self.rs:30:24
|
||||||
@ -53,18 +54,19 @@ error[E0109]: type arguments are not allowed for this type
|
|||||||
LL | let z = Self::<u8> {};
|
LL | let z = Self::<u8> {};
|
||||||
| ^^ type argument not allowed
|
| ^^ type argument not allowed
|
||||||
|
|
|
|
||||||
note: the `Self` type is `S`
|
note: `Self` is of type `S`
|
||||||
--> $DIR/struct-path-self.rs:1:8
|
--> $DIR/struct-path-self.rs:1:8
|
||||||
|
|
|
|
||||||
LL | struct S;
|
LL | struct S;
|
||||||
| ^ `Self` corresponds to this type
|
| ^ `Self` corresponds to this type, which doesn't have type parameters
|
||||||
...
|
...
|
||||||
LL | impl S {
|
LL | impl S {
|
||||||
| ------ `Self` is `S` in this `impl`
|
| ------ `Self` is or type `S` in this `impl`
|
||||||
help: the `Self` type doesn't accept type parameters, use the concrete type's name `S` instead if you want to specify its type parameters
|
help: the `Self` type doesn't accept type parameters
|
||||||
|
|
|
||||||
|
LL - let z = Self::<u8> {};
|
||||||
|
LL + let z = Self {};
|
||||||
|
|
|
|
||||||
LL | let z = S::<u8> {};
|
|
||||||
| ~
|
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
@ -29,14 +29,14 @@ error[E0109]: type arguments are not allowed for this type
|
|||||||
LL | Self::<()>::TSVariant(());
|
LL | Self::<()>::TSVariant(());
|
||||||
| ^^ type argument not allowed
|
| ^^ type argument not allowed
|
||||||
|
|
|
|
||||||
note: the `Self` type is `Enum<T>`
|
note: `Self` is of type `Enum<T>`
|
||||||
--> $DIR/enum-variant-generic-args.rs:7:6
|
--> $DIR/enum-variant-generic-args.rs:7:6
|
||||||
|
|
|
|
||||||
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
|
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
|
||||||
| ^^^^ `Self` corresponds to this type
|
| ^^^^ `Self` corresponds to this type
|
||||||
...
|
...
|
||||||
LL | impl<T> Enum<T> {
|
LL | impl<T> Enum<T> {
|
||||||
| --------------- `Self` is `Enum` in this `impl`
|
| --------------- `Self` is or type `Enum` in this `impl`
|
||||||
help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
|
help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
|
||||||
|
|
|
|
||||||
LL | Enum::<()>::TSVariant(());
|
LL | Enum::<()>::TSVariant(());
|
||||||
@ -67,14 +67,14 @@ error[E0109]: type arguments are not allowed for this type
|
|||||||
LL | Self::<()>::TSVariant::<()>(());
|
LL | Self::<()>::TSVariant::<()>(());
|
||||||
| ^^ type argument not allowed
|
| ^^ type argument not allowed
|
||||||
|
|
|
|
||||||
note: the `Self` type is `Enum<T>`
|
note: `Self` is of type `Enum<T>`
|
||||||
--> $DIR/enum-variant-generic-args.rs:7:6
|
--> $DIR/enum-variant-generic-args.rs:7:6
|
||||||
|
|
|
|
||||||
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
|
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
|
||||||
| ^^^^ `Self` corresponds to this type
|
| ^^^^ `Self` corresponds to this type
|
||||||
...
|
...
|
||||||
LL | impl<T> Enum<T> {
|
LL | impl<T> Enum<T> {
|
||||||
| --------------- `Self` is `Enum` in this `impl`
|
| --------------- `Self` is or type `Enum` in this `impl`
|
||||||
help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
|
help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
|
||||||
|
|
|
|
||||||
LL | Enum::<()>::TSVariant::<()>(());
|
LL | Enum::<()>::TSVariant::<()>(());
|
||||||
@ -129,14 +129,14 @@ error[E0109]: type arguments are not allowed for this type
|
|||||||
LL | Self::<()>::SVariant { v: () };
|
LL | Self::<()>::SVariant { v: () };
|
||||||
| ^^ type argument not allowed
|
| ^^ type argument not allowed
|
||||||
|
|
|
|
||||||
note: the `Self` type is `Enum<T>`
|
note: `Self` is of type `Enum<T>`
|
||||||
--> $DIR/enum-variant-generic-args.rs:7:6
|
--> $DIR/enum-variant-generic-args.rs:7:6
|
||||||
|
|
|
|
||||||
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
|
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
|
||||||
| ^^^^ `Self` corresponds to this type
|
| ^^^^ `Self` corresponds to this type
|
||||||
...
|
...
|
||||||
LL | impl<T> Enum<T> {
|
LL | impl<T> Enum<T> {
|
||||||
| --------------- `Self` is `Enum` in this `impl`
|
| --------------- `Self` is or type `Enum` in this `impl`
|
||||||
help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
|
help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
|
||||||
|
|
|
|
||||||
LL | Enum::<()>::SVariant { v: () };
|
LL | Enum::<()>::SVariant { v: () };
|
||||||
@ -160,14 +160,14 @@ error[E0109]: type arguments are not allowed for this type
|
|||||||
LL | Self::<()>::SVariant::<()> { v: () };
|
LL | Self::<()>::SVariant::<()> { v: () };
|
||||||
| ^^ type argument not allowed
|
| ^^ type argument not allowed
|
||||||
|
|
|
|
||||||
note: the `Self` type is `Enum<T>`
|
note: `Self` is of type `Enum<T>`
|
||||||
--> $DIR/enum-variant-generic-args.rs:7:6
|
--> $DIR/enum-variant-generic-args.rs:7:6
|
||||||
|
|
|
|
||||||
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
|
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
|
||||||
| ^^^^ `Self` corresponds to this type
|
| ^^^^ `Self` corresponds to this type
|
||||||
...
|
...
|
||||||
LL | impl<T> Enum<T> {
|
LL | impl<T> Enum<T> {
|
||||||
| --------------- `Self` is `Enum` in this `impl`
|
| --------------- `Self` is or type `Enum` in this `impl`
|
||||||
help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
|
help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
|
||||||
|
|
|
|
||||||
LL | Enum::<()>::SVariant::<()> { v: () };
|
LL | Enum::<()>::SVariant::<()> { v: () };
|
||||||
@ -210,14 +210,14 @@ error[E0109]: type arguments are not allowed for this type
|
|||||||
LL | Self::<()>::UVariant;
|
LL | Self::<()>::UVariant;
|
||||||
| ^^ type argument not allowed
|
| ^^ type argument not allowed
|
||||||
|
|
|
|
||||||
note: the `Self` type is `Enum<T>`
|
note: `Self` is of type `Enum<T>`
|
||||||
--> $DIR/enum-variant-generic-args.rs:7:6
|
--> $DIR/enum-variant-generic-args.rs:7:6
|
||||||
|
|
|
|
||||||
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
|
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
|
||||||
| ^^^^ `Self` corresponds to this type
|
| ^^^^ `Self` corresponds to this type
|
||||||
...
|
...
|
||||||
LL | impl<T> Enum<T> {
|
LL | impl<T> Enum<T> {
|
||||||
| --------------- `Self` is `Enum` in this `impl`
|
| --------------- `Self` is or type `Enum` in this `impl`
|
||||||
help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
|
help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
|
||||||
|
|
|
|
||||||
LL | Enum::<()>::UVariant;
|
LL | Enum::<()>::UVariant;
|
||||||
@ -229,14 +229,14 @@ error[E0109]: type arguments are not allowed for this type
|
|||||||
LL | Self::<()>::UVariant::<()>;
|
LL | Self::<()>::UVariant::<()>;
|
||||||
| ^^ type argument not allowed
|
| ^^ type argument not allowed
|
||||||
|
|
|
|
||||||
note: the `Self` type is `Enum<T>`
|
note: `Self` is of type `Enum<T>`
|
||||||
--> $DIR/enum-variant-generic-args.rs:7:6
|
--> $DIR/enum-variant-generic-args.rs:7:6
|
||||||
|
|
|
|
||||||
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
|
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
|
||||||
| ^^^^ `Self` corresponds to this type
|
| ^^^^ `Self` corresponds to this type
|
||||||
...
|
...
|
||||||
LL | impl<T> Enum<T> {
|
LL | impl<T> Enum<T> {
|
||||||
| --------------- `Self` is `Enum` in this `impl`
|
| --------------- `Self` is or type `Enum` in this `impl`
|
||||||
help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
|
help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
|
||||||
|
|
|
|
||||||
LL | Enum::<()>::UVariant::<()>;
|
LL | Enum::<()>::UVariant::<()>;
|
||||||
|
Loading…
Reference in New Issue
Block a user