Skip to content
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
12 changes: 6 additions & 6 deletions src/fsharp/CheckComputationExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,7 @@ let TcComputationExpression cenv env (overallTy: OverallTy) tpenv (mWhole, inter
Some (trans CompExprTranslationPass.Initial q varSpace thenComp (fun holeFill -> translatedCtxt (SynExpr.IfThenElse (guardExpr, holeFill, Some elseComp, spIfToThen, isRecovery, mIfToEndOfElseBranch, trivia))))

// 'let binds in expr'
| SynExpr.LetOrUse (isRec, false, binds, innerComp, m) ->
| SynExpr.LetOrUse (isRec, false, binds, innerComp, m, trivia) ->

// For 'query' check immediately
if isQuery then
Expand All @@ -1118,7 +1118,7 @@ let TcComputationExpression cenv env (overallTy: OverallTy) tpenv (mWhole, inter
// error case
error(Error(FSComp.SR.tcCustomOperationMayNotBeUsedInConjunctionWithNonSimpleLetBindings(), mQueryOp)))

Some (trans CompExprTranslationPass.Initial q varSpace innerComp (fun holeFill -> translatedCtxt (SynExpr.LetOrUse (isRec, false, binds, holeFill, m))))
Some (trans CompExprTranslationPass.Initial q varSpace innerComp (fun holeFill -> translatedCtxt (SynExpr.LetOrUse (isRec, false, binds, holeFill, m, trivia))))

// 'use x = expr in expr'
| SynExpr.LetOrUse (isUse=true; bindings=[SynBinding (kind=SynBindingKind.Normal; headPat=pat; expr=rhsExpr; debugPoint=spBind)]; body=innerComp) ->
Expand Down Expand Up @@ -1566,11 +1566,11 @@ let TcComputationExpression cenv env (overallTy: OverallTy) tpenv (mWhole, inter
| None -> None
| Some elseExprOpt -> Some (SynExpr.IfThenElse (guardExpr, thenExpr, elseExprOpt, spIfToThen, isRecovery, mIfToEndOfElseBranch, trivia), None)

| SynExpr.LetOrUse (isRec, false, binds, innerComp, m) ->
| SynExpr.LetOrUse (isRec, false, binds, innerComp, m, trivia) ->
match convertSimpleReturnToExpr varSpace innerComp with
| None -> None
| Some (_, Some _) -> None
| Some (innerExpr, None) -> Some (SynExpr.LetOrUse (isRec, false, binds, innerExpr, m), None)
| Some (innerExpr, None) -> Some (SynExpr.LetOrUse (isRec, false, binds, innerExpr, m, trivia), None)

| OptionalSequential (CustomOperationClause (nm, _, _, mClause, _), _) when customOperationMaintainsVarSpaceUsingBind nm ->

Expand Down Expand Up @@ -1607,7 +1607,7 @@ let TcComputationExpression cenv env (overallTy: OverallTy) tpenv (mWhole, inter
| SynExpr.Sequential (_, _, innerComp1, innerComp2, _) -> isSimpleExpr innerComp1 && isSimpleExpr innerComp2
| SynExpr.IfThenElse (thenExpr=thenComp; elseExpr=elseCompOpt) ->
isSimpleExpr thenComp && (match elseCompOpt with None -> true | Some c -> isSimpleExpr c)
| SynExpr.LetOrUse (_, _, _, innerComp, _) -> isSimpleExpr innerComp
| SynExpr.LetOrUse (body=innerComp) -> isSimpleExpr innerComp
| SynExpr.LetOrUseBang _ -> false
| SynExpr.Match (clauses=clauses) ->
clauses |> List.forall (fun (SynMatchClause(resultExpr = innerComp)) -> isSimpleExpr innerComp)
Expand Down Expand Up @@ -1840,7 +1840,7 @@ let TcSequenceExpression (cenv: cenv) env tpenv comp (overallTy: OverallTy) m =
Some(mkCond spIfToThen DebugPointAtTarget.Yes mIfToEndOfElseBranch genOuterTy guardExpr' thenExpr elseExpr, tpenv)

// 'let x = expr in expr'
| SynExpr.LetOrUse (_, false (* not a 'use' binding *), _, _, _) ->
| SynExpr.LetOrUse (isUse=false (* not a 'use' binding *)) ->
TcLinearExprs
(fun overallTy envinner tpenv e -> tcSequenceExprBody envinner overallTy.Commit tpenv e)
cenv env overallTy
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9693,7 +9693,7 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr expr cont =
TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr e2 (fun (e2', tpenv) ->
cont (Expr.Sequential (e1', e2', NormalSeq, sp, m), tpenv))

| SynExpr.LetOrUse (isRec, isUse, binds, body, m) when not (isUse && isCompExpr) ->
| SynExpr.LetOrUse (isRec, isUse, binds, body, m, _) when not (isUse && isCompExpr) ->
if isRec then
// TcLinearExprs processes at most one recursive binding, this is not tailcalling
CheckRecursiveBindingIds binds
Expand Down
3 changes: 2 additions & 1 deletion src/fsharp/SyntaxTree.fs
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,8 @@ type SynExpr =
isUse: bool *
bindings: SynBinding list *
body: SynExpr *
range: range
range: range *
trivia: SynExprLetOrUseTrivia

| TryWith of
tryExpr: SynExpr *
Expand Down
3 changes: 2 additions & 1 deletion src/fsharp/SyntaxTree.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,8 @@ type SynExpr =
isUse: bool *
bindings: SynBinding list *
body: SynExpr *
range: range
range: range *
trivia: SynExprLetOrUseTrivia

/// F# syntax: try expr with pat -> expr
| TryWith of
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/SyntaxTreeOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ let rec synExprContainsError inpExpr =
| SynExpr.Match (expr=e; clauses=cl) ->
walkExpr e || walkMatchClauses cl

| SynExpr.LetOrUse (_, _, bs, e, _) ->
| SynExpr.LetOrUse (bindings=bs; body=e) ->
walkBinds bs || walkExpr e

| SynExpr.TryWith (tryExpr=e; withCases=cl) ->
Expand Down
4 changes: 4 additions & 0 deletions src/fsharp/SyntaxTrivia.fs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ type SynExprLambdaTrivia =
{ ArrowRange: range option }
static member Zero: SynExprLambdaTrivia = { ArrowRange = None }

[<NoEquality; NoComparison>]
type SynExprLetOrUseTrivia =
{ InKeyword: range option }

[<NoEquality; NoComparison>]
type SynMatchClauseTrivia =
{ ArrowRange: range option
Expand Down
8 changes: 8 additions & 0 deletions src/fsharp/SyntaxTrivia.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ type SynExprLambdaTrivia =
}
static member Zero: SynExprLambdaTrivia

/// Represents additional information for SynExpr.Lambda
[<NoEquality; NoComparison>]
type SynExprLetOrUseTrivia =
{
/// The syntax range of the `in` keyword.
InKeyword: range option
}

/// Represents additional information for SynMatchClause
[<NoEquality; NoComparison>]
type SynMatchClauseTrivia =
Expand Down
54 changes: 32 additions & 22 deletions src/fsharp/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ let mkClassMemberLocalBindings(isStatic, initialRangeOpt, attrs, vis, BindingSet
if isUse then errorR(Error(FSComp.SR.parsUseBindingsIllegalInImplicitClassConstructors(), wholeRange))
SynMemberDefn.LetBindings (decls, isStatic, isRec, wholeRange)

let mkLocalBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs, _), body) =
let mkLocalBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs, _), mIn, body) =
let ignoredFreeAttrs, decls = declsPreAttrs [] None
if not (isNil ignoredFreeAttrs) then warning(Error(FSComp.SR.parsAttributesIgnored(), mWhole))
SynExpr.LetOrUse (isRec, isUse, decls, body, mWhole)
SynExpr.LetOrUse (isRec, isUse, decls, body, mWhole, { InKeyword = mIn })

let mkDefnBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs, _bindingSetRange), attrs, vis, attrsm) =
if isUse then warning(Error(FSComp.SR.parsUseBindingsIllegalInModules(), mWhole))
Expand Down Expand Up @@ -1309,7 +1309,7 @@ moduleDefn:

/* 'let' or 'do' definitions in #light */
| opt_attributes opt_declVisibility hardwhiteLetBindings %prec decl_let
{ let hwlb, m = $3
{ let hwlb, m, _ = $3
if Option.isSome $2 then errorR(Error(FSComp.SR.parsVisibilityDeclarationsShouldComePriorToIdentifier(), rhs parseState 2))
parseState.ResetSynArgNameGenerator()
mkDefnBindings (m, hwlb, $1, $2, m) }
Expand Down Expand Up @@ -2711,7 +2711,8 @@ hardwhiteLetBindings:
{ let mLetKwd = rhs parseState 1
let isUse = $1
let isRec = $2
$4 (if isUse then "use" else "let") mLetKwd // report unterminated error
let report, mIn = $4
report (if isUse then "use" else "let") mLetKwd // report unterminated error

let localBindingsLastRangeOpt, localBindingsBuilder = $3

Expand All @@ -2729,7 +2730,9 @@ hardwhiteLetBindings:
if not isRec && not (isNilOrSingleton binds) then
reportParseErrorAt mLetKwd (FSComp.SR.parsLetAndForNonRecBindings())
[], binds),
bindingSetRange), (unionRanges mLetKwd bindingSetRange) }
bindingSetRange),
(unionRanges mLetKwd bindingSetRange),
mIn }


/* A 'do ...' statement */
Expand All @@ -2752,7 +2755,7 @@ classDefnBindings:
{ $1 }

| hardwhiteLetBindings
{ let b, m = $1 in b }
{ let b, m, _ = $1 in b }

| hardwhiteDoBinding
{ fst $1 }
Expand All @@ -2761,7 +2764,10 @@ classDefnBindings:
/* The terminator for a 'let ....' binding in the #light syntax */
hardwhiteDefnBindingsTerminator:
| ODECLEND
{ (fun _ m -> ()) }
{ let mToken = rhs parseState 1
// In LexFilter.fs the IN token could have been transformed to an ODECLEND one.
let mIn = if (mToken.EndColumn - mToken.StartColumn) = 2 then Some mToken else None
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dsyme I just discovered that this little hack doesn't work with:

do
    let e1 = e :?> Collections.DictionaryEntry
    e1.Key, e1.Value

Because e1 has the same length as in the check fall apart.
Any other check I can implement to detect that the token was replaced?

(fun _ m -> ()), mIn }

| recover
{ (fun kwd m ->
Expand All @@ -2771,7 +2777,7 @@ hardwhiteDefnBindingsTerminator:
| "use!" -> FSComp.SR.parsUnmatchedUseBang()
| "use" -> FSComp.SR.parsUnmatchedUse()
| _ (*"let" *) -> FSComp.SR.parsUnmatchedLet()
reportParseErrorAt m msg) }
reportParseErrorAt m msg), None }

/* An 'extern' DllImport function definition in C-style syntax */
cPrototype:
Expand Down Expand Up @@ -3489,12 +3495,12 @@ sequentialExpr:
{ SynExpr.Sequential (DebugPointAtSequential.SuppressNeither, false, $1, $4, unionRanges $1.Range $4.Range) }

| hardwhiteLetBindings %prec prec_args_error
{ let hwlb, m = $1
{ let hwlb, m, mIn = $1
let mLetKwd, isUse = match hwlb with (BindingSetPreAttrs(m, _, isUse, _, _)) -> m, isUse
let usedKeyword = if isUse then "use" else "let"
reportParseErrorAt mLetKwd (FSComp.SR.parsExpectedExpressionAfterLet(usedKeyword, usedKeyword))
let fauxRange = m.EndRange // zero width range at end of m
mkLocalBindings (m, hwlb, arbExpr("seqExpr", fauxRange)) }
mkLocalBindings (m, hwlb, mIn, arbExpr("seqExpr", fauxRange)) }

/* Use this as the last terminal when performing error recovery */
/* The contract for using this is that (a) if EOF occurs then the */
Expand All @@ -3515,7 +3521,8 @@ moreBinders:
SynExprAndBang(spBind, $1, true, $2, mEquals, $4, m) :: $6 }

| OAND_BANG headBindingPattern EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP moreBinders %prec expr_let
{ $5 "and!" (rhs parseState 1) // report unterminated error
{ let report, mIn = $5
report "and!" (rhs parseState 1) // report unterminated error
let spBind = DebugPointAtBinding.Yes(rhs2 parseState 1 5) (* TODO Pretty sure this is wrong *)
let mEquals = rhs parseState 3
let m = rhs parseState 1 (* TODO Pretty sure this is wrong *)
Expand All @@ -3526,31 +3533,33 @@ moreBinders:

declExpr:
| defnBindings IN typedSequentialExpr %prec expr_let
{ mkLocalBindings (unionRanges (rhs2 parseState 1 2) $3.Range, $1, $3) }
{ let mIn = rhs parseState 2 |> Some
mkLocalBindings (unionRanges (rhs2 parseState 1 2) $3.Range, $1, mIn, $3) }

| defnBindings IN error %prec expr_let
{ mkLocalBindings (rhs2 parseState 1 2, $1, arbExpr("declExpr1", (rhs parseState 3))) }
{ let mIn = rhs parseState 2 |> Some
mkLocalBindings (rhs2 parseState 1 2, $1, mIn, arbExpr("declExpr1", (rhs parseState 3))) }
/*
FSComp.SR.parsNoMatchingInForLet() -- leave this in for now - it's an unused error string
*/

| hardwhiteLetBindings typedSequentialExprBlock %prec expr_let
{ let hwlb, m = $1
mkLocalBindings (unionRanges m $2.Range, hwlb, $2) }
{ let hwlb, m, mIn = $1
mkLocalBindings (unionRanges m $2.Range, hwlb, mIn, $2) }

| hardwhiteLetBindings error %prec expr_let
{ let hwlb, m = $1
{ let hwlb, m, mIn = $1
reportParseErrorAt (match hwlb with (BindingSetPreAttrs(m, _, _, _, _)) -> m) (FSComp.SR.parsErrorInReturnForLetIncorrectIndentation())
mkLocalBindings (m, hwlb, arbExpr("declExpr2", (rhs parseState 2))) }
mkLocalBindings (m, hwlb, mIn, arbExpr("declExpr2", (rhs parseState 2))) }

| hardwhiteLetBindings OBLOCKSEP typedSequentialExprBlock %prec expr_let
{ let hwlb, m = $1
mkLocalBindings (unionRanges m $3.Range, hwlb, $3) }
{ let hwlb, m, mIn = $1
mkLocalBindings (unionRanges m $3.Range, hwlb, mIn, $3) }

| hardwhiteLetBindings OBLOCKSEP error %prec expr_let
{ let hwlb, m = $1
{ let hwlb, m, mIn = $1
//reportParseErrorAt (match hwlb with (BindingSetPreAttrs(m, _, _, _, _)) -> m) (FSComp.SR.parsErrorInReturnForLetIncorrectIndentation())
mkLocalBindings (unionRanges m (rhs parseState 3), hwlb, arbExpr("declExpr3", (rhs parseState 3))) }
mkLocalBindings (unionRanges m (rhs parseState 3), hwlb, mIn, arbExpr("declExpr3", (rhs parseState 3))) }

| hardwhiteDoBinding %prec expr_let
{ let e = snd $1
Expand Down Expand Up @@ -3828,7 +3837,8 @@ declExpr:
SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, $2, Some mEquals, $4, $7, $8, m) }

| OBINDER headBindingPattern EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP moreBinders typedSequentialExprBlock %prec expr_let
{ $5 (if $1 = "use" then "use!" else "let!") (rhs parseState 1) // report unterminated error
{ let report, mIn = $5
report (if $1 = "use" then "use!" else "let!") (rhs parseState 1) // report unterminated error
let spBind = DebugPointAtBinding.Yes(unionRanges (rhs parseState 1) $4.Range)
let mEquals = rhs parseState 3
let m = unionRanges (rhs parseState 1) $8.Range
Expand Down
6 changes: 3 additions & 3 deletions src/fsharp/service/FSharpParseFileResults.fs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput,
walkBinding expr2 workingRange


| SynExpr.LetOrUse(_, _, bindings, bodyExpr, _) ->
| SynExpr.LetOrUse(bindings=bindings; body=bodyExpr) ->
let potentialNestedRange =
bindings
|> List.tryFind (fun binding -> rangeContainsPos binding.RangeOfBindingWithRhs pos)
Expand Down Expand Up @@ -205,7 +205,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput,
// of the identifier of the function we're after
getIdentRangeForFuncExprInApp traverseSynExpr funcExpr pos

| SynExpr.LetOrUse (_, _, bindings, body, range) when rangeContainsPos range pos ->
| SynExpr.LetOrUse (bindings=bindings; body=body; range=range) when rangeContainsPos range pos ->
let binding =
bindings
|> List.tryFind (fun x -> rangeContainsPos x.RangeOfBindingWithRhs pos)
Expand Down Expand Up @@ -631,7 +631,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput,
yield! walkExprOpt true whenExpr
yield! walkExpr true tgtExpr

| SynExpr.LetOrUse (_, _, binds, bodyExpr, _) ->
| SynExpr.LetOrUse (bindings=binds; body=bodyExpr) ->
yield! walkBinds binds
yield! walkExpr true bodyExpr

Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/service/ServiceInterfaceStubGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,7 @@ module InterfaceStubGenerator =
| SynExpr.TypeApp (synExpr, _, _synTypeList, _commas, _, _, _range) ->
walkExpr synExpr

| SynExpr.LetOrUse (_, _, synBindingList, synExpr, _range) ->
| SynExpr.LetOrUse (bindings=synBindingList; body=synExpr) ->
Option.orElse (List.tryPick walkBinding synBindingList) (walkExpr synExpr)

| SynExpr.TryWith (tryExpr=synExpr) ->
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/service/ServiceParseTreeWalk.fs
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ module SyntaxTraversal =

| SynExpr.TypeApp (synExpr, _, _synTypeList, _commas, _, _, _range) -> traverseSynExpr synExpr

| SynExpr.LetOrUse (_, isRecursive, synBindingList, synExpr, range) ->
| SynExpr.LetOrUse (_, isRecursive, synBindingList, synExpr, range, _) ->
match visitor.VisitLetOrUse(path, isRecursive, traverseSynBinding path, synBindingList, range) with
| Some x -> Some x
| None ->
Expand Down
4 changes: 2 additions & 2 deletions src/fsharp/service/ServiceParsedInputOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ module ParsedInput =
| SynExpr.App (_, _, e1, e2, _) -> List.tryPick (walkExprWithKind parentKind) [e1; e2]
| SynExpr.TypeApp (e, _, tys, _, _, _, _) ->
walkExprWithKind (Some EntityKind.Type) e |> Option.orElseWith (fun () -> List.tryPick walkType tys)
| SynExpr.LetOrUse (_, _, bindings, e, _) -> List.tryPick walkBinding bindings |> Option.orElseWith (fun () -> walkExprWithKind parentKind e)
| SynExpr.LetOrUse (bindings=bindings; body=e) -> List.tryPick walkBinding bindings |> Option.orElseWith (fun () -> walkExprWithKind parentKind e)
| SynExpr.TryWith (tryExpr=e; withCases=clauses) -> walkExprWithKind parentKind e |> Option.orElseWith (fun () -> List.tryPick walkClause clauses)
| SynExpr.TryFinally (tryExpr=e1; finallyExpr=e2) -> List.tryPick (walkExprWithKind parentKind) [e1; e2]
| SynExpr.Lazy (e, _) -> walkExprWithKind parentKind e
Expand Down Expand Up @@ -1358,7 +1358,7 @@ module ParsedInput =
List.iter walkClause synMatchClauseList
| SynExpr.TypeApp (e, _, tys, _, _, _, _) ->
List.iter walkType tys; walkExpr e
| SynExpr.LetOrUse (_, _, bindings, e, _) ->
| SynExpr.LetOrUse (bindings=bindings; body=e) ->
List.iter walkBinding bindings; walkExpr e
| SynExpr.TryWith (tryExpr=e; withCases=clauses) ->
List.iter walkClause clauses; walkExpr e
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/service/ServiceStructure.fs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ module Structure =
| SynExpr.ForEach (_, _, _, _, _, e, r) ->
rcheck Scope.For Collapse.Below r r
parseExpr e
| SynExpr.LetOrUse (_, _, bindings, body, _) ->
| SynExpr.LetOrUse (bindings=bindings; body=body) ->
parseBindings bindings
parseExpr body
| SynExpr.Match (matchDebugPoint=seqPointAtBinding; clauses=clauses; range=r)
Expand Down
Loading