Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_errors/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3544,6 +3544,8 @@ pub fn detect_confusion_type(sm: &SourceMap, suggested: &str, sp: Span) -> Confu
let mut has_digit_letter_confusable = false;
let mut has_other_diff = false;

// Letters whose lowercase version is very similar to the uppercase
// version.
let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z'];

let digit_letter_confusables = [('0', 'O'), ('1', 'l'), ('5', 'S'), ('8', 'B'), ('9', 'g')];
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ parse_keyword_lifetime =
lifetimes cannot use keyword names

parse_kw_bad_case = keyword `{$kw}` is written in the wrong case
.suggestion = write it in the correct case
.suggestion = write it in {$case}

parse_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item}
parse_label_unexpected_token = unexpected token
Expand Down
23 changes: 21 additions & 2 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// ignore-tidy-filelength

use std::borrow::Cow;
use std::path::PathBuf;

use rustc_ast::token::Token;
use rustc_ast::util::parser::ExprPrecedence;
use rustc_ast::{Path, Visibility};
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic,
SuggestionStyle,
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg,
Level, Subdiagnostic, SuggestionStyle,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_session::errors::ExprParenthesesNeeded;
Expand Down Expand Up @@ -3335,6 +3336,24 @@ pub(crate) struct KwBadCase<'a> {
#[suggestion(code = "{kw}", style = "verbose", applicability = "machine-applicable")]
pub span: Span,
pub kw: &'a str,
pub case: Case,
}

pub(crate) enum Case {
Upper,
Lower,
Mixed,
}

impl IntoDiagArg for Case {
fn into_diag_arg(self, path: &mut Option<PathBuf>) -> DiagArgValue {
match self {
Case::Upper => "uppercase",
Case::Lower => "lowercase",
Case::Mixed => "the correct case",
}
.into_diag_arg(path)
}
}

#[derive(Diagnostic)]
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,20 @@ impl<'a> Parser<'a> {
// Do an ASCII case-insensitive match, because all keywords are ASCII.
&& ident.as_str().eq_ignore_ascii_case(exp.kw.as_str())
{
self.dcx().emit_err(errors::KwBadCase { span: ident.span, kw: exp.kw.as_str() });
let kw = exp.kw.as_str();
let is_upper = kw.chars().all(char::is_uppercase);
let is_lower = kw.chars().all(char::is_lowercase);

let case = match (is_upper, is_lower) {
(true, true) => {
unreachable!("keyword that is both fully upper- and fully lowercase")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This triggers on empty keywords. Though I'm not sure if that's possible, I guess not? We were getting rid of the empty identifier anyway so I don't think we need to worry about it.

}
(true, false) => errors::Case::Upper,
(false, true) => errors::Case::Lower,
(false, false) => errors::Case::Mixed,
};

self.dcx().emit_err(errors::KwBadCase { span: ident.span, kw, case });
self.bump();
true
} else {
Expand Down
28 changes: 14 additions & 14 deletions tests/ui/parser/item-kw-case-mismatch.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: keyword `use` is written in the wrong case
LL | Use std::ptr::read;
| ^^^
|
help: write it in the correct case (notice the capitalization)
help: write it in lowercase (notice the capitalization)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the notice the capitalization bit is here because the misspelled keyword has letters that whose capitalization is hard to notice (for instance, u and U are similar, kinda).

i do think it's a good thing and it should be kept because it reinforces the fact that some extra attention is needed in order to spot the mistake.

|
LL - Use std::ptr::read;
LL + use std::ptr::read;
Expand All @@ -16,7 +16,7 @@ error: keyword `use` is written in the wrong case
LL | USE std::ptr::write;
| ^^^
|
help: write it in the correct case
help: write it in lowercase
|
LL - USE std::ptr::write;
LL + use std::ptr::write;
Expand All @@ -28,7 +28,7 @@ error: keyword `fn` is written in the wrong case
LL | async Fn _a() {}
| ^^
|
help: write it in the correct case (notice the capitalization)
help: write it in lowercase (notice the capitalization)
|
LL - async Fn _a() {}
LL + async fn _a() {}
Expand All @@ -40,7 +40,7 @@ error: keyword `fn` is written in the wrong case
LL | Fn _b() {}
| ^^
|
help: write it in the correct case (notice the capitalization)
help: write it in lowercase (notice the capitalization)
|
LL - Fn _b() {}
LL + fn _b() {}
Expand All @@ -52,7 +52,7 @@ error: keyword `async` is written in the wrong case
LL | aSYNC fN _c() {}
| ^^^^^
|
help: write it in the correct case
help: write it in lowercase
|
LL - aSYNC fN _c() {}
LL + async fN _c() {}
Expand All @@ -64,7 +64,7 @@ error: keyword `fn` is written in the wrong case
LL | aSYNC fN _c() {}
| ^^
|
help: write it in the correct case
help: write it in lowercase
|
LL - aSYNC fN _c() {}
LL + aSYNC fn _c() {}
Expand All @@ -76,7 +76,7 @@ error: keyword `async` is written in the wrong case
LL | Async fn _d() {}
| ^^^^^
|
help: write it in the correct case
help: write it in lowercase
|
LL - Async fn _d() {}
LL + async fn _d() {}
Expand All @@ -88,7 +88,7 @@ error: keyword `const` is written in the wrong case
LL | CONST UNSAFE FN _e() {}
| ^^^^^
|
help: write it in the correct case
help: write it in lowercase
|
LL - CONST UNSAFE FN _e() {}
LL + const UNSAFE FN _e() {}
Expand All @@ -100,7 +100,7 @@ error: keyword `unsafe` is written in the wrong case
LL | CONST UNSAFE FN _e() {}
| ^^^^^^
|
help: write it in the correct case
help: write it in lowercase
|
LL - CONST UNSAFE FN _e() {}
LL + CONST unsafe FN _e() {}
Expand All @@ -112,7 +112,7 @@ error: keyword `fn` is written in the wrong case
LL | CONST UNSAFE FN _e() {}
| ^^
|
help: write it in the correct case
help: write it in lowercase
|
LL - CONST UNSAFE FN _e() {}
LL + CONST UNSAFE fn _e() {}
Expand All @@ -124,7 +124,7 @@ error: keyword `unsafe` is written in the wrong case
LL | unSAFE EXTern "C" fn _f() {}
| ^^^^^^
|
help: write it in the correct case
help: write it in lowercase
|
LL - unSAFE EXTern "C" fn _f() {}
LL + unsafe EXTern "C" fn _f() {}
Expand All @@ -136,7 +136,7 @@ error: keyword `extern` is written in the wrong case
LL | unSAFE EXTern "C" fn _f() {}
| ^^^^^^
|
help: write it in the correct case
help: write it in lowercase
|
LL - unSAFE EXTern "C" fn _f() {}
LL + unSAFE extern "C" fn _f() {}
Expand All @@ -148,7 +148,7 @@ error: keyword `extern` is written in the wrong case
LL | EXTERN "C" FN _g() {}
| ^^^^^^
|
help: write it in the correct case
help: write it in lowercase
|
LL - EXTERN "C" FN _g() {}
LL + extern "C" FN _g() {}
Expand All @@ -160,7 +160,7 @@ error: keyword `fn` is written in the wrong case
LL | EXTERN "C" FN _g() {}
| ^^
|
help: write it in the correct case
help: write it in lowercase
|
LL - EXTERN "C" FN _g() {}
LL + EXTERN "C" fn _g() {}
Expand Down
Loading