-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Implement RFC 3503: frontmatters #140035
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Implement RFC 3503: frontmatters #140035
Conversation
The job Click to see the possible cause of the failure (guessed by this bot)
|
I'll do a review pass next Monday/Tuesday, but in the meantime, I'll roll this to Wesley who I think have more context on the general vibes. r? @wesleywiser |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the implementation! I left some (adversarial) review notes under the impression based on reading back #137193 that frontmatter is a Rust language syntax. However, the existing diagnostics here I find is already quite nice.
I especially appreciate using error annotations in between frontmatter openers/closers, I found that very clever (and cute) 😆
let mut cursor = Cursor::new(input); | ||
let mut cursor = Cursor::new(input, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit (readability): I find this at call sites somewhat hard to understand. Maybe introduce an enum like FrontmatterAllowed::{Yes,No}
explicitly?
--- cargo | ||
//~^ ERROR: invalid infostring for frontmatter | ||
--- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question [FRONT-TERM 1/2]: wait, why is this rejected? My reading of the RFC text
Opens with 3+ dashes followed by 0+ whitespace, an optional term (one or more characters excluding whitespace and commas), 0+ whitespace, and a newline
is that ---cargo
and --- cargo
and --- cargo
are considered valid due to "opens with 3+ dashes followed by 0+ whitespace" ? 🤔 Maybe I'm misreading it? As in, my interpretation of this grammar is sth like (EBNF-esque syntax)
frontmatter start = three or more dashes , [ whitespaces ] , [ term ] , [ whitespaces ] , '\n'
where each of the whitespaces
and term
are optional.
(See also [FRONT-TERM 2/2], I think this as described in the RFC text is ambiguous)
LL | --- cargo | ||
| ^^^^^^ | ||
| | ||
= note: frontmatter infostrings must be a single identifier immediately following the opening |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question [FRONT-TERM 2/2]: (Adversarial review, thinking out loud here)
and re. this diagnostics, my reading of the RFC is that all the following are considered "valid" openers:
---
no infostring likecargo
or whatever, w.r.t. "an optional term"---cargo
or--- cargo
or--- cargo
infostrings ("term" is what the RFC uses I guess), "0+ whitespace" between---
andcargo
--- -
: note the whitespace between---
and the "term" here-
. The RFC says "an optional term (one or more characters excluding whitespace and commas)" which notably does not exclude-
.
And these are considered "invalid" openers:
---,
,--- ,
: violates "excluding whitespace and commas"--- a b
: space between "term" characters--- edition2024,no_run
: comma between "term" characters
Was this changed after the RFC was accepted? As in, my interpretation of the "term" is that it's only (EBNF-esque syntax)
term = { all characters - ( whitespace | ',' ) }
where { .. }
indicates repetition. Notably, it accepts -
.
Hmm, actually, isn't this ambiguous? For instance, take the following opener
----\n
can be considered:- "3+ dashes" (4 in fact), optional 0+ whitespace (take 0), optional term (none), optional 0+ whitespace (take 0), and a newline
- But it can also be considered 3 dashes followed by optional 0+ whitespace (take 0), an optional term (one or more characters excluding whitespace and commas) (take
-
as the character), optional 0+ whitespace (take 0), and a newline
🤔
#![feature(frontmatter)] | ||
|
||
--- | ||
//~^ ERROR: expected item, found `-` | ||
// FIXME(frontmatter): make this diagnostic better | ||
--- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remark: yeah, I'm not sure how to detect this properly without making some convoluted logic, even though I imagine this would be one of the more common mistakes to make. At least this does error, maybe we could provide some kind of contextual HELP like if we see ---
(3+ starting dashes)
error: expected item, found `-`
--> $DIR/frontmatter-after-tokens.rs:3:1
|
LL | ---
| ^ expected item
|
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
= help: if you meant to write a frontmatter, the frontmatter must come after an optional shebang but before any regular source code
(With some better wording, I find it tricky to explain)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Words are hard 🙂
If the file doesn't start with a shebang line, maybe we could just say something like
= help: if you meant to write a frontmatter, the frontmatter must appear first in the file
Shebangs are not super commonly used so if we can leave that detail out, it would simplify the error message.
/// Frontmatter `---` blocks for use by external tools. | ||
(unstable, frontmatter, "CURRENT_RUSTC_VERSION", Some(136889)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussion: (stealing this to force an inline comment, not about this line of code itself)
Some positive/negative test coverage that you may or may not want to consider (but not necessarily blocking for this initial PR, but may be blockers prior to stabilization):
- How does frontmatter interact with
include!()
?- Maybe also a smoke test for interactions with
file!()
/line!()
?
- Maybe also a smoke test for interactions with
- (Probably not for this PR) How does frontmatter interact with
-Zunpretty
as mentioned by @fmease in Add unstable frontmatter support #137193 (comment)? - (A stretch) maybe a positive smoke test that the offsets are correctly reflected in an example debuginfo test? But I guess that might be overkill since the span offsets should already be handled by that time.
- (Before stabilization) we should add a run-make test that exercises how cargo and rustc works together w.r.t. frontmatter, depending on what the final cooperation scheme we end up using.
- (Before stabilization) we should add a positive smoke test to check that rustfix is able to account for frontmatters (or properly ignore), i.e.
//@ run-rustfix
.
/// Frontmatter `---` blocks for use by external tools. | ||
(unstable, frontmatter, "CURRENT_RUSTC_VERSION", Some(136889)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussion (meta, not necessarily for this PR): hm, frontmatter is going to be interesting when it comes to cooking it sufficiently for stabilization. Like rustfmt
, clippy
, rust-analyzer
, cargo
might all at least need to learn how to account for (or properly ignore) frontmatters in source files, since it's a language syntax and not just sth tools can be expected to naively strip away prior to passing a modified source file to rustc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion (meta): it'd also be quite helpful if you could add a brief comment for each of these frontmatter tests regarding their intention. I can guess of their intention, but I still need to stare at them (and compare against the RFC text) for a few moments.
☔ The latest upstream changes (presumably #140180) made this pull request unmergeable. Please resolve the merge conflicts. |
} | ||
|
||
if !found { | ||
// recovery strategy: a closing statement might have precending whitespace/newline |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks reasonable! If we don't find a ---
, perhaps we could also look for a use
statement or a crate attribute or a //!
doc comment as these might plausibly be expected to often follow a frontmatter block.
#![feature(frontmatter)] | ||
|
||
--- | ||
//~^ ERROR: expected item, found `-` | ||
// FIXME(frontmatter): make this diagnostic better | ||
--- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Words are hard 🙂
If the file doesn't start with a shebang line, maybe we could just say something like
= help: if you meant to write a frontmatter, the frontmatter must appear first in the file
Shebangs are not super commonly used so if we can leave that detail out, it would simplify the error message.
Supercedes #137193. This implements RFC 3503.
This might break rust-analyzer. Will look into how to fix that.
Suggestions welcome for how to improve diagnostics.