Skip to content

Commit 1526233

Browse files
committed
Support lists and stylings in more places for rustc --explain
1 parent bda221a commit 1526233

File tree

5 files changed

+62
-37
lines changed

5 files changed

+62
-37
lines changed

compiler/rustc_error_codes/src/error_codes/E0373.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,4 @@ fn spawn<F: Future + Send + 'static>(future: F) {
7070

7171
Similarly to closures, `async` blocks are not executed immediately and may
7272
capture closed-over data by reference. For more information, see
73-
https://rust-lang.github.io/async-book/03_async_await/01_chapter.html.
73+
<https://rust-lang.github.io/async-book/03_async_await/01_chapter.html>.

compiler/rustc_error_codes/src/error_codes/E0378.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ where
2020

2121
The `DispatchFromDyn` trait currently can only be implemented for
2222
builtin pointer types and structs that are newtype wrappers around them
23-
— that is, the struct must have only one field (except for`PhantomData`),
23+
— that is, the struct must have only one field (except for `PhantomData`),
2424
and that field must itself implement `DispatchFromDyn`.
2525

2626
```

compiler/rustc_errors/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#![feature(box_patterns)]
1616
#![feature(error_reporter)]
1717
#![feature(extract_if)]
18+
#![feature(if_let_guard)]
1819
#![feature(let_chains)]
1920
#![feature(negative_impls)]
2021
#![feature(never_type)]

compiler/rustc_errors/src/markdown/parse.rs

+25-29
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,11 @@ const CBK: &[u8] = b"```";
1010
const CIL: &[u8] = b"`";
1111
const CMT_E: &[u8] = b"-->";
1212
const CMT_S: &[u8] = b"<!--";
13-
const EMP: &[u8] = b"_";
1413
const HDG: &[u8] = b"#";
1514
const LNK_CHARS: &str = "$-_.+!*'()/&?=:%";
1615
const LNK_E: &[u8] = b"]";
1716
const LNK_S: &[u8] = b"[";
18-
const STG: &[u8] = b"**";
1917
const STK: &[u8] = b"~~";
20-
const UL1: &[u8] = b"* ";
21-
const UL2: &[u8] = b"- ";
2218

2319
/// Pattern replacements
2420
const REPLACEMENTS: &[(&str, &str)] = &[
@@ -100,25 +96,26 @@ fn parse_recursive<'a>(buf: &'a [u8], ctx: Context) -> MdStream<'_> {
10096
};
10197

10298
let res: ParseResult<'_> = match (top_blk, prev) {
103-
(_, Newline | Whitespace) if loop_buf.starts_with(CMT_S) => {
99+
_ if loop_buf.starts_with(CMT_S) => {
104100
parse_simple_pat(loop_buf, CMT_S, CMT_E, Po::TrimNoEsc, MdTree::Comment)
105101
}
106102
(true, Newline) if loop_buf.starts_with(CBK) => Some(parse_codeblock(loop_buf)),
107-
(_, Newline | Whitespace) if loop_buf.starts_with(CIL) => parse_codeinline(loop_buf),
103+
_ if loop_buf.starts_with(CIL) => parse_codeinline(loop_buf),
108104
(true, Newline | Whitespace) if loop_buf.starts_with(HDG) => parse_heading(loop_buf),
109105
(true, Newline) if loop_buf.starts_with(BRK) => {
110106
Some((MdTree::HorizontalRule, parse_to_newline(loop_buf).1))
111107
}
112-
(_, Newline | Whitespace) if loop_buf.starts_with(EMP) => {
113-
parse_simple_pat(loop_buf, EMP, EMP, Po::None, MdTree::Emphasis)
108+
(_, Newline) if unordered_list_start(loop_buf) => Some(parse_unordered_li(loop_buf)),
109+
_ if let Some(strong @ (b"**" | b"__")) = loop_buf.get(..2) => {
110+
parse_simple_pat(loop_buf, strong, strong, Po::None, MdTree::Strong)
114111
}
115-
(_, Newline | Whitespace) if loop_buf.starts_with(STG) => {
116-
parse_simple_pat(loop_buf, STG, STG, Po::None, MdTree::Strong)
112+
_ if let Some(emph @ (b"*" | b"_")) = loop_buf.get(..1) => {
113+
parse_simple_pat(loop_buf, emph, emph, Po::None, MdTree::Emphasis)
117114
}
118-
(_, Newline | Whitespace) if loop_buf.starts_with(STK) => {
115+
_ if loop_buf.starts_with(STK) => {
119116
parse_simple_pat(loop_buf, STK, STK, Po::None, MdTree::Strikethrough)
120117
}
121-
(_, Newline | Whitespace) if loop_buf.starts_with(ANC_S) => {
118+
_ if loop_buf.starts_with(ANC_S) => {
122119
let tt_fn = |link| MdTree::Link { disp: link, link };
123120
let ret = parse_simple_pat(loop_buf, ANC_S, ANC_E, Po::None, tt_fn);
124121
match ret {
@@ -130,11 +127,8 @@ fn parse_recursive<'a>(buf: &'a [u8], ctx: Context) -> MdStream<'_> {
130127
_ => None,
131128
}
132129
}
133-
(_, Newline) if (loop_buf.starts_with(UL1) || loop_buf.starts_with(UL2)) => {
134-
Some(parse_unordered_li(loop_buf))
135-
}
136130
(_, Newline) if ord_list_start(loop_buf).is_some() => Some(parse_ordered_li(loop_buf)),
137-
(_, Newline | Whitespace) if loop_buf.starts_with(LNK_S) => {
131+
_ if loop_buf.starts_with(LNK_S) => {
138132
parse_any_link(loop_buf, top_blk && prev == Prev::Newline)
139133
}
140134
(_, Escape | _) => None,
@@ -251,7 +245,6 @@ fn parse_heading(buf: &[u8]) -> ParseResult<'_> {
251245

252246
/// Bulleted list
253247
fn parse_unordered_li(buf: &[u8]) -> Parsed<'_> {
254-
debug_assert!(buf.starts_with(b"* ") || buf.starts_with(b"- "));
255248
let (txt, rest) = get_indented_section(&buf[2..]);
256249
let ctx = Context { top_block: false, prev: Prev::Whitespace };
257250
let stream = parse_recursive(trim_ascii_start(txt), ctx);
@@ -267,25 +260,28 @@ fn parse_ordered_li(buf: &[u8]) -> Parsed<'_> {
267260
(MdTree::OrderedListItem(num, stream), rest)
268261
}
269262

270-
/// Find first line that isn't empty or doesn't start with whitespace, that will
271-
/// be our contents
272263
fn get_indented_section(buf: &[u8]) -> (&[u8], &[u8]) {
273-
let mut end = buf.len();
274-
for (idx, window) in buf.windows(2).enumerate() {
275-
let &[ch, next_ch] = window else { unreachable!("always 2 elements") };
276-
if idx >= buf.len().saturating_sub(2) && next_ch == b'\n' {
277-
// End of stream
278-
end = buf.len().saturating_sub(1);
279-
break;
280-
} else if ch == b'\n' && (!next_ch.is_ascii_whitespace() || next_ch == b'\n') {
281-
end = idx;
282-
break;
264+
let mut lines = buf.split(|&byte| byte == b'\n');
265+
let mut end = lines.next().map_or(0, |line| line.len());
266+
for line in lines {
267+
if let Some(first) = line.first() {
268+
if unordered_list_start(line) || !first.is_ascii_whitespace() {
269+
break;
270+
}
283271
}
272+
end += line.len() + 1;
284273
}
285274

286275
(&buf[..end], &buf[end..])
287276
}
288277

278+
fn unordered_list_start(mut buf: &[u8]) -> bool {
279+
while let [b' ', rest @ ..] = buf {
280+
buf = rest;
281+
}
282+
matches!(buf, [b'*' | b'-', b' ', ..])
283+
}
284+
289285
/// Verify a valid ordered list start (e.g. `1.`) and parse it. Returns the
290286
/// parsed number and offset of character after the dot.
291287
fn ord_list_start(buf: &[u8]) -> Option<(u16, usize)> {

compiler/rustc_errors/src/markdown/tests/parse.rs

+34-6
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ use ParseOpt as PO;
44
#[test]
55
fn test_parse_simple() {
66
let buf = "**abcd** rest";
7-
let (t, r) = parse_simple_pat(buf.as_bytes(), STG, STG, PO::None, MdTree::Strong).unwrap();
7+
let (t, r) = parse_simple_pat(buf.as_bytes(), b"**", b"**", PO::None, MdTree::Strong).unwrap();
88
assert_eq!(t, MdTree::Strong("abcd"));
99
assert_eq!(r, b" rest");
1010

1111
// Escaping should fail
1212
let buf = r"**abcd\** rest";
13-
let res = parse_simple_pat(buf.as_bytes(), STG, STG, PO::None, MdTree::Strong);
13+
let res = parse_simple_pat(buf.as_bytes(), b"**", b"**", PO::None, MdTree::Strong);
1414
assert!(res.is_none());
1515
}
1616

@@ -141,12 +141,12 @@ fn test_indented_section() {
141141
assert_eq!(str::from_utf8(r).unwrap(), "\nnot ind");
142142

143143
let (txt, rest) = get_indented_section(IND2.as_bytes());
144-
assert_eq!(str::from_utf8(txt).unwrap(), "test end of stream\n 1\n 2");
145-
assert_eq!(str::from_utf8(rest).unwrap(), "\n");
144+
assert_eq!(str::from_utf8(txt).unwrap(), "test end of stream\n 1\n 2\n");
145+
assert_eq!(str::from_utf8(rest).unwrap(), "");
146146

147147
let (txt, rest) = get_indented_section(IND3.as_bytes());
148-
assert_eq!(str::from_utf8(txt).unwrap(), "test empty lines\n 1\n 2");
149-
assert_eq!(str::from_utf8(rest).unwrap(), "\n\nnot ind");
148+
assert_eq!(str::from_utf8(txt).unwrap(), "test empty lines\n 1\n 2\n");
149+
assert_eq!(str::from_utf8(rest).unwrap(), "\nnot ind");
150150
}
151151

152152
const HBT: &str = r"# Heading
@@ -310,3 +310,31 @@ fn test_code_at_start() {
310310
let res = entrypoint(CODE_STARTLINE);
311311
assert_eq!(res, expected);
312312
}
313+
314+
#[test]
315+
fn test_code_in_parens() {
316+
let expected =
317+
vec![MdTree::PlainText("("), MdTree::CodeInline("Foo"), MdTree::PlainText(")")].into();
318+
let res = entrypoint("(`Foo`)");
319+
assert_eq!(res, expected);
320+
}
321+
322+
const LIST_WITH_SPACE: &str = "
323+
para
324+
* l1
325+
* l2
326+
";
327+
328+
#[test]
329+
fn test_list_with_space() {
330+
let expected = vec![
331+
MdTree::PlainText("para"),
332+
MdTree::ParagraphBreak,
333+
MdTree::UnorderedListItem(vec![MdTree::PlainText("l1")].into()),
334+
MdTree::LineBreak,
335+
MdTree::UnorderedListItem(vec![MdTree::PlainText("l2")].into()),
336+
]
337+
.into();
338+
let res = entrypoint(LIST_WITH_SPACE);
339+
assert_eq!(res, expected);
340+
}

0 commit comments

Comments
 (0)