Skip to content

Support if-let guards in matches macros by using :guard matcher#156025

Open
SpriteOvO wants to merge 2 commits into
rust-lang:mainfrom
SpriteOvO:matches-guard
Open

Support if-let guards in matches macros by using :guard matcher#156025
SpriteOvO wants to merge 2 commits into
rust-lang:mainfrom
SpriteOvO:matches-guard

Conversation

@SpriteOvO
Copy link
Copy Markdown
Member

@SpriteOvO SpriteOvO commented May 1, 2026

Tracking issue #153104.

This PR replaces the original if $guard:expr with new matcher $guard:guard in macros matches! and assert_matches! to support the use of if-let guards syntax in these macros. This syntax is already stable in #141295 for match arms.

Please note that this PR directly applies :guard to macros that are already stable, so the support for if-let guards in these macros is instantly stable.

When using these macros that accept :guard, users will not be required to use nightly and enable #![feature(macro_guard_matcher)]. However, when defining macros with :guard, nightly and #![feature(macro_guard_matcher)] are still required. Therefore, I think a Crater run is needed.

cc @programmerjake
r? libs

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 1, 2026
@SpriteOvO
Copy link
Copy Markdown
Member Author

Please note that this PR directly applies :guard to macros that are already stable, so the support for if-let guards in these macros is instantly stable.

When using these macros that accept :guard, users will not be required to use nightly and enable #![feature(macro_guard_matcher)]. However, when defining macros with :guard, nightly and #![feature(macro_guard_matcher)] are still required. Therefore, I think a Crater run is needed.

Alternatively, to be more safe, we only provide the :guard version of macros when users activate macro_guard_matcher, otherwise falling back to the original if $e:expr version. But I couldn't find a way to write something like #[cfg(unstable_feature = "macro_guard_matcher")] in stdlib.

@Mark-Simulacrum Mark-Simulacrum added needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. S-waiting-on-t-libs-api Status: Awaiting decision from T-libs-api and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 9, 2026
@nia-e
Copy link
Copy Markdown
Member

nia-e commented May 12, 2026

Hi - could you provide us some examples of where this might be a breaking change? We discussed this in the libs-api meeting but it wasn't quite clear what this might affect

@SpriteOvO
Copy link
Copy Markdown
Member Author

NonterminalKind::Guard => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`{`"];
match tok {
TokenTree::Token(token) => match token.kind {
FatArrow | Comma | OpenBrace => IsInFollow::Yes,
_ => IsInFollow::No(TOKENS),
},
_ => IsInFollow::No(TOKENS),
}
}

@nia-e My main concern was in is_in_follow function, because the comment states it impacts future compatibility。 @fmease has also noted an unresolved question regarding this in the tracking issue. Let me quote it here and explain my thoughts alongside it:

  • (fmease writing) Should { really be in the follow set? I'm not quite sure it should.
    • The condition of match guards can be an "unrestricted" expressions precisely because the guard can only be followed by => contrary to the conditions of if & while expressions and the iterator of for loops which are expressions without struct expressions.
    • So while if S {} successfully parses as an expression (namely as if (S) {}), macro matcher $g:guard {} currently rejects if S {} as input because it parses if (S {}) and looks for extra { } which aren't there of course.

I took some time to rethink it, given that the original intent of this matcher was just to simplify matching match-guards, rather than to allow users to extend the syntax with custom rules. And strictly according to MatchArmGuard, { is indeed not supposed to follow it. In that case, removing it might be better, or at least a conservative choice.

The requested Crater run was also based on the potential impacts mentioned above, plus, it’s instantly stable. If we decide to remove { from the follow-set, is the Crater run still needed? (Tbh, this is my first time requesting a Crater run, I'm not quite sure if such a change is worth a run)

@nia-e nia-e added the I-lang-nominated Nominated for discussion during a lang team meeting. label May 26, 2026
@nia-e
Copy link
Copy Markdown
Member

nia-e commented May 26, 2026

We discussed this in today's @rust-lang/libs-api meeting - we're fine with this so long as lang is okay committing to these semantics. Thanks!

@traviscross traviscross added T-lang Relevant to the language team I-lang-radar Items that are on lang's radar and will need eventual work or consideration. P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang labels May 27, 2026
@scottmcm
Copy link
Copy Markdown
Member

The one concern I have here is that if stabilizing guard did find some kind of a problem in what it does, having it exposed in matches! would mean that that a breaking change to fix that problem would end up being a breaking change to the matches! macro itself, and thus potentially problematic. (Unimportant aside: which is distinct from if the library manually did it, which would be immune to any change to the unstable feature.)

But I really want the macro to use the guard matcher, so can we just stabilize the matcher at the same time? Let's get extra eyes on exactly the definition of the macro to make sure we didn't miss anything, and then once it's stable if there's any problems that just becomes a "well we need guard_2024+guard_2027 matchers" following the usual pattern for matcher changes over editions.

(Said on the assumption that there's nothing particularly tricky involved in the guard matcher itself and thus it shouldn't be materially more work to just write up stabilization for that since arguably we'd need to know what it's stabilizing to understand any breaking changes to the matches! macro anyway. I'm quite happy to not try to roll it up into some bigger "stabilize lots of new matchers" group, in fact. We have a specific use, we -- hopefully -- have the syntax it's matching described in the reference already anyway, so let's just lang-stabilize the new matcher along with the libs-api-stabilization of the macro update.)

@traviscross
Copy link
Copy Markdown
Contributor

Similar to what @scottmcm said, it'd seem best to me for us to commit to the semantics of the :guard macro matcher fragment specifier by stabilizing it. And in terms of maintaining a similar flavor across the language — as users experience it — I'd prefer to see matches! use :guard rather than implementing a distinct DSL.

@traviscross
Copy link
Copy Markdown
Contributor

traviscross commented May 27, 2026

Please also keep in mind rust-lang/rfcs#3637. What's the story on forward compatibility with guard patterns if we do this?

@traviscross traviscross removed I-lang-nominated Nominated for discussion during a lang team meeting. P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang labels May 27, 2026
@traviscross
Copy link
Copy Markdown
Contributor

@rustbot author

@rustbot rustbot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label May 27, 2026
@traviscross traviscross removed the S-waiting-on-t-libs-api Status: Awaiting decision from T-libs-api label May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

I-lang-radar Items that are on lang's radar and will need eventual work or consideration. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants