Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
1799aaf
make attribute targets mismatches a warning and not an error.
edgarfgp Apr 23, 2025
55507e9
release notes
edgarfgp Apr 23, 2025
1738018
update tests
edgarfgp Apr 23, 2025
65f5bb6
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 24, 2025
0c97b9d
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 27, 2025
6f2b706
update baselines
edgarfgp Apr 29, 2025
e8f1bb0
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 29, 2025
75d8f5e
Update baselines
edgarfgp Apr 29, 2025
4f2e97e
Merge branch 'fix-attr-targets' of github.com:edgarfgp/fsharp into fi…
edgarfgp Apr 29, 2025
63be5d5
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 30, 2025
4248f2a
Move attribute form logic to an AP
edgarfgp Apr 30, 2025
cc96217
Merge branch 'main' into fix-attr-targets
edgarfgp May 1, 2025
e270b88
Merge branch 'main' into fix-attr-targets
edgarfgp May 1, 2025
e0cc65a
Merge branch 'main' into fix-attr-targets
edgarfgp May 2, 2025
1e29d58
Merge branch 'main' into fix-attr-targets
edgarfgp May 5, 2025
1470bf9
Merge branch 'main' into fix-attr-targets
edgarfgp May 6, 2025
8988215
Merge branch 'main' into fix-attr-targets
edgarfgp May 7, 2025
74712e8
Merge branch 'main' into fix-attr-targets
edgarfgp May 12, 2025
967c4a9
Merge branch 'main' of github.com:edgarfgp/fsharp
edgarfgp May 13, 2025
a30cef4
Merge branch 'dotnet:main' into main
edgarfgp May 22, 2025
5fa0480
Merge branch 'dotnet:main' into main
edgarfgp May 24, 2025
15e3d34
Merge branch 'dotnet:main' into main
edgarfgp May 29, 2025
b7ffcf8
Merge branch 'dotnet:main' into main
edgarfgp Jun 6, 2025
5bde641
Merge branch 'dotnet:main' into main
edgarfgp Jul 26, 2025
0f7c23c
Merge branch 'dotnet:main' into main
edgarfgp Jul 29, 2025
6a6843c
Merge branch 'dotnet:main' into main
edgarfgp Aug 4, 2025
d11dd4a
Merge branch 'dotnet:main' into main
edgarfgp Aug 4, 2025
9d3c0f5
Remove LetOrUseBang
edgarfgp Aug 4, 2025
6cf1a9c
Update syntax tree tests
edgarfgp Aug 4, 2025
a0005ec
update baselines
edgarfgp Aug 4, 2025
f6c80c7
Update type checking to use LetOrUse
edgarfgp Aug 4, 2025
720eec5
Merge branch 'main' into unify-let-or-use
edgarfgp Aug 4, 2025
d380ef0
Update CheckComputationExpressions.fs
edgarfgp Aug 4, 2025
1b2d9e5
Update CheckExpressionsOps.fs
edgarfgp Aug 4, 2025
05e88b7
Update FileContentMapping.fs
edgarfgp Aug 4, 2025
ee9397a
Update FSharpParseFileResults.fs
edgarfgp Aug 4, 2025
b3db637
Service updates
edgarfgp Aug 4, 2025
f960746
Update CheckComputationExpressions.fs
edgarfgp Aug 5, 2025
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: 1 addition & 1 deletion src/Compiler/Checking/CheckRecordSyntaxHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,4 @@ let BindOriginalRecdExpr (withExpr: SynExpr * BlockSeparator) mkRecdExpr =
None,
SynBindingTrivia.Zero)

SynExpr.LetOrUse(false, false, [ binding ], mkRecdExpr (Some withExpr), mOrigExprSynth, SynExprLetOrUseTrivia.Zero)
SynExpr.LetOrUse(false, false, false, false, [ binding ], mkRecdExpr (Some withExpr), mOrigExprSynth, SynExprLetOrUseTrivia.Zero)
216 changes: 163 additions & 53 deletions src/Compiler/Checking/Expressions/CheckComputationExpressions.fs

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions src/Compiler/Checking/Expressions/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6072,7 +6072,7 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE
| SynExpr.DoBang (trivia = { DoBangKeyword = m })
| SynExpr.MatchBang (trivia = { MatchBangKeyword = m })
| SynExpr.WhileBang (range = m)
| SynExpr.LetOrUseBang (trivia = { LetOrUseKeyword = m }) ->
| SynExpr.LetOrUse(isComputed = true; trivia = { LetOrUseKeyword = m }) ->
error(Error(FSComp.SR.tcConstructRequiresComputationExpression(), m))

| SynExpr.IndexFromEnd (rightExpr, m) ->
Expand Down Expand Up @@ -9199,7 +9199,6 @@ and TcImplicitOpItemThen (cenv: cenv) overallTy env id sln tpenv mItem delayed =
| SynExpr.YieldOrReturn _
| SynExpr.YieldOrReturnFrom _
| SynExpr.MatchBang _
| SynExpr.LetOrUseBang _
| SynExpr.DoBang _
| SynExpr.WhileBang _
| SynExpr.TraitCall _
Expand Down Expand Up @@ -10614,7 +10613,7 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr synExpr cont =
TcLinearExprs bodyChecker cenv env2 overallTy tpenv isCompExpr expr2 (fun (expr2R, tpenv) ->
cont (Expr.Sequential (expr1R, expr2R, NormalSeq, 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
6 changes: 1 addition & 5 deletions src/Compiler/Checking/Expressions/CheckExpressionsOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,6 @@ let YieldFree (cenv: TcFileState) expr =
| SynExpr.While(doExpr = body)
| SynExpr.WhileBang(doExpr = body)
| SynExpr.ForEach(bodyExpr = body) -> YieldFree body

| SynExpr.LetOrUseBang(body = body) -> YieldFree body

| SynExpr.YieldOrReturn(flags = (true, _)) -> false

| _ -> true
Expand Down Expand Up @@ -232,7 +229,7 @@ let YieldFree (cenv: TcFileState) expr =
| SynExpr.WhileBang(doExpr = body)
| SynExpr.ForEach(bodyExpr = body) -> YieldFree body

| SynExpr.LetOrUseBang _
| SynExpr.LetOrUse(isComputed = true)
| SynExpr.YieldOrReturnFrom _
| SynExpr.YieldOrReturn _
| SynExpr.ImplicitZero _
Expand All @@ -256,7 +253,6 @@ let inline IsSimpleSemicolonSequenceElement expr cenv acceptDeprecated =
| SynExpr.LetOrUse _
| SynExpr.Do _
| SynExpr.MatchBang _
| SynExpr.LetOrUseBang _
| SynExpr.While _
| SynExpr.WhileBang _ -> false
| _ -> true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT
// The 'mBind' is attached to the lambda
Some(mkSeqUsing cenv env wholeExprMark bindPatTy genOuterTy inputExpr consumeExpr, tpenv)

| SynExpr.LetOrUseBang(range = m) -> error (Error(FSComp.SR.tcUseForInSequenceExpression (), m))
| SynExpr.LetOrUse(isComputed = true; range = m) -> error (Error(FSComp.SR.tcUseForInSequenceExpression (), m))

| SynExpr.Match(spMatch, expr, clauses, _m, _trivia) ->
let inputExpr, inputTy, tpenv = TcExprOfUnknownType cenv env tpenv expr
Expand Down
34 changes: 17 additions & 17 deletions src/Compiler/Driver/GraphChecking/FileContentMapping.fs
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,23 @@ let visitSynExpr (e: SynExpr) : FileContentEntry list =
visit funcExpr (fun funcNodes -> visit argExpr (fun argNodes -> funcNodes @ argNodes |> continuation))
| SynExpr.TypeApp(expr = expr; typeArgs = typeArgs) ->
visit expr (fun exprNodes -> exprNodes @ List.collect visitSynType typeArgs |> continuation)
| SynExpr.LetOrUse(bindings = bindings; body = body) ->
visit body (fun nodes -> List.collect visitBinding bindings @ nodes |> continuation)
| SynExpr.LetOrUse(isComputed = isComputed; bindings = bindings; body = body) ->
Copy link
Member

Choose a reason for hiding this comment

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

Likewise, do we need to distinguish the computed variant here? I'd expect the logic from LetOrUse to be reused.

if isComputed then
let bindingExprs = List.map (fun (SynBinding(expr = expr)) -> expr) bindings
let continuations = List.map visit (body :: bindingExprs)

let finalContinuation nodes =
[
yield! List.concat nodes
for SynBinding(headPat = pat) in bindings do
yield! visitPat pat
]
|> continuation

Continuation.sequence continuations finalContinuation
else
// Handle regular let and use expressions
visit body (fun nodes -> List.collect visitBinding bindings @ nodes |> continuation)
| SynExpr.TryWith(tryExpr = tryExpr; withCases = withCases) ->
visit tryExpr (fun nodes -> nodes @ List.collect visitSynMatchClause withCases |> continuation)
| SynExpr.TryFinally(tryExpr = tryExpr; finallyExpr = finallyExpr) ->
Expand Down Expand Up @@ -505,21 +520,6 @@ let visitSynExpr (e: SynExpr) : FileContentEntry list =
Continuation.concatenate continuations continuation
| SynExpr.YieldOrReturn(expr = expr) -> visit expr continuation
| SynExpr.YieldOrReturnFrom(expr = expr) -> visit expr continuation
| SynExpr.LetOrUseBang(pat = pat; rhs = rhs; andBangs = andBangs; body = body) ->
let continuations =
let andBangExprs = List.map (fun (SynBinding(expr = body)) -> body) andBangs
List.map visit (body :: rhs :: andBangExprs)

let finalContinuation nodes =
[
yield! List.concat nodes
yield! visitPat pat
for SynBinding(headPat = pat) in andBangs do
yield! visitPat pat
]
|> continuation

Continuation.sequence continuations finalContinuation
| SynExpr.MatchBang(expr = expr; clauses = clauses) ->
visit expr (fun exprNodes ->
[ yield! exprNodes; yield! List.collect visitSynMatchClause clauses ]
Expand Down
12 changes: 5 additions & 7 deletions src/Compiler/Service/FSharpParseFileResults.fs
Original file line number Diff line number Diff line change
Expand Up @@ -762,13 +762,11 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput,
yield! walkExpr false e2
yield! walkExpr false e3

| SynExpr.LetOrUseBang(spBind, _, _, _, rhsExpr, andBangs, bodyExpr, _, _) ->
yield! walkBindSeqPt spBind
yield! walkExpr true rhsExpr

for SynBinding(debugPoint = andBangSpBind; expr = eAndBang) in andBangs do
yield! walkBindSeqPt andBangSpBind
yield! walkExpr true eAndBang
| SynExpr.LetOrUse(isComputed = true; bindings = bindings; body = bodyExpr) ->
Copy link
Member

Choose a reason for hiding this comment

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

Isn't it covered on line 700?

// Handle all bindings (first let!/use! and all and! bindings)
for SynBinding(debugPoint = spBind; expr = bindingExpr) in bindings do
yield! walkBindSeqPt spBind
yield! walkExpr true bindingExpr

yield! walkExpr true bodyExpr
]
Expand Down
21 changes: 10 additions & 11 deletions src/Compiler/Service/ServiceInterfaceStubGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -904,8 +904,16 @@ module InterfaceStubGenerator =

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

| SynExpr.LetOrUse(bindings = synBindingList; body = synExpr) ->
Option.orElse (List.tryPick walkBinding synBindingList) (walkExpr synExpr)
| SynExpr.LetOrUse(isComputed = isComputed; bindings = synBindingList; body = synExpr) ->
if isComputed then
[
for SynBinding(expr = bindingExpr) in synBindingList do
yield bindingExpr
yield synExpr
]
|> List.tryPick walkExpr
else
Option.orElse (List.tryPick walkBinding synBindingList) (walkExpr synExpr)
Comment on lines +908 to +916
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if different logic is actually needed here. Would it work as expected if we just reuse the LetOrUse logic for the computed variants? It seems the tree traversal should be the same.


| SynExpr.TryWith(tryExpr = synExpr) -> walkExpr synExpr

Expand Down Expand Up @@ -956,15 +964,6 @@ module InterfaceStubGenerator =
| SynExpr.YieldOrReturnFrom(expr = synExpr)
| SynExpr.DoBang(expr = synExpr) -> walkExpr synExpr

| SynExpr.LetOrUseBang(rhs = synExpr1; andBangs = synExprAndBangs; body = synExpr2) ->
[
yield synExpr1
for SynBinding(expr = eAndBang) in synExprAndBangs do
yield eAndBang
yield synExpr2
]
|> List.tryPick walkExpr

Comment on lines -959 to -967
Copy link
Member

Choose a reason for hiding this comment

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

Not a suggestion in this particular case, but we could in theory match

| SynExpr.LetOrUse(isComputed = true; bindings = synBindingList; body = synExpr) ->

to minimize the diff in cases like this.

| SynExpr.LibraryOnlyILAssembly _
| SynExpr.LibraryOnlyStaticOptimization _
| SynExpr.LibraryOnlyUnionCaseFieldGet _
Expand Down
38 changes: 17 additions & 21 deletions src/Compiler/Service/ServiceParseTreeWalk.fs
Original file line number Diff line number Diff line change
Expand Up @@ -669,17 +669,27 @@ module SyntaxTraversal =
]
|> pick expr

| SynExpr.LetOrUse(isRecursive = isRecursive; bindings = synBindingList; body = synExpr; range = range) ->
match visitor.VisitLetOrUse(path, isRecursive, traverseSynBinding path, synBindingList, range) with
| None ->
| SynExpr.LetOrUse(
isRecursive = isRecursive; isComputed = isComputed; bindings = synBindingList; body = synExpr; range = range) ->
if isComputed then
[
yield!
synBindingList
|> List.map (fun x -> dive x x.RangeOfBindingWithRhs (traverseSynBinding path))
for SynBinding(headPat = pat; expr = bindingExpr) in synBindingList do
yield dive pat pat.Range traversePat
yield dive bindingExpr bindingExpr.Range traverseSynExpr
yield dive synExpr synExpr.Range traverseSynExpr
]
|> pick expr
| x -> x
else
match visitor.VisitLetOrUse(path, isRecursive, traverseSynBinding path, synBindingList, range) with
| None ->
[
yield!
synBindingList
|> List.map (fun x -> dive x x.RangeOfBindingWithRhs (traverseSynBinding path))
yield dive synExpr synExpr.Range traverseSynExpr
]
|> pick expr
| x -> x

| SynExpr.IfThenElse(ifExpr = synExpr; thenExpr = synExpr2; elseExpr = synExprOpt) ->
[
Expand Down Expand Up @@ -745,20 +755,6 @@ module SyntaxTraversal =
]
|> pick expr

| SynExpr.LetOrUseBang(pat = synPat; rhs = synExpr; andBangs = andBangSynExprs; body = synExpr2) ->
[
yield dive synPat synPat.Range traversePat
yield dive synExpr synExpr.Range traverseSynExpr
yield!
[
for SynBinding(headPat = andBangSynPat; expr = 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.Dynamic _
| SynExpr.Ident _
| SynExpr.LongIdent _
Expand Down
46 changes: 21 additions & 25 deletions src/Compiler/Service/ServiceParsedInputOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -834,9 +834,17 @@ module ParsedInput =
walkExprWithKind (Some EntityKind.Type) e
|> Option.orElseWith (fun () -> List.tryPick walkType tys)

| SynExpr.LetOrUse(bindings = bindings; body = e) ->
List.tryPick walkBinding bindings
|> Option.orElseWith (fun () -> walkExprWithKind parentKind e)
| SynExpr.LetOrUse(isComputed = isComputed; bindings = bindings; body = e) ->
if isComputed then
[
for SynBinding(expr = bindingExpr) in bindings do
yield bindingExpr
yield e
]
|> List.tryPick (walkExprWithKind parentKind)
else
List.tryPick walkBinding bindings
|> Option.orElseWith (fun () -> walkExprWithKind parentKind e)

| SynExpr.IfThenElse(ifExpr = e1; thenExpr = e2; elseExpr = e3) ->
walkExprWithKind parentKind e1
Expand All @@ -848,15 +856,6 @@ module ParsedInput =

| SynExpr.Ident ident -> ifPosInRange ident.idRange (fun _ -> Some(EntityKind.FunctionOrValue false))

| SynExpr.LetOrUseBang(rhs = e1; andBangs = es; body = e2) ->
[
yield e1
for SynBinding(expr = eAndBang) in es do
yield eAndBang
yield e2
]
|> List.tryPick (walkExprWithKind parentKind)

| SynExpr.TraitCall(TypesForTypar ts, sign, e, _) ->
List.tryPick walkType ts
|> Option.orElseWith (fun () -> walkMemberSig sign)
Expand Down Expand Up @@ -2111,9 +2110,16 @@ module ParsedInput =
List.iter walkType tys
walkExpr e

| SynExpr.LetOrUse(bindings = bindings; body = e) ->
List.iter walkBinding bindings
walkExpr e
| SynExpr.LetOrUse(isComputed = isComputed; bindings = bindings; body = e) ->
if isComputed then
for SynBinding(headPat = pat; expr = bindingExpr) in bindings do
walkPat pat
walkExpr bindingExpr

walkExpr e
else
List.iter walkBinding bindings
walkExpr e

| SynExpr.TryWith(tryExpr = e; withCases = clauses) ->
List.iter walkClause clauses
Expand Down Expand Up @@ -2155,16 +2161,6 @@ module ParsedInput =
walkExpr e2
walkExpr e3

| SynExpr.LetOrUseBang(pat = pat; rhs = e1; andBangs = es; body = e2) ->
walkPat pat
walkExpr e1

for SynBinding(headPat = patAndBang; expr = eAndBang) in es do
walkPat patAndBang
walkExpr eAndBang

walkExpr e2

| SynExpr.TraitCall(TypesForTypar ts, sign, e, _) ->
List.iter walkType ts
walkMemberSig sign
Expand Down
39 changes: 16 additions & 23 deletions src/Compiler/Service/ServiceStructure.fs
Original file line number Diff line number Diff line change
Expand Up @@ -258,33 +258,26 @@ module Structure =
rcheck Scope.Do Collapse.Below r <| Range.modStart 3 r
parseExpr e

| SynExpr.LetOrUseBang(pat = pat; rhs = eLet; andBangs = es; body = eBody) ->
let exprs =
[
eLet
for SynBinding(expr = eAndBang) in es do
eAndBang
]

for e in exprs do
// 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(doBody = e; range = r)
| SynExpr.ForEach(_, _, _, _, _, _, e, r) ->
rcheck Scope.For Collapse.Below r r
parseExpr e

| SynExpr.LetOrUse(bindings = bindings; body = body) ->
parseBindings bindings
parseExpr body
| SynExpr.LetOrUse(isComputed = isComputed; bindings = bindings; body = body) ->
if isComputed then
for SynBinding(headPat = pat; expr = expr) in bindings do
// 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 expr.Range
rcheck Scope.LetOrUseBang Collapse.Below r r
parseExpr expr

parseExpr body
else
parseBindings bindings
parseExpr body

| SynExpr.Match(matchDebugPoint = seqPointAtBinding; clauses = clauses; range = r)
| SynExpr.MatchBang(matchDebugPoint = seqPointAtBinding; clauses = clauses; range = r) ->
Expand Down Expand Up @@ -862,7 +855,7 @@ module Structure =
| _ -> loop (lineNum, None, result) rest (lineNum + 1)

let comments =
let (_, lastComment, comments) = loop (-1, None, []) (List.ofArray lines) 0
let _, lastComment, comments = loop (-1, None, []) (List.ofArray lines) 0

match lastComment with
| Some comment -> comment :: comments
Expand Down
5 changes: 1 addition & 4 deletions src/Compiler/Service/SynExpr.fs
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,7 @@ module SynExpr =
[<return: Struct>]
let (|LetOrUse|_|) =
dangling (function
| SynExpr.LetOrUse _
| SynExpr.LetOrUseBang _ as expr -> Some expr
| SynExpr.LetOrUse _ as expr -> Some expr
| _ -> None)

/// Matches a dangling sequential expression.
Expand Down Expand Up @@ -697,7 +696,6 @@ module SynExpr =
| _, SyntaxNode.SynExpr(SynExpr.Lazy _ as outer) :: _
| _, SyntaxNode.SynExpr(SynExpr.App(argExpr = SynExpr.Paren(expr = Is expr)) as outer) :: _
| _, SyntaxNode.SynExpr(SynExpr.LetOrUse _ as outer) :: _
| _, SyntaxNode.SynExpr(SynExpr.LetOrUseBang _ as outer) :: _
| _, SyntaxNode.SynExpr(SynExpr.TryWith _ as outer) :: _
| _, SyntaxNode.SynExpr(SynExpr.TryFinally _ as outer) :: _
| _, SyntaxNode.SynExpr(SynExpr.For _ as outer) :: _
Expand Down Expand Up @@ -1211,7 +1209,6 @@ module SynExpr =
| SynExpr.Match _, _
| SynExpr.MatchBang _, _
| SynExpr.LetOrUse _, _
| SynExpr.LetOrUseBang _, _
| SynExpr.Sequential _, _
| SynExpr.Do _, _
| SynExpr.DoBang _, _
Expand Down
Loading
Loading