Skip to content

Commit e33831a

Browse files
jwostyKevinRansom
authored andcommitted
[FS-1047] - match! (match-bang) (#4427)
* Attempt add match! syntax to parser (as normal match) (does not work) * Add name for MATCH_BANG token ("keyword 'match!') * Make match! valid in (and only in) computational expressions * match! works * Add match! to xlf localization files * Add two tests for match! * Don't use left-pipe * Give match! keyword a description * Fix syntax error, and change match! description * xlf updated * Add match! keyword description to resx * Update FSComp.fs * Write quotation test for match! * First crack at compile error tests * Fix baselines * Fix baseline one more time * Add vs baseline * Fix merge mistake * Fix merge mistake (#2) * Fix merge mistake in tests
1 parent 2b6afdf commit e33831a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1813
-1408
lines changed

src/buildfromsource/FSharp.Compiler.Private/FSComp.fs

Lines changed: 1401 additions & 1397 deletions
Large diffs are not rendered by default.

src/buildfromsource/FSharp.Compiler.Private/FSComp.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4152,6 +4152,9 @@
41524152
<data name="keywordDescriptionMatch" xml:space="preserve">
41534153
<value>Used to branch by comparing a value to a pattern.</value>
41544154
</data>
4155+
<data name="keywordDescriptionMatchBang" xml:space="preserve">
4156+
<value>Used in computation expressions to pattern match directly over the result of another computation expression.</value>
4157+
</data>
41554158
<data name="keywordDescriptionMember" xml:space="preserve">
41564159
<value>Used to declare a property or method in an object type.</value>
41574160
</data>

src/fsharp/CompileOps.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,7 @@ let OutputPhasedErrorR (os:StringBuilder) (err:PhasedDiagnostic) =
10311031
| Parser.TOKEN_LAZY -> getErrorString("Parser.TOKEN.LAZY")
10321032
| Parser.TOKEN_OLAZY -> getErrorString("Parser.TOKEN.LAZY")
10331033
| Parser.TOKEN_MATCH -> getErrorString("Parser.TOKEN.MATCH")
1034+
| Parser.TOKEN_MATCH_BANG -> getErrorString("Parser.TOKEN.MATCH.BANG")
10341035
| Parser.TOKEN_MUTABLE -> getErrorString("Parser.TOKEN.MUTABLE")
10351036
| Parser.TOKEN_NEW -> getErrorString("Parser.TOKEN.NEW")
10361037
| Parser.TOKEN_OF -> getErrorString("Parser.TOKEN.OF")

src/fsharp/FSComp.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,7 @@ keywordDescriptionLazy,"Used to specify a computation that is to be performed on
13721372
keywordDescriptionLet,"Used to associate, or bind, a name to a value or function."
13731373
keywordDescriptionLetBang,"Used in asynchronous workflows to bind a name to the result of an asynchronous computation, or, in other computation expressions, used to bind a name to a result, which is of the computation type."
13741374
keywordDescriptionMatch,"Used to branch by comparing a value to a pattern."
1375+
keywordDescriptionMatchBang,"Used in computation expressions to pattern match directly over the result of another computation expression."
13751376
keywordDescriptionMember,"Used to declare a property or method in an object type."
13761377
keywordDescriptionModule,"Used to associate a name with a group of related types, values, and functions, to logically separate it from other code."
13771378
keywordDescriptionMutable,"Used to declare a variable, that is, a value that can be changed."

src/fsharp/FSStrings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,9 @@
594594
<data name="Parser.TOKEN.MATCH" xml:space="preserve">
595595
<value>keyword 'match'</value>
596596
</data>
597+
<data name="Parser.TOKEN.MATCH.BANG" xml:space="preserve">
598+
<value>keyword 'match!'</value>
599+
</data>
597600
<data name="Parser.TOKEN.MUTABLE" xml:space="preserve">
598601
<value>keyword 'mutable'</value>
599602
</data>

src/fsharp/LexFilter.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ type LexFilterImpl (lightSyntaxStatus:LightSyntaxStatus, compilingFsLib, lexer,
10511051
| Parser.EOF _ -> false
10521052
| _ ->
10531053
not (isSameLine()) ||
1054-
(match peekNextToken() with TRY | MATCH | IF | LET _ | FOR | WHILE -> true | _ -> false)
1054+
(match peekNextToken() with TRY | MATCH | MATCH_BANG | IF | LET _ | FOR | WHILE -> true | _ -> false)
10551055

10561056
// Look for '=' or '.Id.id.id = ' after an identifier
10571057
let rec isLongIdentEquals token =
@@ -2034,7 +2034,7 @@ type LexFilterImpl (lightSyntaxStatus:LightSyntaxStatus, compilingFsLib, lexer,
20342034
pushCtxt tokenTup (CtxtIf (tokenStartPos))
20352035
returnToken tokenLexbufState token
20362036

2037-
| MATCH, _ ->
2037+
| (MATCH | MATCH_BANG), _ ->
20382038
if debug then dprintf "MATCH, pushing CtxtMatch(%a)\n" outputPos tokenStartPos
20392039
pushCtxt tokenTup (CtxtMatch (tokenStartPos))
20402040
returnToken tokenLexbufState token

src/fsharp/TypeChecker.fs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3457,7 +3457,8 @@ let (|SimpleSemicolonSequence|_|) acceptDeprecated c =
34573457
| SynExpr.Sequential (_, _, e1, e2, _) -> YieldFree e1 && YieldFree e2
34583458
| SynExpr.IfThenElse (_, e2, e3opt, _, _, _, _) -> YieldFree e2 && Option.forall YieldFree e3opt
34593459
| SynExpr.TryWith (e1, _, clauses, _, _, _, _) -> YieldFree e1 && clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
3460-
| SynExpr.Match (_, _, clauses, _, _) -> clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
3460+
| (SynExpr.Match (_, _, clauses, _, _) | SynExpr.MatchBang (_, _, clauses, _, _)) ->
3461+
clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
34613462
| SynExpr.For (_, _, _, _, _, body, _)
34623463
| SynExpr.TryFinally (body, _, _, _, _)
34633464
| SynExpr.LetOrUse (_, _, _, body, _)
@@ -3483,6 +3484,7 @@ let (|SimpleSemicolonSequence|_|) acceptDeprecated c =
34833484
| SynExpr.YieldOrReturn _
34843485
| SynExpr.LetOrUse _
34853486
| SynExpr.Do _
3487+
| SynExpr.MatchBang _
34863488
| SynExpr.LetOrUseBang _
34873489
| SynExpr.ImplicitZero _
34883490
| SynExpr.While _ -> false
@@ -6040,17 +6042,19 @@ and TcExprUndelayed cenv overallTy env tpenv (expr: SynExpr) =
60406042

60416043
| SynExpr.YieldOrReturn ((isTrueYield, _), _, m)
60426044
| SynExpr.YieldOrReturnFrom ((isTrueYield, _), _, m) when isTrueYield ->
6043-
error(Error(FSComp.SR.tcConstructRequiresListArrayOrSequence(), m))
6045+
error(Error(FSComp.SR.tcConstructRequiresListArrayOrSequence(), m))
60446046
| SynExpr.YieldOrReturn ((_, isTrueReturn), _, m)
60456047
| SynExpr.YieldOrReturnFrom ((_, isTrueReturn), _, m) when isTrueReturn ->
6046-
error(Error(FSComp.SR.tcConstructRequiresComputationExpressions(), m))
6048+
error(Error(FSComp.SR.tcConstructRequiresComputationExpressions(), m))
60476049
| SynExpr.YieldOrReturn (_, _, m)
60486050
| SynExpr.YieldOrReturnFrom (_, _, m)
60496051
| SynExpr.ImplicitZero m ->
6050-
error(Error(FSComp.SR.tcConstructRequiresSequenceOrComputations(), m))
6052+
error(Error(FSComp.SR.tcConstructRequiresSequenceOrComputations(), m))
60516053
| SynExpr.DoBang (_, m)
60526054
| SynExpr.LetOrUseBang (_, _, _, _, _, _, m) ->
6053-
error(Error(FSComp.SR.tcConstructRequiresComputationExpression(), m))
6055+
error(Error(FSComp.SR.tcConstructRequiresComputationExpression(), m))
6056+
| SynExpr.MatchBang (_, _, _, _, m) ->
6057+
error(Error(FSComp.SR.tcConstructRequiresComputationExpression(), m))
60546058

60556059
/// Check lambdas as a group, to catch duplicate names in patterns
60566060
and TcIteratedLambdas cenv isFirst (env: TcEnv) overallTy takenNames tpenv e =
@@ -7960,6 +7964,15 @@ and TcComputationExpression cenv env overallTy mWhole interpExpr builderTy tpenv
79607964
let clauses = clauses |> List.map (fun (Clause(pat, cond, innerComp, patm, sp)) -> Clause(pat, cond, transNoQueryOps innerComp, patm, sp))
79617965
Some(translatedCtxt (SynExpr.Match(spMatch, expr, clauses, false, m)))
79627966

7967+
// 'match! expr with pats ...' --> build.Bind(e1, (function pats ...))
7968+
| SynExpr.MatchBang (spMatch, expr, clauses, false, m) ->
7969+
let mMatch = match spMatch with SequencePointAtBinding mMatch -> mMatch | _ -> m
7970+
if isQuery then error(Error(FSComp.SR.tcMatchMayNotBeUsedWithQuery(), mMatch))
7971+
if isNil (TryFindIntrinsicOrExtensionMethInfo cenv env mMatch ad "Bind" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Bind"), mMatch))
7972+
let clauses = clauses |> List.map (fun (Clause(pat, cond, innerComp, patm, sp)) -> Clause(pat, cond, transNoQueryOps innerComp, patm, sp))
7973+
let consumeExpr = SynExpr.MatchLambda(false, mMatch, clauses, spMatch, mMatch)
7974+
Some(translatedCtxt (mkSynCall "Bind" mMatch [expr; consumeExpr]))
7975+
79637976
| SynExpr.TryWith (innerComp, _mTryToWith, clauses, _mWithToLast, mTryToLast, spTry, _spWith) ->
79647977
let mTry = match spTry with SequencePointAtTry(m) -> m | _ -> mTryToLast
79657978

@@ -8766,6 +8779,7 @@ and TcItemThen cenv overallTy env tpenv (item, mItem, rest, afterResolution) del
87668779
| SynExpr.ImplicitZero _
87678780
| SynExpr.YieldOrReturn _
87688781
| SynExpr.YieldOrReturnFrom _
8782+
| SynExpr.MatchBang _
87698783
| SynExpr.LetOrUseBang _
87708784
| SynExpr.DoBang _
87718785
| SynExpr.TraitCall _

src/fsharp/ast.fs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,9 @@ and
692692
/// Computation expressions only
693693
| LetOrUseBang of bindSeqPoint:SequencePointInfoForBinding * isUse:bool * isFromSource:bool * SynPat * SynExpr * SynExpr * range:range
694694

695+
/// F# syntax: match! expr with pat1 -> expr | ... | patN -> exprN
696+
| MatchBang of matchSeqPoint:SequencePointInfoForBinding * expr:SynExpr * clauses:SynMatchClause list * isExnMatch:bool * range:range (* bool indicates if this is an exception match in a computation expression which throws unmatched exceptions *)
697+
695698
/// F# syntax: do! expr
696699
/// Computation expressions only
697700
| DoBang of expr:SynExpr * range:range
@@ -779,6 +782,7 @@ and
779782
| SynExpr.YieldOrReturn (range=m)
780783
| SynExpr.YieldOrReturnFrom (range=m)
781784
| SynExpr.LetOrUseBang (range=m)
785+
| SynExpr.MatchBang (range=m)
782786
| SynExpr.DoBang (range=m)
783787
| SynExpr.Fixed (range=m) -> m
784788
| SynExpr.Ident id -> id.idRange
@@ -839,6 +843,7 @@ and
839843
| SynExpr.YieldOrReturn (range=m)
840844
| SynExpr.YieldOrReturnFrom (range=m)
841845
| SynExpr.LetOrUseBang (range=m)
846+
| SynExpr.MatchBang (range=m)
842847
| SynExpr.DoBang (range=m) -> m
843848
| SynExpr.DotGet (expr,_,lidwd,m) -> if lidwd.ThereIsAnExtraDotAtTheEnd then unionRanges expr.Range lidwd.RangeSansAnyExtraDot else m
844849
| SynExpr.LongIdent (_,lidwd,_,_) -> lidwd.RangeSansAnyExtraDot
@@ -901,6 +906,7 @@ and
901906
| SynExpr.YieldOrReturn (range=m)
902907
| SynExpr.YieldOrReturnFrom (range=m)
903908
| SynExpr.LetOrUseBang (range=m)
909+
| SynExpr.MatchBang (range=m)
904910
| SynExpr.DoBang (range=m) -> m
905911
// these are better than just .Range, and also commonly applicable inside queries
906912
| SynExpr.Paren(_,m,_,_) -> m
@@ -2397,6 +2403,8 @@ let rec synExprContainsError inpExpr =
23972403
| SynExpr.DotNamedIndexedPropertySet (e1,_,e2,e3,_) ->
23982404
walkExpr e1 || walkExpr e2 || walkExpr e3
23992405

2406+
| SynExpr.MatchBang (_,e,cl,_,_) ->
2407+
walkExpr e || walkMatchClauses cl
24002408
| SynExpr.LetOrUseBang (_,_,_,_,e1,e2,_) ->
24012409
walkExpr e1 || walkExpr e2
24022410
walkExpr inpExpr

src/fsharp/lex.fsl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ rule token args skip = parse
238238
{ YIELD_BANG(true) }
239239
| "return!"
240240
{ YIELD_BANG(false) }
241+
| "match!"
242+
{ MATCH_BANG }
241243
| ident '!'
242244
{ let tok = Keywords.KeywordOrIdentifierToken args lexbuf (lexemeTrimRight lexbuf 1)
243245
match tok with

src/fsharp/lexhelp.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ module Keywords =
394394
"let", FSComp.SR.keywordDescriptionLet()
395395
"let!", FSComp.SR.keywordDescriptionLetBang()
396396
"match", FSComp.SR.keywordDescriptionMatch()
397+
"match!", FSComp.SR.keywordDescriptionMatchBang()
397398
"member", FSComp.SR.keywordDescriptionMember()
398399
"module", FSComp.SR.keywordDescriptionModule()
399400
"mutable", FSComp.SR.keywordDescriptionMutable()

0 commit comments

Comments
 (0)