Skip to content
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

[RFC FS-1063] Applicative CEs via and! and BindReturn #7756

Merged
merged 9 commits into from
Jan 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/fsharp/CompileOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,8 @@ let OutputPhasedErrorR (os: StringBuilder) (err: PhasedDiagnostic) (canSuggestNa
| Parser.TOKEN_OLET(_) -> getErrorString("Parser.TOKEN.OLET")
| Parser.TOKEN_OBINDER
| Parser.TOKEN_BINDER -> getErrorString("Parser.TOKEN.BINDER")
| Parser.TOKEN_OAND_BANG
| Parser.TOKEN_AND_BANG -> getErrorString("Parser.TOKEN.AND.BANG")
| Parser.TOKEN_ODO -> getErrorString("Parser.TOKEN.ODO")
| Parser.TOKEN_OWITH -> getErrorString("Parser.TOKEN.OWITH")
| Parser.TOKEN_OFUNCTION -> getErrorString("Parser.TOKEN.OFUNCTION")
Expand Down
3 changes: 3 additions & 0 deletions src/fsharp/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1475,6 +1475,9 @@ notAFunctionButMaybeDeclaration,"This value is not a function and cannot be appl
3301,chkInvalidFunctionReturnType,"The function or method has an invalid return type '%s'. This is not permitted by the rules of Common IL."
3302,packageManagementRequiresVFive,"The package management feature requires language version 5.0 use /langversion:preview"
3303,fromEndSlicingRequiresVFive,"From the end slicing with requires language version 5.0, use /langversion:preview."
3343,tcRequireMergeSourcesOrBindN,"The 'let! ... and! ...' construct may only be used if the computation expression builder defines either a '%s' method or appropriate 'MergeSource' and 'Bind' methods"
3344,tcAndBangNotSupported,"This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature."
3345,tcInvalidUseBangBindingNoAndBangs,"use! may not be combined with and!"
useSdkRefs,"Use reference assemblies for .NET framework references when available (Enabled by default)."
fSharpBannerVersion,"%s for F# %s"
optsLangVersion,"Display the allowed values for language version, specify language version such as 'latest' or 'preview'"
Expand Down
3 changes: 3 additions & 0 deletions src/fsharp/FSStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,9 @@
<data name="Parser.TOKEN.AND" xml:space="preserve">
<value>keyword 'and'</value>
</data>
!<data name="Parser.TOKEN.AND.BANG" xml:space="preserve">
<value>keyword 'and!'</value>
</data>
<data name="Parser.TOKEN.AS" xml:space="preserve">
<value>keyword 'as'</value>
</data>
Expand Down
2 changes: 2 additions & 0 deletions src/fsharp/LanguageFeatures.fs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type LanguageFeature =
| PackageManagement
| FromEndSlicing
| FixedIndexSlice3d4d
| AndBang

/// LanguageVersion management
type LanguageVersion (specifiedVersionAsString) =
Expand Down Expand Up @@ -61,6 +62,7 @@ type LanguageVersion (specifiedVersionAsString) =
LanguageFeature.NameOf, previewVersion
LanguageFeature.OpenStaticClasses, previewVersion
LanguageFeature.PackageManagement, previewVersion
LanguageFeature.AndBang, previewVersion
]

let specified =
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/LanguageFeatures.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type LanguageFeature =
| PackageManagement
| FromEndSlicing
| FixedIndexSlice3d4d

| AndBang

/// LanguageVersion management
type LanguageVersion =
Expand Down
7 changes: 7 additions & 0 deletions src/fsharp/LexFilter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1784,6 +1784,13 @@ type LexFilterImpl (lightSyntaxStatus: LightSyntaxStatus, compilingFsLib, lexer,
pushCtxt tokenTup (CtxtLetDecl(blockLet, tokenStartPos))
returnToken tokenLexbufState (if blockLet then OBINDER b else token)

// and! ... ~~~> CtxtLetDecl
| AND_BANG isUse, (ctxt :: _) ->
let blockLet = match ctxt with CtxtSeqBlock _ -> true | _ -> false
if debug then dprintf "AND!: entering CtxtLetDecl(blockLet=%b), awaiting EQUALS to go to CtxtSeqBlock (%a)\n" blockLet outputPos tokenStartPos
pushCtxt tokenTup (CtxtLetDecl(blockLet,tokenStartPos))
returnToken tokenLexbufState (if blockLet then OAND_BANG isUse else token)

| (VAL | STATIC | ABSTRACT | MEMBER | OVERRIDE | DEFAULT), ctxtStack when thereIsACtxtMemberBodyOnTheStackAndWeShouldPopStackForUpcomingMember ctxtStack ->
if debug then dprintf "STATIC/MEMBER/OVERRIDE/DEFAULT: already inside CtxtMemberBody, popping all that context before starting next member...\n"
// save this token, we'll consume it again later...
Expand Down
362 changes: 293 additions & 69 deletions src/fsharp/TypeChecker.fs
100644 → 100755

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions src/fsharp/ast.fs
Original file line number Diff line number Diff line change
Expand Up @@ -764,12 +764,13 @@ and
/// Computation expressions only
| YieldOrReturnFrom of (bool * bool) * expr: SynExpr * range: range

/// SynExpr.LetOrUseBang (spBind, isUse, isFromSource, pat, rhsExpr, bodyExpr, mWholeExpr).
/// SynExpr.LetOrUseAndBang (spBind, isUse, isFromSource, pat, rhsExpr, mLetBangExpr, [(andBangSpBind, andBangIsUse, andBangIsFromSource, andBangPat, andBangRhsExpr, mAndBangExpr)], bodyExpr).
///
/// F# syntax: let! pat = expr in expr
/// F# syntax: use! pat = expr in expr
/// F# syntax: let! pat = expr and! ... and! ... and! pat = expr in expr
/// Computation expressions only
| LetOrUseBang of bindSeqPoint: SequencePointInfoForBinding * isUse: bool * isFromSource: bool * SynPat * SynExpr * SynExpr * range: range
| LetOrUseBang of bindSeqPoint: SequencePointInfoForBinding * isUse: bool * isFromSource: bool * SynPat * rhs: SynExpr * andBangs:(SequencePointInfoForBinding * bool * bool * SynPat * SynExpr * range) list * body:SynExpr * range: range

/// F# syntax: match! expr with pat1 -> expr | ... | patN -> exprN
| MatchBang of matchSeqPoint: SequencePointInfoForBinding * expr: SynExpr * clauses: SynMatchClause list * range: range (* bool indicates if this is an exception match in a computation expression which throws unmatched exceptions *)
Expand Down Expand Up @@ -2475,6 +2476,6 @@ let rec synExprContainsError inpExpr =

| SynExpr.MatchBang (_, e, cl, _) ->
walkExpr e || walkMatchClauses cl
| SynExpr.LetOrUseBang (_, _, _, _, e1, e2, _) ->
walkExpr e1 || walkExpr e2
| SynExpr.LetOrUseBang (rhs=e1;body=e2;andBangs=es) ->
walkExpr e1 || walkExprs [ for (_,_,_,_,e,_) in es do yield e ] || walkExpr e2
walkExpr inpExpr
4 changes: 3 additions & 1 deletion src/fsharp/lex.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,12 @@ rule token args skip = parse
{ YIELD_BANG(false) }
| "match!"
{ MATCH_BANG }
| "and!"
{ AND_BANG(false) }
| ident '!'
{ let tok = Keywords.KeywordOrIdentifierToken args lexbuf (lexemeTrimRight lexbuf 1)
match tok with
| LET _ -> BINDER (lexemeTrimRight lexbuf 1)
| LET _ -> BINDER (lexemeTrimRight lexbuf 1)
| _ -> fail args lexbuf (FSComp.SR.lexIdentEndInMarkReserved("!")) (Keywords.KeywordOrIdentifierToken args lexbuf (lexeme lexbuf)) }
| ident ('#')
{ fail args lexbuf (FSComp.SR.lexIdentEndInMarkReserved("#")) (Keywords.KeywordOrIdentifierToken args lexbuf (lexeme lexbuf)) }
Expand Down
44 changes: 34 additions & 10 deletions src/fsharp/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ let rangeOfLongIdent(lid:LongIdent) =
%token <char> CHAR
%token <System.Decimal> DECIMAL
%token <(string * string)> BIGNUM
%token <bool> LET YIELD YIELD_BANG
%token <bool> LET YIELD YIELD_BANG AND_BANG
%token <bool> LESS GREATER /* here the bool indicates if the tokens are part of a type application or type parameter declaration, e.g. C<int>, detected by the lex filter */
%token <string> PERCENT_OP BINDER
%token <string * bool> LQUOTE RQUOTE RQUOTE_DOT
Expand Down Expand Up @@ -218,6 +218,7 @@ let rangeOfLongIdent(lid:LongIdent) =
/* for offside rule */
%token <bool> OLET /* LexFilter #light converts 'LET' tokens to 'OLET' when starting (CtxtLetDecl(blockLet=true)) */
%token <string> OBINDER /* LexFilter #light converts 'BINDER' tokens to 'OBINDER' when starting (CtxtLetDecl(blockLet=true)) */
%token <bool> OAND_BANG /* LexFilter #light converts 'AND_BANG' tokens to 'OAND_BANG' when starting (CtxtLetDecl(blockLet=true)) */
%token ODO /* LexFilter #light converts 'DO' tokens to 'ODO' */
%token ODO_BANG /* LexFilter #light converts 'DO_BANG' tokens to 'ODO_BANG' */
%token OTHEN /* LexFilter #light converts 'THEN' tokens to 'OTHEN' */
Expand Down Expand Up @@ -453,7 +454,8 @@ let rangeOfLongIdent(lid:LongIdent) =
%nonassoc paren_pat_colon
%nonassoc paren_pat_attribs
%left OR BAR_BAR JOIN_IN
%left AND /* check */
%left AND
%left AND_BANG
%left AMP AMP_AMP
%nonassoc pat_conj
%nonassoc expr_not
Expand Down Expand Up @@ -3060,6 +3062,20 @@ recover:
| error { debugPrint("recovering via error"); true }
| EOF { debugPrint("recovering via EOF"); false }

morebinders:
| AND_BANG headBindingPattern EQUALS typedSeqExprBlock IN morebinders %prec expr_let
{ let spBind = SequencePointAtBinding(rhs2 parseState 1 5) (* TODO Pretty sure this is wrong *)
let m = rhs parseState 1 (* TODO Pretty sure this is wrong *)
(spBind,$1,true,$2,$4,m) :: $6 }

| OAND_BANG headBindingPattern EQUALS typedSeqExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP morebinders %prec expr_let
{ $5 "and!" (rhs parseState 1) // report unterminated error
let spBind = SequencePointAtBinding(rhs2 parseState 1 5) (* TODO Pretty sure this is wrong *)
let m = rhs parseState 1 (* TODO Pretty sure this is wrong *)
(spBind,$1,true,$2,$4,m) :: $7 }

| %prec prec_no_more_attr_bindings
{ [] }

declExpr:
| defnBindings IN typedSeqExpr %prec expr_let
Expand Down Expand Up @@ -3353,27 +3369,35 @@ declExpr:
| YIELD_BANG declExpr
{ SynExpr.YieldOrReturnFrom (($1,not $1), $2, unionRanges (rhs parseState 1) $2.Range) }

| BINDER headBindingPattern EQUALS typedSeqExprBlock IN opt_OBLOCKSEP typedSeqExprBlock %prec expr_let
| YIELD recover
{ let mYieldAll = rhs parseState 1
SynExpr.YieldOrReturn (($1, not $1), arbExpr("yield", mYieldAll), mYieldAll) }

| YIELD_BANG recover
{ let mYieldAll = rhs parseState 1
SynExpr.YieldOrReturnFrom (($1, not $1), arbExpr("yield!", mYieldAll), mYieldAll) }

| BINDER headBindingPattern EQUALS typedSeqExprBlock IN opt_OBLOCKSEP morebinders typedSeqExprBlock %prec expr_let
{ let spBind = SequencePointAtBinding(rhs2 parseState 1 5)
let m = unionRanges (rhs parseState 1) $7.Range
SynExpr.LetOrUseBang (spBind,($1 = "use"),true,$2,$4,$7,m) }
let m = unionRanges (rhs parseState 1) $8.Range
SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, $2, $4, $7, $8, m) }

| OBINDER headBindingPattern EQUALS typedSeqExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP typedSeqExprBlock %prec expr_let
| OBINDER headBindingPattern EQUALS typedSeqExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP morebinders typedSeqExprBlock %prec expr_let
{ $5 (if $1 = "use" then "use!" else "let!") (rhs parseState 1) // report unterminated error
let spBind = SequencePointAtBinding(unionRanges (rhs parseState 1) $4.Range)
let m = unionRanges (rhs parseState 1) $7.Range
SynExpr.LetOrUseBang (spBind,($1 = "use"),true,$2,$4,$7,m) }
let m = unionRanges (rhs parseState 1) $8.Range
SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, $2, $4, $7, $8, m) }

| OBINDER headBindingPattern EQUALS typedSeqExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP error %prec expr_let
{ // error recovery that allows intellisense when writing incomplete computation expressions
let spBind = SequencePointAtBinding(unionRanges (rhs parseState 1) $4.Range)
let mAll = unionRanges (rhs parseState 1) (rhs parseState 7)
let m = $4.Range.EndRange // zero-width range
SynExpr.LetOrUseBang (spBind,($1 = "use"),true,$2,$4, SynExpr.ImplicitZero m, mAll) }
SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, $2, $4, [], SynExpr.ImplicitZero m, mAll) }

| DO_BANG typedSeqExpr IN opt_OBLOCKSEP typedSeqExprBlock %prec expr_let
{ let spBind = NoSequencePointAtDoBinding
SynExpr.LetOrUseBang (spBind,false,true,SynPat.Const(SynConst.Unit,$2.Range),$2,$5, unionRanges (rhs parseState 1) $5.Range) }
SynExpr.LetOrUseBang(spBind, false, true, SynPat.Const(SynConst.Unit,$2.Range), $2, [], $5, unionRanges (rhs parseState 1) $5.Range) }

| ODO_BANG typedSeqExprBlock hardwhiteDefnBindingsTerminator %prec expr_let
{ SynExpr.DoBang ($2, unionRanges (rhs parseState 1) $2.Range) }
Expand Down
8 changes: 6 additions & 2 deletions src/fsharp/service/ServiceAssemblyContent.fs
Original file line number Diff line number Diff line change
Expand Up @@ -703,9 +703,13 @@ module ParsedInput =
addLongIdentWithDots ident
List.iter walkExpr [e1; e2; e3]
| SynExpr.JoinIn (e1, _, e2, _) -> List.iter walkExpr [e1; e2]
| SynExpr.LetOrUseBang (_, _, _, pat, e1, e2, _) ->
| SynExpr.LetOrUseBang (_, _, _, pat, e1, es, e2, _) ->
walkPat pat
List.iter walkExpr [e1; e2]
walkExpr e1
for (_,_,_,patAndBang,eAndBang,_) in es do
walkPat patAndBang
walkExpr eAndBang
walkExpr e2
| SynExpr.TraitCall (ts, sign, e, _) ->
List.iter walkTypar ts
walkMemberSig sign
Expand Down
10 changes: 8 additions & 2 deletions src/fsharp/service/ServiceInterfaceStubGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -896,8 +896,14 @@ module InterfaceStubGenerator =
| SynExpr.DoBang (synExpr, _range) ->
walkExpr synExpr

| SynExpr.LetOrUseBang (_sequencePointInfoForBinding, _, _, _synPat, synExpr1, synExpr2, _range) ->
List.tryPick walkExpr [synExpr1; synExpr2]
| SynExpr.LetOrUseBang (_sequencePointInfoForBinding, _, _, _synPat, synExpr1, synExprAndBangs, synExpr2, _range) ->
[
yield synExpr1
dsyme marked this conversation as resolved.
Show resolved Hide resolved
for (_,_,_,_,eAndBang,_) in synExprAndBangs do
yield eAndBang
yield synExpr2
]
|> List.tryPick walkExpr

| SynExpr.LibraryOnlyILAssembly _
| SynExpr.LibraryOnlyStaticOptimization _
Expand Down
4 changes: 2 additions & 2 deletions src/fsharp/service/ServiceLexing.fs
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -261,14 +261,14 @@ module internal TokenClassifications =
| MEMBER | STATIC | NAMESPACE
| OASSERT | OLAZY | ODECLEND | OBLOCKSEP | OEND | OBLOCKBEGIN | ORIGHT_BLOCK_END
| OBLOCKEND | OBLOCKEND_COMING_SOON | OBLOCKEND_IS_HERE | OTHEN | OELSE | OLET(_)
| OBINDER _ | BINDER _ | ODO | OWITH | OFUNCTION | OFUN | ORESET | ODUMMY _ | DO_BANG
| OBINDER _ | OAND_BANG _ | BINDER _ | ODO | OWITH | OFUNCTION | OFUN | ORESET | ODUMMY _ | DO_BANG
| ODO_BANG | YIELD _ | YIELD_BANG _ | OINTERFACE_MEMBER
| ELIF | RARROW | LARROW | SIG | STRUCT
| UPCAST | DOWNCAST | NULL | RESERVED | MODULE | AND | AS | ASSERT | ASR
| DOWNTO | EXCEPTION | FALSE | FOR | FUN | FUNCTION
| FINALLY | LAZY | MATCH | MATCH_BANG | MUTABLE | NEW | OF | OPEN | OR | VOID | EXTERN
| INTERFACE | REC | TO | TRUE | TRY | TYPE | VAL | INLINE | WHEN | WHILE | WITH
| IF | THEN | ELSE | DO | DONE | LET(_) | IN (*| NAMESPACE*) | CONST
| IF | THEN | ELSE | DO | DONE | LET _ | AND_BANG _ | IN | CONST
| HIGH_PRECEDENCE_PAREN_APP | FIXED
| HIGH_PRECEDENCE_BRACK_APP
| TYPE_COMING_SOON | TYPE_IS_HERE | MODULE_COMING_SOON | MODULE_IS_HERE ->
Expand Down
14 changes: 10 additions & 4 deletions src/fsharp/service/ServiceParseTreeWalk.fs
Original file line number Diff line number Diff line change
Expand Up @@ -473,10 +473,16 @@ module public AstTraversal =
| SynExpr.ImplicitZero (_range) -> None
| SynExpr.YieldOrReturn (_, synExpr, _range) -> traverseSynExpr synExpr
| SynExpr.YieldOrReturnFrom (_, synExpr, _range) -> traverseSynExpr synExpr
| SynExpr.LetOrUseBang (_sequencePointInfoForBinding, _, _, synPat, synExpr, synExpr2, _range) ->
[dive synPat synPat.Range traversePat
dive synExpr synExpr.Range traverseSynExpr
dive synExpr2 synExpr2.Range traverseSynExpr]
| SynExpr.LetOrUseBang(_sequencePointInfoForBinding, _, _, synPat, synExpr, andBangSynExprs, synExpr2, _range) ->
[
yield dive synPat synPat.Range traversePat
yield dive synExpr synExpr.Range traverseSynExpr
yield!
[ for (_,_,_,andBangSynPat,andBangSynExpr,_) in andBangSynExprs do
yield (dive andBangSynPat andBangSynPat.Range traversePat)
yield (dive andBangSynExpr andBangSynExpr.Range traverseSynExpr)]
yield dive synExpr2 synExpr2.Range traverseSynExpr
]
|> pick expr
| SynExpr.MatchBang (_sequencePointInfoForBinding, synExpr, synMatchClauseList, _range) ->
[yield dive synExpr synExpr.Range traverseSynExpr
Expand Down
23 changes: 15 additions & 8 deletions src/fsharp/service/ServiceStructure.fs
Original file line number Diff line number Diff line change
Expand Up @@ -245,14 +245,21 @@ module Structure =
| SynExpr.DoBang (e, r) ->
rcheck Scope.Do Collapse.Below r <| Range.modStart 3 r
parseExpr e
| SynExpr.LetOrUseBang (_, _, _, pat, e1, e2, _) ->
// for `let!` or `use!` the pattern begins at the end of the keyword so that
// this scope can be used without adjustment if there is no `=` on the same line
// if there is an `=` the range will be adjusted during the tooltip creation
let r = Range.endToEnd pat.Range e1.Range
rcheck Scope.LetOrUseBang Collapse.Below r r
parseExpr e1
parseExpr e2
| SynExpr.LetOrUseBang (_, _, _, pat, eLet, es, eBody, _) ->
[
yield eLet
yield! [ for (_,_,_,_,eAndBang,_) in es do yield eAndBang ]
dsyme marked this conversation as resolved.
Show resolved Hide resolved
]
|> List.iter (fun e ->
// for `let!`, `use!` or `and!` the pattern begins at the end of the
// keyword so that this scope can be used without adjustment if there is no `=`
// on the same line. If there is an `=` the range will be adjusted during the
// tooltip creation
let r = Range.endToEnd pat.Range e.Range
rcheck Scope.LetOrUseBang Collapse.Below r r
parseExpr e
)
parseExpr eBody
| SynExpr.For (_, _, _, _, _, e, r)
| SynExpr.ForEach (_, _, _, _, _, e, r) ->
rcheck Scope.For Collapse.Below r r
Expand Down
14 changes: 12 additions & 2 deletions src/fsharp/service/ServiceUntypedParse.fs
Original file line number Diff line number Diff line change
Expand Up @@ -322,9 +322,12 @@ type FSharpParseFileResults(errors: FSharpErrorInfo[], input: Ast.ParsedInput op
yield! walkExpr false e2
yield! walkExpr false e3

| SynExpr.LetOrUseBang (spBind, _, _, _, e1, e2, _) ->
| SynExpr.LetOrUseBang (spBind, _, _, _, e1, es, e2, _) ->
yield! walkBindSeqPt spBind
yield! walkExpr true e1
for (andBangSpBind,_,_,_,eAndBang,_) in es do
yield! walkBindSeqPt andBangSpBind
yield! walkExpr true eAndBang
yield! walkExpr true e2

| SynExpr.MatchBang (spBind, e, cl, _) ->
Expand Down Expand Up @@ -880,7 +883,14 @@ module UntypedParseImpl =
| SynExpr.Match (_, e, synMatchClauseList, _)
| SynExpr.MatchBang (_, e, synMatchClauseList, _) ->
walkExprWithKind parentKind e |> Option.orElse (List.tryPick walkClause synMatchClauseList)
| SynExpr.LetOrUseBang (_, _, _, _, e1, e2, _) -> List.tryPick (walkExprWithKind parentKind) [e1; e2]
| SynExpr.LetOrUseBang(_, _, _, _, e1, es, e2, _) ->
[
yield e1
dsyme marked this conversation as resolved.
Show resolved Hide resolved
for (_,_,_,_,eAndBang,_) in es do
yield eAndBang
yield e2
]
|> List.tryPick (walkExprWithKind parentKind)
| SynExpr.DoBang (e, _) -> walkExprWithKind parentKind e
| SynExpr.TraitCall (ts, sign, e, _) ->
List.tryPick walkTypar ts
Expand Down
Loading