Skip to content

Commit aed6884

Browse files
committed
Implement comparison of InvisibleOrigin without PartialEq
1 parent 84a1747 commit aed6884

File tree

7 files changed

+66
-27
lines changed

7 files changed

+66
-27
lines changed

compiler/rustc_ast/src/attr/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,9 @@ impl AttrItem {
269269

270270
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
271271
match &self.args {
272-
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
272+
AttrArgs::Delimited(args)
273+
if args.delim.eq_special_invisible_origin(&Delimiter::Parenthesis) =>
274+
{
273275
MetaItemKind::list_from_tokens(args.tokens.clone())
274276
}
275277
AttrArgs::Delimited(_) | AttrArgs::Eq { .. } | AttrArgs::Empty => None,

compiler/rustc_ast/src/token.rs

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ pub enum CommentKind {
2222
Block,
2323
}
2424

25-
// This type must not implement `Hash` due to the unusual `PartialEq` impl below.
26-
#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)]
25+
#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
2726
pub enum InvisibleOrigin {
2827
// From the expansion of a metavariable in a declarative macro.
2928
MetaVar(MetaVarKind),
@@ -45,20 +44,6 @@ impl InvisibleOrigin {
4544
}
4645
}
4746

48-
impl PartialEq for InvisibleOrigin {
49-
#[inline]
50-
fn eq(&self, _other: &InvisibleOrigin) -> bool {
51-
// When we had AST-based nonterminals we couldn't compare them, and the
52-
// old `Nonterminal` type had an `eq` that always returned false,
53-
// resulting in this restriction:
54-
// https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment
55-
// This `eq` emulates that behaviour. We could consider lifting this
56-
// restriction now but there are still cases involving invisible
57-
// delimiters that make it harder than it first appears.
58-
false
59-
}
60-
}
61-
6247
/// Annoyingly similar to `NonterminalKind`, but the slight differences are important.
6348
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
6449
pub enum MetaVarKind {
@@ -114,7 +99,7 @@ impl fmt::Display for MetaVarKind {
11499
/// Describes how a sequence of token trees is delimited.
115100
/// Cannot use `proc_macro::Delimiter` directly because this
116101
/// structure should implement some additional traits.
117-
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
102+
#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)]
118103
pub enum Delimiter {
119104
/// `( ... )`
120105
Parenthesis,
@@ -130,6 +115,20 @@ pub enum Delimiter {
130115
Invisible(InvisibleOrigin),
131116
}
132117

118+
impl PartialEq for Delimiter {
119+
fn eq(&self, other: &Self) -> bool {
120+
match (self, other) {
121+
(Delimiter::Parenthesis, Delimiter::Parenthesis) => true,
122+
(Delimiter::Brace, Delimiter::Brace) => true,
123+
(Delimiter::Bracket, Delimiter::Bracket) => true,
124+
(Delimiter::Invisible(_), _) | (_, Delimiter::Invisible(_)) => {
125+
panic!("Comparing an invisible delimiter using PartialEq");
126+
}
127+
_ => false,
128+
}
129+
}
130+
}
131+
133132
impl Delimiter {
134133
// Should the parser skip these delimiters? Only happens for certain kinds
135134
// of invisible delimiters. Ideally this function will eventually disappear
@@ -142,7 +141,8 @@ impl Delimiter {
142141
}
143142
}
144143

145-
// This exists because `InvisibleOrigin`s should be compared. It is only used for assertions.
144+
// This exists because `InvisibleOrigin`s should not be compared. It is only used for
145+
// assertions.
146146
pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool {
147147
match (self, other) {
148148
(Delimiter::Parenthesis, Delimiter::Parenthesis) => true,
@@ -153,6 +153,18 @@ impl Delimiter {
153153
}
154154
}
155155

156+
/// Compare two delimiters while always considering invisible delimiters to NOT be equal
157+
/// to anything else.
158+
pub fn eq_special_invisible_origin(&self, other: &Delimiter) -> bool {
159+
match (self, other) {
160+
(Delimiter::Parenthesis, Delimiter::Parenthesis) => true,
161+
(Delimiter::Brace, Delimiter::Brace) => true,
162+
(Delimiter::Bracket, Delimiter::Bracket) => true,
163+
(Delimiter::Invisible(_), _) | (_, Delimiter::Invisible(_)) => false,
164+
_ => false,
165+
}
166+
}
167+
156168
pub fn as_open_token_kind(&self) -> TokenKind {
157169
match *self {
158170
Delimiter::Parenthesis => OpenParen,

compiler/rustc_ast/src/tokenstream.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl TokenTree {
4848
match (self, other) {
4949
(TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind,
5050
(TokenTree::Delimited(.., delim, tts), TokenTree::Delimited(.., delim2, tts2)) => {
51-
delim == delim2
51+
delim.eq_special_invisible_origin(delim2)
5252
&& tts.len() == tts2.len()
5353
&& tts.iter().zip(tts2.iter()).all(|(a, b)| a.eq_unspanned(b))
5454
}

compiler/rustc_ast/src/util/classify.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ pub fn expr_is_complete(e: &ast::Expr) -> bool {
7777
/// ```
7878
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
7979
match &e.kind {
80-
MacCall(mac_call) => mac_call.args.delim != Delimiter::Brace,
80+
MacCall(mac_call) => !mac_call.args.delim.eq_special_invisible_origin(&Delimiter::Brace),
8181
_ => !expr_is_complete(e),
8282
}
8383
}
@@ -209,7 +209,8 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
209209
}
210210

211211
MacCall(mac) => {
212-
break (mac.args.delim == Delimiter::Brace).then_some(TrailingBrace::MacCall(mac));
212+
break (mac.args.delim.eq_special_invisible_origin(&Delimiter::Brace))
213+
.then_some(TrailingBrace::MacCall(mac));
213214
}
214215

215216
InlineAsm(_) | OffsetOf(_, _) | IncludedBytes(_) | FormatArgs(_) => {
@@ -252,7 +253,8 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
252253
loop {
253254
match &ty.kind {
254255
ast::TyKind::MacCall(mac) => {
255-
break (mac.args.delim == Delimiter::Brace).then_some(mac);
256+
break (mac.args.delim.eq_special_invisible_origin(&Delimiter::Brace))
257+
.then_some(mac);
256258
}
257259

258260
ast::TyKind::Ptr(mut_ty)

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
795795
convert_dollar_crate: bool,
796796
span: Span,
797797
) {
798-
let cb = (delim == Delimiter::Brace).then(|| self.cbox(INDENT_UNIT));
798+
let cb =
799+
delim.eq_special_invisible_origin(&Delimiter::Brace).then(|| self.cbox(INDENT_UNIT));
799800
match header {
800801
Some(MacHeader::Path(path)) => self.print_path(path, false, 0),
801802
Some(MacHeader::Keyword(kw)) => self.word(kw),

compiler/rustc_expand/src/mbe/macro_parser.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ use std::rc::Rc;
7777

7878
pub(crate) use NamedMatch::*;
7979
pub(crate) use ParseResult::*;
80-
use rustc_ast::token::{self, DocComment, NonterminalKind, Token};
80+
use rustc_ast::token::{self, DocComment, NonterminalKind, Token, TokenKind};
8181
use rustc_data_structures::fx::FxHashMap;
8282
use rustc_errors::ErrorGuaranteed;
8383
use rustc_lint_defs::pluralize;
@@ -397,7 +397,29 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool {
397397
{
398398
ident1.name == ident2.name && is_raw1 == is_raw2
399399
} else {
400-
t1.kind == t2.kind
400+
// Note: we SHOULD NOT use `t1.kind == t2.kind` here, and we should instead compare the
401+
// tokens using the special comparison function.
402+
compare_token_kind(t1.kind, t2.kind)
403+
}
404+
}
405+
406+
/// Compares two token kinds while making sure that variants containing `InvisibleOrigin` will
407+
/// never compare equal to one another.
408+
///
409+
/// When we had AST-based nonterminals we couldn't compare them, and the
410+
/// old `Nonterminal` type had an `eq` that always returned false,
411+
/// resulting in this restriction:
412+
/// <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment>
413+
/// This comparison logic emulates that behaviour. We could consider lifting this
414+
/// restriction now but there are still cases involving invisible
415+
/// delimiters that make it harder than it first appears.
416+
fn compare_token_kind(t1: TokenKind, t2: TokenKind) -> bool {
417+
match (t1, t2) {
418+
(TokenKind::OpenInvisible(_), _)
419+
| (TokenKind::CloseInvisible(_), _)
420+
| (_, TokenKind::CloseInvisible(_))
421+
| (_, TokenKind::OpenInvisible(_)) => false,
422+
(a, b) => a == b,
401423
}
402424
}
403425

compiler/rustc_expand/src/mbe/transcribe.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ pub(super) fn transcribe<'a>(
223223
FrameKind::Delimited { delim, span, mut spacing, .. } => {
224224
// Hack to force-insert a space after `]` in certain case.
225225
// See discussion of the `hex-literal` crate in #114571.
226-
if delim == Delimiter::Bracket {
226+
if delim.eq_special_invisible_origin(&Delimiter::Bracket) {
227227
spacing.close = Spacing::Alone;
228228
}
229229
if tscx.result_stack.is_empty() {

0 commit comments

Comments
 (0)