Skip to content

Commit a5e4623

Browse files
authored
Unrolled build for rust-lang#120570
Rollup merge of rust-lang#120570 - fmease:change-ty-to-ct-param-sugg, r=compiler-errors Suggest changing type to const parameters if we encounter a type in the trait bound position The first commit is just drive-by cleanup. Provide a structured suggestion if the user forgot to prefix a “const parameter” with `const`, e.g., in `struct Tagged<TAG: u64>;`. This happens to me from time to time. Maybe C++ devs are also prone to this mistake given template syntax looks like `template<typename T, uint32_t N>`.
2 parents 671eb38 + 5906237 commit a5e4623

8 files changed

+175
-14
lines changed

compiler/rustc_resolve/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,9 @@ resolve_underscore_lifetime_name_cannot_be_used_here =
289289
`'_` cannot be used here
290290
.note = `'_` is a reserved lifetime name
291291
292+
resolve_unexpected_res_change_ty_to_const_param_sugg =
293+
you might have meant to write a const parameter here
294+
292295
resolve_unreachable_label =
293296
use of unreachable label `{$name}`
294297
.label = unreachable label `{$name}`

compiler/rustc_resolve/src/errors.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_errors::codes::*;
1+
use rustc_errors::{codes::*, Applicability};
22
use rustc_macros::{Diagnostic, Subdiagnostic};
33
use rustc_span::{
44
symbol::{Ident, Symbol},
@@ -787,3 +787,16 @@ pub(crate) struct IsNotDirectlyImportable {
787787
pub(crate) span: Span,
788788
pub(crate) target: Ident,
789789
}
790+
791+
#[derive(Subdiagnostic)]
792+
#[suggestion(
793+
resolve_unexpected_res_change_ty_to_const_param_sugg,
794+
code = "const ",
795+
style = "verbose"
796+
)]
797+
pub(crate) struct UnexpectedResChangeTyToConstParamSugg {
798+
#[primary_span]
799+
pub span: Span,
800+
#[applicability]
801+
pub applicability: Applicability,
802+
}

compiler/rustc_resolve/src/late.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -594,9 +594,9 @@ struct DiagnosticMetadata<'ast> {
594594
/// The current trait (used to suggest).
595595
current_item: Option<&'ast Item>,
596596

597-
/// When processing generics and encountering a type not found, suggest introducing a type
598-
/// param.
599-
currently_processing_generics: bool,
597+
/// When processing generic arguments and encountering an unresolved ident not found,
598+
/// suggest introducing a type or const param depending on the context.
599+
currently_processing_generic_args: bool,
600600

601601
/// The current enclosing (non-closure) function (used for better errors).
602602
current_function: Option<(FnKind<'ast>, Span)>,
@@ -1069,7 +1069,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
10691069

10701070
fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
10711071
debug!("visit_generic_arg({:?})", arg);
1072-
let prev = replace(&mut self.diagnostic_metadata.currently_processing_generics, true);
1072+
let prev = replace(&mut self.diagnostic_metadata.currently_processing_generic_args, true);
10731073
match arg {
10741074
GenericArg::Type(ref ty) => {
10751075
// We parse const arguments as path types as we cannot distinguish them during
@@ -1100,7 +1100,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
11001100
},
11011101
);
11021102

1103-
self.diagnostic_metadata.currently_processing_generics = prev;
1103+
self.diagnostic_metadata.currently_processing_generic_args = prev;
11041104
return;
11051105
}
11061106
}
@@ -1113,7 +1113,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
11131113
self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::No))
11141114
}
11151115
}
1116-
self.diagnostic_metadata.currently_processing_generics = prev;
1116+
self.diagnostic_metadata.currently_processing_generic_args = prev;
11171117
}
11181118

11191119
fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {

compiler/rustc_resolve/src/late/diagnostics.rs

+59-7
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
444444
}
445445

446446
self.suggest_bare_struct_literal(&mut err);
447+
self.suggest_changing_type_to_const_param(&mut err, res, source, span);
447448

448449
if self.suggest_pattern_match_with_let(&mut err, source, span) {
449450
// Fallback label.
@@ -452,7 +453,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
452453
}
453454

454455
self.suggest_self_or_self_ref(&mut err, path, span);
455-
self.detect_assoct_type_constraint_meant_as_path(&mut err, &base_error);
456+
self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error);
456457
if self.suggest_self_ty(&mut err, source, path, span)
457458
|| self.suggest_self_value(&mut err, source, path, span)
458459
{
@@ -491,7 +492,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
491492
(err, candidates)
492493
}
493494

494-
fn detect_assoct_type_constraint_meant_as_path(
495+
fn detect_assoc_type_constraint_meant_as_path(
495496
&self,
496497
err: &mut Diagnostic,
497498
base_error: &BaseError,
@@ -799,17 +800,19 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
799800
false,
800801
) = (source, res, is_macro)
801802
{
802-
if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
803+
if let Some(bounds @ [first_bound, .., last_bound]) =
804+
self.diagnostic_metadata.current_trait_object
805+
{
803806
fallback = true;
804807
let spans: Vec<Span> = bounds
805808
.iter()
806809
.map(|bound| bound.span())
807810
.filter(|&sp| sp != base_error.span)
808811
.collect();
809812

810-
let start_span = bounds[0].span();
813+
let start_span = first_bound.span();
811814
// `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
812-
let end_span = bounds.last().unwrap().span();
815+
let end_span = last_bound.span();
813816
// `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
814817
let last_bound_span = spans.last().cloned().unwrap();
815818
let mut multi_span: MultiSpan = spans.clone().into();
@@ -1136,6 +1139,55 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
11361139
}
11371140
}
11381141

1142+
fn suggest_changing_type_to_const_param(
1143+
&mut self,
1144+
err: &mut Diagnostic,
1145+
res: Option<Res>,
1146+
source: PathSource<'_>,
1147+
span: Span,
1148+
) {
1149+
let PathSource::Trait(_) = source else { return };
1150+
1151+
// We don't include `DefKind::Str` and `DefKind::AssocTy` as they can't be reached here anyway.
1152+
let applicability = match res {
1153+
Some(Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_) | PrimTy::Bool | PrimTy::Char)) => {
1154+
Applicability::MachineApplicable
1155+
}
1156+
// FIXME(const_generics): Add `DefKind::TyParam` and `SelfTyParam` once we support generic
1157+
// const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the
1158+
// benefits of including them here outweighs the small number of false positives.
1159+
Some(Res::Def(DefKind::Struct | DefKind::Enum, _))
1160+
if self.r.tcx.features().adt_const_params =>
1161+
{
1162+
Applicability::MaybeIncorrect
1163+
}
1164+
_ => return,
1165+
};
1166+
1167+
let Some(item) = self.diagnostic_metadata.current_item else { return };
1168+
let Some(generics) = item.kind.generics() else { return };
1169+
1170+
let param = generics.params.iter().find_map(|param| {
1171+
// Only consider type params with exactly one trait bound.
1172+
if let [bound] = &*param.bounds
1173+
&& let ast::GenericBound::Trait(tref, ast::TraitBoundModifiers::NONE) = bound
1174+
&& tref.span == span
1175+
&& param.ident.span.eq_ctxt(span)
1176+
{
1177+
Some(param.ident.span)
1178+
} else {
1179+
None
1180+
}
1181+
});
1182+
1183+
if let Some(param) = param {
1184+
err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg {
1185+
span: param.shrink_to_lo(),
1186+
applicability,
1187+
});
1188+
}
1189+
}
1190+
11391191
fn suggest_pattern_match_with_let(
11401192
&mut self,
11411193
err: &mut Diagnostic,
@@ -2419,10 +2471,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
24192471
let mut iter = ident.chars().map(|c| c.is_uppercase());
24202472
let single_uppercase_char =
24212473
matches!(iter.next(), Some(true)) && matches!(iter.next(), None);
2422-
if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char {
2474+
if !self.diagnostic_metadata.currently_processing_generic_args && !single_uppercase_char {
24232475
return None;
24242476
}
2425-
match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generics) {
2477+
match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generic_args) {
24262478
(Some(Item { kind: ItemKind::Fn(..), ident, .. }), _, _) if ident.name == sym::main => {
24272479
// Ignore `fn main()` as we don't want to suggest `fn main<T>()`
24282480
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
fn make<N: u32>() {}
2+
//~^ ERROR expected trait, found builtin type `u32`
3+
//~| HELP you might have meant to write a const parameter here
4+
5+
struct Array<N: usize>([bool; N]);
6+
//~^ ERROR expected trait, found builtin type `usize`
7+
//~| HELP you might have meant to write a const parameter here
8+
//~| ERROR expected value, found type parameter `N`
9+
10+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error[E0404]: expected trait, found builtin type `u32`
2+
--> $DIR/change-ty-to-const-param-sugg-0.rs:1:12
3+
|
4+
LL | fn make<N: u32>() {}
5+
| ^^^ not a trait
6+
|
7+
help: you might have meant to write a const parameter here
8+
|
9+
LL | fn make<const N: u32>() {}
10+
| +++++
11+
12+
error[E0404]: expected trait, found builtin type `usize`
13+
--> $DIR/change-ty-to-const-param-sugg-0.rs:5:17
14+
|
15+
LL | struct Array<N: usize>([bool; N]);
16+
| ^^^^^ not a trait
17+
|
18+
help: you might have meant to write a const parameter here
19+
|
20+
LL | struct Array<const N: usize>([bool; N]);
21+
| +++++
22+
23+
error[E0423]: expected value, found type parameter `N`
24+
--> $DIR/change-ty-to-const-param-sugg-0.rs:5:31
25+
|
26+
LL | struct Array<N: usize>([bool; N]);
27+
| - ^ not a value
28+
| |
29+
| found this type parameter
30+
31+
error: aborting due to 3 previous errors
32+
33+
Some errors have detailed explanations: E0404, E0423.
34+
For more information about an error, try `rustc --explain E0404`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(adt_const_params)]
2+
#![allow(incomplete_features)]
3+
4+
use std::marker::ConstParamTy;
5+
6+
struct Tagged<T: Tag, O: Options>;
7+
//~^ ERROR expected trait, found enum `Tag`
8+
//~| HELP you might have meant to write a const parameter here
9+
//~| ERROR expected trait, found struct `Options`
10+
//~| HELP you might have meant to write a const parameter here
11+
12+
#[derive(PartialEq, Eq, ConstParamTy)]
13+
enum Tag {
14+
One,
15+
Two,
16+
}
17+
18+
#[derive(PartialEq, Eq, ConstParamTy)]
19+
struct Options {
20+
verbose: bool,
21+
safe: bool,
22+
}
23+
24+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0404]: expected trait, found enum `Tag`
2+
--> $DIR/change-ty-to-const-param-sugg-1.rs:6:18
3+
|
4+
LL | struct Tagged<T: Tag, O: Options>;
5+
| ^^^ not a trait
6+
|
7+
help: you might have meant to write a const parameter here
8+
|
9+
LL | struct Tagged<const T: Tag, O: Options>;
10+
| +++++
11+
12+
error[E0404]: expected trait, found struct `Options`
13+
--> $DIR/change-ty-to-const-param-sugg-1.rs:6:26
14+
|
15+
LL | struct Tagged<T: Tag, O: Options>;
16+
| ^^^^^^^ not a trait
17+
|
18+
help: you might have meant to write a const parameter here
19+
|
20+
LL | struct Tagged<T: Tag, const O: Options>;
21+
| +++++
22+
23+
error: aborting due to 2 previous errors
24+
25+
For more information about this error, try `rustc --explain E0404`.

0 commit comments

Comments
 (0)