Cleanup error messages, improve docstrings
This commit is contained in:
parent
629e97a5a0
commit
c15f86b4b3
8 changed files with 48 additions and 30 deletions
|
@ -41,7 +41,7 @@ impl<'a> Cursor<'a> {
|
||||||
/// If requested position doesn't exist, `EOF_CHAR` is returned.
|
/// If requested position doesn't exist, `EOF_CHAR` is returned.
|
||||||
/// However, getting `EOF_CHAR` doesn't always mean actual end of file,
|
/// However, getting `EOF_CHAR` doesn't always mean actual end of file,
|
||||||
/// it should be checked with `is_eof` method.
|
/// it should be checked with `is_eof` method.
|
||||||
pub(crate) fn nth_char(&self, n: usize) -> char {
|
fn nth_char(&self, n: usize) -> char {
|
||||||
self.chars().nth(n).unwrap_or(EOF_CHAR)
|
self.chars().nth(n).unwrap_or(EOF_CHAR)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,25 +141,41 @@ pub enum LiteralKind {
|
||||||
RawByteStr(UnvalidatedRawStr),
|
RawByteStr(UnvalidatedRawStr),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents something that looks like a raw string, but may have some
|
||||||
|
/// problems. Use `.validate()` to convert it into something
|
||||||
|
/// usable.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct UnvalidatedRawStr {
|
pub struct UnvalidatedRawStr {
|
||||||
|
/// The prefix (`r###"`) is valid
|
||||||
valid_start: bool,
|
valid_start: bool,
|
||||||
|
/// The number of leading `#`
|
||||||
n_start_hashes: usize,
|
n_start_hashes: usize,
|
||||||
|
/// The number of trailing `#`. `n_end_hashes` <= `n_start_hashes`
|
||||||
n_end_hashes: usize,
|
n_end_hashes: usize,
|
||||||
|
/// The offset starting at `r` or `br` where the user may have intended to end the string.
|
||||||
|
/// Currently, it is the longest sequence of pattern `"#+"`.
|
||||||
possible_terminator_offset: Option<usize>,
|
possible_terminator_offset: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error produced validating a raw string. Represents cases like:
|
||||||
|
/// - `r##~"abcde"##`: `LexRawStrError::InvalidStarter`
|
||||||
|
/// - `r###"abcde"##`: `LexRawStrError::NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)`
|
||||||
|
/// - Too many `#`s (>65536): `TooManyDelimiters`
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum LexRawStrError {
|
pub enum LexRawStrError {
|
||||||
/// Non # characters between `r` and `"` eg. `r#~"..`
|
/// Non `#` characters exist between `r` and `"` eg. `r#~"..`
|
||||||
InvalidStarter,
|
InvalidStarter,
|
||||||
/// The string was never terminated. `possible_terminator_offset` is the best guess of where they
|
/// The string was never terminated. `possible_terminator_offset` is the number of characters after `r` or `br` where they
|
||||||
/// may have intended to terminate it.
|
/// may have intended to terminate it.
|
||||||
NoTerminator { expected: usize, found: usize, possible_terminator_offset: Option<usize> },
|
NoTerminator { expected: usize, found: usize, possible_terminator_offset: Option<usize> },
|
||||||
/// More than 65536 # signs
|
/// More than 65536 `#`s exist.
|
||||||
TooManyDelimiters,
|
TooManyDelimiters,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Raw String that contains a valid prefix (`#+"`) and postfix (`"#+`) where
|
||||||
|
/// there are a matching number of `#` characters in both. Note that this will
|
||||||
|
/// not consume extra trailing `#` characters: `r###"abcde"####` is lexed as a
|
||||||
|
/// `ValidatedRawString { n_hashes: 3 }` followed by a `#` token.
|
||||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||||
pub struct ValidatedRawStr {
|
pub struct ValidatedRawStr {
|
||||||
n_hashes: u16,
|
n_hashes: u16,
|
||||||
|
@ -172,29 +188,28 @@ impl ValidatedRawStr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnvalidatedRawStr {
|
impl UnvalidatedRawStr {
|
||||||
pub fn started(&self) -> bool {
|
|
||||||
self.valid_start
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validate(self) -> Result<ValidatedRawStr, LexRawStrError> {
|
pub fn validate(self) -> Result<ValidatedRawStr, LexRawStrError> {
|
||||||
if !self.valid_start {
|
if !self.valid_start {
|
||||||
return Err(LexRawStrError::InvalidStarter);
|
return Err(LexRawStrError::InvalidStarter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only up to 65535 `#`s are allowed in raw strings
|
||||||
let n_start_safe: u16 =
|
let n_start_safe: u16 =
|
||||||
self.n_start_hashes.try_into().map_err(|_| LexRawStrError::TooManyDelimiters)?;
|
self.n_start_hashes.try_into().map_err(|_| LexRawStrError::TooManyDelimiters)?;
|
||||||
match (self.n_start_hashes, self.n_end_hashes) {
|
|
||||||
(n_start, n_end) if n_start > n_end => Err(LexRawStrError::NoTerminator {
|
if self.n_start_hashes > self.n_end_hashes {
|
||||||
expected: n_start,
|
Err(LexRawStrError::NoTerminator {
|
||||||
|
expected: self.n_start_hashes,
|
||||||
found: self.n_end_hashes,
|
found: self.n_end_hashes,
|
||||||
possible_terminator_offset: self.possible_terminator_offset,
|
possible_terminator_offset: self.possible_terminator_offset,
|
||||||
}),
|
})
|
||||||
(n_start, n_end) => {
|
} else {
|
||||||
debug_assert_eq!(n_start, n_end);
|
// Since the lexer should never produce a literal with n_end > n_start, if n_start <= n_end,
|
||||||
|
// they must be equal.
|
||||||
|
debug_assert_eq!(self.n_start_hashes, self.n_end_hashes);
|
||||||
Ok(ValidatedRawStr { n_hashes: n_start_safe })
|
Ok(ValidatedRawStr { n_hashes: n_start_safe })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Base of numeric literal encoding according to its prefix.
|
/// Base of numeric literal encoding according to its prefix.
|
||||||
|
@ -656,7 +671,7 @@ impl Cursor<'_> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Eats the double-quoted string an UnvalidatedRawStr
|
/// Eats the double-quoted string and returns an `UnvalidatedRawStr`.
|
||||||
fn raw_double_quoted_string(&mut self, prefix_len: usize) -> UnvalidatedRawStr {
|
fn raw_double_quoted_string(&mut self, prefix_len: usize) -> UnvalidatedRawStr {
|
||||||
debug_assert!(self.prev() == 'r');
|
debug_assert!(self.prev() == 'r');
|
||||||
let mut valid_start: bool = false;
|
let mut valid_start: bool = false;
|
||||||
|
|
|
@ -533,13 +533,12 @@ impl<'a> StringReader<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(possible_offset) = possible_offset {
|
if let Some(possible_offset) = possible_offset {
|
||||||
let span = self.mk_sp(
|
let lo = start + BytePos(possible_offset as u32);
|
||||||
start + BytePos(possible_offset as u32),
|
let hi = lo + BytePos(found_terminators as u32);
|
||||||
start + BytePos(possible_offset as u32) + BytePos(found_terminators as u32),
|
let span = self.mk_sp(lo, hi);
|
||||||
);
|
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
span,
|
span,
|
||||||
"you might have intended to terminate the string here",
|
"consider terminating the string here",
|
||||||
"#".repeat(n_hashes),
|
"#".repeat(n_hashes),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#![feature(crate_visibility_modifier)]
|
#![feature(crate_visibility_modifier)]
|
||||||
#![feature(bindings_after_at)]
|
#![feature(bindings_after_at)]
|
||||||
#![feature(try_blocks)]
|
#![feature(try_blocks)]
|
||||||
|
#![feature(or_patterns)]
|
||||||
|
|
||||||
use rustc_ast::ast;
|
use rustc_ast::ast;
|
||||||
use rustc_ast::token::{self, Nonterminal};
|
use rustc_ast::token::{self, Nonterminal};
|
||||||
|
|
|
@ -288,9 +288,12 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
fn check_too_many_raw_str_terminators(&mut self, err: &mut DiagnosticBuilder<'_>) -> bool {
|
fn check_too_many_raw_str_terminators(&mut self, err: &mut DiagnosticBuilder<'_>) -> bool {
|
||||||
let prev_token_raw_str = match self.prev_token {
|
let prev_token_raw_str = match self.prev_token {
|
||||||
Token { kind: TokenKind::Literal(Lit { kind: LitKind::StrRaw(n), .. }), .. } => Some(n),
|
|
||||||
Token {
|
Token {
|
||||||
kind: TokenKind::Literal(Lit { kind: LitKind::ByteStrRaw(n), .. }), ..
|
kind:
|
||||||
|
TokenKind::Literal(Lit {
|
||||||
|
kind: LitKind::StrRaw(n) | LitKind::ByteStrRaw(n), ..
|
||||||
|
}),
|
||||||
|
..
|
||||||
} => Some(n),
|
} => Some(n),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
@ -300,11 +303,11 @@ impl<'a> Parser<'a> {
|
||||||
err.set_primary_message("too many `#` when terminating raw string");
|
err.set_primary_message("too many `#` when terminating raw string");
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
self.token.span,
|
self.token.span,
|
||||||
"Remove the extra `#`",
|
"remove the extra `#`",
|
||||||
String::new(),
|
String::new(),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
err.note(&format!("The raw string started with {} `#`s", n_hashes));
|
err.note(&format!("the raw string started with {} `#`s", n_hashes));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ error[E0748]: unterminated raw string
|
||||||
--> $DIR/raw-byte-string-eof.rs:2:5
|
--> $DIR/raw-byte-string-eof.rs:2:5
|
||||||
|
|
|
|
||||||
LL | br##"a"#;
|
LL | br##"a"#;
|
||||||
| ^ - help: you might have intended to terminate the string here: `##`
|
| ^ - help: consider terminating the string here: `##`
|
||||||
| |
|
| |
|
||||||
| unterminated raw string
|
| unterminated raw string
|
||||||
|
|
|
|
||||||
|
|
|
@ -2,9 +2,9 @@ error: too many `#` when terminating raw string
|
||||||
--> $DIR/raw-str-unbalanced.rs:3:9
|
--> $DIR/raw-str-unbalanced.rs:3:9
|
||||||
|
|
|
|
||||||
LL | "##
|
LL | "##
|
||||||
| ^ help: Remove the extra `#`
|
| ^ help: remove the extra `#`
|
||||||
|
|
|
|
||||||
= note: The raw string started with 1 `#`s
|
= note: the raw string started with 1 `#`s
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ error[E0748]: unterminated raw string
|
||||||
--> $DIR/raw_string.rs:2:13
|
--> $DIR/raw_string.rs:2:13
|
||||||
|
|
|
|
||||||
LL | let x = r##"lol"#;
|
LL | let x = r##"lol"#;
|
||||||
| ^ - help: you might have intended to terminate the string here: `##`
|
| ^ - help: consider terminating the string here: `##`
|
||||||
| |
|
| |
|
||||||
| unterminated raw string
|
| unterminated raw string
|
||||||
|
|
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue