minimally implement is
(RFC 3573), sans parsing
#144174
Open
+502
−23
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR partially implements rust-lang/rfcs#3573 for experimentation. It's not yet suitable for general use and may not yet reflect the intended design, but this should hopefully make it easier to explore its design space. r? @joshtriplett for design concerns
Placeholder syntax
Since
is
isn't parsed as an infix operator, I'm using permanently-unstablebuiltin#
syntax as a placeholder. Instead ofexpr is pat
, writebuiltin # is(expr is pat)
or define a macro expanding to that. One possible improvement if raw keywords (RFC 3098) were implemented would be to usek#is
as an infix operator. My understanding is that this syntax is already reserved by RFC 3101.Scoping
I've opted for a simple and restrictive interpretation of the scoping rules in the RFC, based on the rules for
let
-chains:I don't think this is necessarily the intended scope for
is
(or the ideal scope forlet
expressions in that first case, honestly), but my hope is that it will be easier to refine given a concrete implementation1. Lints or errors to prevent shadowing mistakes are left for future work.Desugaring
builtin # is(expr is pat)
is desugared as follows when lowering to HIR:let
expression would be permitted,expr is pat
desugars tolet pat = expr
.&&
-chain containing theis
is wrapped in anif
condition, thenis
is desugared tolet
:... && expr is pat &&...
becomesif ... && let pat = expr && ... { true } else { false }
.This results in non-ideal MIR in some cases, but jump-threading optimizations should hopefully clean it up. I haven't included any tests for that, since this implementation isn't meant for production use. This also doesn't currently enforce Rust 2024 scoping rules for
if
s in its desugaring; how to handle older editions is left as an open question.Behavior in macro expansions
I couldn't find discussion of macros on the RFC, so I've taken the simplest approach: it doesn't really work yet. Similar to
let
statements but unlikelet
expressions, you can putbuiltin # is($e is $p)
in a macro and it will introduce its pattern's bindings into scope as if it were inlined into its expansion site. This doesn't work forlet
expressions because of how macros are parsed: whetherlet
is allowed is determined when parsing, and the macro doesn't have the context of its expansion site to work with, so it doesn't know if it's being expanded into a condition or not. There's one catch though: because of this, most parts of the compiler that work withlet
expressions assume&&
operators associate to the left. Since macro expansions sites aren't re-parsed (cc #61733 (comment)), macros expanding to&&
-chains containingis
operators will break that assumption: putting one of those expansions on the right-hand-side of an&&
will cause this implementation to panic incheck_match
(and also likely make some incorrect assumptions inregion_scope_tree
).I've also tried to handle attributes on
is
correctly. There's no tests since it would be impossible to put an attribute directly on anis
operator expression currently without parentheses (cc #127436), but it may eventually be possible if attributes can apply to macro expansions (cc #63221).Feature gate and tracking issue
None yet. I can add those if there's interest in merging these changes. Since the current
builtin # is(expr is pat)
syntax is permanently unstable, this PR does not stabilize anything.Footnotes
Since
let
-chains already exist, I'd be curious if it'd make sense to restrict the scope ofis
further, to avoid its scope depending on whether it appears in a condition. Possibly some of the questions around shadowing would be easier to resolve too. But it raises some questions around temporary lifetimes and how mixingis
andlet
in&&
-chains should work. Alternatively, I'd be happy with shortening the lifetime oflet
expressions' temporaries by default and keepingis
consistent withlet
. I've been running into some trouble withlet
temporary lifetimes in designingif let
guard patterns too. ↩