Skip to content

Commit

Permalink
Unrolled build for rust-lang#120570
Browse files Browse the repository at this point in the history
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>`.
  • Loading branch information
rust-timer committed Feb 4, 2024
2 parents 671eb38 + 5906237 commit a5e4623
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 14 deletions.
3 changes: 3 additions & 0 deletions compiler/rustc_resolve/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,9 @@ resolve_underscore_lifetime_name_cannot_be_used_here =
`'_` cannot be used here
.note = `'_` is a reserved lifetime name
resolve_unexpected_res_change_ty_to_const_param_sugg =
you might have meant to write a const parameter here
resolve_unreachable_label =
use of unreachable label `{$name}`
.label = unreachable label `{$name}`
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use rustc_errors::codes::*;
use rustc_errors::{codes::*, Applicability};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{
symbol::{Ident, Symbol},
Expand Down Expand Up @@ -787,3 +787,16 @@ pub(crate) struct IsNotDirectlyImportable {
pub(crate) span: Span,
pub(crate) target: Ident,
}

#[derive(Subdiagnostic)]
#[suggestion(
resolve_unexpected_res_change_ty_to_const_param_sugg,
code = "const ",
style = "verbose"
)]
pub(crate) struct UnexpectedResChangeTyToConstParamSugg {
#[primary_span]
pub span: Span,
#[applicability]
pub applicability: Applicability,
}
12 changes: 6 additions & 6 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,9 +594,9 @@ struct DiagnosticMetadata<'ast> {
/// The current trait (used to suggest).
current_item: Option<&'ast Item>,

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

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

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

self.diagnostic_metadata.currently_processing_generics = prev;
self.diagnostic_metadata.currently_processing_generic_args = prev;
return;
}
}
Expand All @@ -1113,7 +1113,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::No))
}
}
self.diagnostic_metadata.currently_processing_generics = prev;
self.diagnostic_metadata.currently_processing_generic_args = prev;
}

fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
Expand Down
66 changes: 59 additions & 7 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}

self.suggest_bare_struct_literal(&mut err);
self.suggest_changing_type_to_const_param(&mut err, res, source, span);

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

self.suggest_self_or_self_ref(&mut err, path, span);
self.detect_assoct_type_constraint_meant_as_path(&mut err, &base_error);
self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error);
if self.suggest_self_ty(&mut err, source, path, span)
|| self.suggest_self_value(&mut err, source, path, span)
{
Expand Down Expand Up @@ -491,7 +492,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
(err, candidates)
}

fn detect_assoct_type_constraint_meant_as_path(
fn detect_assoc_type_constraint_meant_as_path(
&self,
err: &mut Diagnostic,
base_error: &BaseError,
Expand Down Expand Up @@ -799,17 +800,19 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
false,
) = (source, res, is_macro)
{
if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
if let Some(bounds @ [first_bound, .., last_bound]) =
self.diagnostic_metadata.current_trait_object
{
fallback = true;
let spans: Vec<Span> = bounds
.iter()
.map(|bound| bound.span())
.filter(|&sp| sp != base_error.span)
.collect();

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

fn suggest_changing_type_to_const_param(
&mut self,
err: &mut Diagnostic,
res: Option<Res>,
source: PathSource<'_>,
span: Span,
) {
let PathSource::Trait(_) = source else { return };

// We don't include `DefKind::Str` and `DefKind::AssocTy` as they can't be reached here anyway.
let applicability = match res {
Some(Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_) | PrimTy::Bool | PrimTy::Char)) => {
Applicability::MachineApplicable
}
// FIXME(const_generics): Add `DefKind::TyParam` and `SelfTyParam` once we support generic
// const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the
// benefits of including them here outweighs the small number of false positives.
Some(Res::Def(DefKind::Struct | DefKind::Enum, _))
if self.r.tcx.features().adt_const_params =>
{
Applicability::MaybeIncorrect
}
_ => return,
};

let Some(item) = self.diagnostic_metadata.current_item else { return };
let Some(generics) = item.kind.generics() else { return };

let param = generics.params.iter().find_map(|param| {
// Only consider type params with exactly one trait bound.
if let [bound] = &*param.bounds
&& let ast::GenericBound::Trait(tref, ast::TraitBoundModifiers::NONE) = bound
&& tref.span == span
&& param.ident.span.eq_ctxt(span)
{
Some(param.ident.span)
} else {
None
}
});

if let Some(param) = param {
err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg {
span: param.shrink_to_lo(),
applicability,
});
}
}

fn suggest_pattern_match_with_let(
&mut self,
err: &mut Diagnostic,
Expand Down Expand Up @@ -2419,10 +2471,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let mut iter = ident.chars().map(|c| c.is_uppercase());
let single_uppercase_char =
matches!(iter.next(), Some(true)) && matches!(iter.next(), None);
if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char {
if !self.diagnostic_metadata.currently_processing_generic_args && !single_uppercase_char {
return None;
}
match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generics) {
match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generic_args) {
(Some(Item { kind: ItemKind::Fn(..), ident, .. }), _, _) if ident.name == sym::main => {
// Ignore `fn main()` as we don't want to suggest `fn main<T>()`
}
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/resolve/change-ty-to-const-param-sugg-0.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fn make<N: u32>() {}
//~^ ERROR expected trait, found builtin type `u32`
//~| HELP you might have meant to write a const parameter here

struct Array<N: usize>([bool; N]);
//~^ ERROR expected trait, found builtin type `usize`
//~| HELP you might have meant to write a const parameter here
//~| ERROR expected value, found type parameter `N`

fn main() {}
34 changes: 34 additions & 0 deletions tests/ui/resolve/change-ty-to-const-param-sugg-0.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
error[E0404]: expected trait, found builtin type `u32`
--> $DIR/change-ty-to-const-param-sugg-0.rs:1:12
|
LL | fn make<N: u32>() {}
| ^^^ not a trait
|
help: you might have meant to write a const parameter here
|
LL | fn make<const N: u32>() {}
| +++++

error[E0404]: expected trait, found builtin type `usize`
--> $DIR/change-ty-to-const-param-sugg-0.rs:5:17
|
LL | struct Array<N: usize>([bool; N]);
| ^^^^^ not a trait
|
help: you might have meant to write a const parameter here
|
LL | struct Array<const N: usize>([bool; N]);
| +++++

error[E0423]: expected value, found type parameter `N`
--> $DIR/change-ty-to-const-param-sugg-0.rs:5:31
|
LL | struct Array<N: usize>([bool; N]);
| - ^ not a value
| |
| found this type parameter

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0404, E0423.
For more information about an error, try `rustc --explain E0404`.
24 changes: 24 additions & 0 deletions tests/ui/resolve/change-ty-to-const-param-sugg-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#![feature(adt_const_params)]
#![allow(incomplete_features)]

use std::marker::ConstParamTy;

struct Tagged<T: Tag, O: Options>;
//~^ ERROR expected trait, found enum `Tag`
//~| HELP you might have meant to write a const parameter here
//~| ERROR expected trait, found struct `Options`
//~| HELP you might have meant to write a const parameter here

#[derive(PartialEq, Eq, ConstParamTy)]
enum Tag {
One,
Two,
}

#[derive(PartialEq, Eq, ConstParamTy)]
struct Options {
verbose: bool,
safe: bool,
}

fn main() {}
25 changes: 25 additions & 0 deletions tests/ui/resolve/change-ty-to-const-param-sugg-1.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
error[E0404]: expected trait, found enum `Tag`
--> $DIR/change-ty-to-const-param-sugg-1.rs:6:18
|
LL | struct Tagged<T: Tag, O: Options>;
| ^^^ not a trait
|
help: you might have meant to write a const parameter here
|
LL | struct Tagged<const T: Tag, O: Options>;
| +++++

error[E0404]: expected trait, found struct `Options`
--> $DIR/change-ty-to-const-param-sugg-1.rs:6:26
|
LL | struct Tagged<T: Tag, O: Options>;
| ^^^^^^^ not a trait
|
help: you might have meant to write a const parameter here
|
LL | struct Tagged<T: Tag, const O: Options>;
| +++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0404`.

0 comments on commit a5e4623

Please sign in to comment.