diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2600981e3c5..0c6c6881251 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,7 @@ // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at: { "name": "F#", - "image": "mcr.microsoft.com/dotnet/sdk:9.0.100-rc.1", + "image": "mcr.microsoft.com/dotnet/sdk:9.0.100-rc.2", "features": { "ghcr.io/devcontainers/features/common-utils:2.5.1": {}, "ghcr.io/devcontainers/features/git:1.3.2": {}, diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 6a22a1cca73..11f7848a276 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,7 +4,7 @@ about: Create a report to help us improve F# title: '' labels: [Bug, Needs-Triage] assignees: '' - +type: 'Bug' --- Please provide a succinct description of the issue. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 9902369d951..a23d1feb39e 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -4,7 +4,7 @@ about: Suggest an idea for the F# tools or compiler title: '' labels: [Feature Request, Needs-Triage] assignees: '' - +type: 'Feature' --- **Is your feature request related to a problem? Please describe.** diff --git a/Directory.Build.props b/Directory.Build.props index 7f5b362cb34..8802ca237b5 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -10,6 +10,11 @@ $(DotNetBuildSourceOnly) + + + $(NoWarn);FS0064;FS1182 + + - false + true true $(MSBuildThisFileDirectory)artifacts/ diff --git a/azure-pipelines-PR.yml b/azure-pipelines-PR.yml index 0c7bc9b5a17..9a5c59441e2 100644 --- a/azure-pipelines-PR.yml +++ b/azure-pipelines-PR.yml @@ -488,6 +488,8 @@ stages: displayName: Publish Test Results inputs: testResultsFormat: 'XUnit' + testRunTitle: WindowsCompressedMetadata $(_testKind) + mergeTestResults: true testResultsFiles: '*.xml' searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_configuration)' continueOnError: true @@ -558,7 +560,9 @@ stages: displayName: Publish Test Results inputs: testResultsFormat: 'XUnit' + testRunTitle: Linux testResultsFiles: '*.xml' + mergeTestResults: true searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' continueOnError: true condition: always() @@ -602,6 +606,8 @@ stages: inputs: testResultsFormat: 'XUnit' testResultsFiles: '*.xml' + testRunTitle: MacOS + mergeTestResults: true searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' continueOnError: true condition: always() diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md index d350b30edbe..51115b5ead0 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md @@ -32,7 +32,7 @@ * Allow access modifies to auto properties getters and setters ([Language suggestion #430](https://github.com/fsharp/fslang-suggestions/issues/430), [PR 16687](https://github.com/dotnet/fsharp/pull/16687), [PR 16861](https://github.com/dotnet/fsharp/pull/16861), [PR 17522](https://github.com/dotnet/fsharp/pull/17522)) * Render C# nullable-analysis attributes in tooltips ([PR #17485](https://github.com/dotnet/fsharp/pull/17485)) * Allow object expression without overrides. ([Language suggestion #632](https://github.com/fsharp/fslang-suggestions/issues/632), [PR #17387](https://github.com/dotnet/fsharp/pull/17387)) -* Enable FSharp 9.0 Language Version ([Issue #17497](https://github.com/dotnet/fsharp/issues/17438)), [PR](https://github.com/dotnet/fsharp/pull/17500))) +* Enable FSharp 9.0 Language Version ([Issue #17497](https://github.com/dotnet/fsharp/issues/17497)), [PR](https://github.com/dotnet/fsharp/pull/17500))) * Enable LanguageFeature.EnforceAttributeTargets in F# 9.0. ([Issue #17514](https://github.com/dotnet/fsharp/issues/17558), [PR #17516](https://github.com/dotnet/fsharp/pull/17558)) * Parser: better recovery for unfinished patterns ([PR #17231](https://github.com/dotnet/fsharp/pull/17231), [PR #17232](https://github.com/dotnet/fsharp/pull/17232))) * Enable consuming generic arguments defined as `allows ref struct` in C# ([Issue #17597](https://github.com/dotnet/fsharp/issues/17597), display them in tooltips [PR #17706](https://github.com/dotnet/fsharp/pull/17706)) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md index 28f20ca2be2..185fa3a015f 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md @@ -5,6 +5,7 @@ * Fix extension methods support for non-reference system assemblies ([PR #17799](https://github.com/dotnet/fsharp/pull/17799)) * Ensure `frameworkTcImportsCache` mutations are thread-safe. ([PR #17795](https://github.com/dotnet/fsharp/pull/17795)) * Fix concurrency issue in `ILPreTypeDefImpl` ([PR #17812](https://github.com/dotnet/fsharp/pull/17812)) +* Fix nullness inference for member val and other OO scenarios ([PR #17845](https://github.com/dotnet/fsharp/pull/17845)) ### Added @@ -18,5 +19,7 @@ * Better ranges for CE `do!` error reporting. ([PR #17779](https://github.com/dotnet/fsharp/pull/17779)) * Better ranges for CE `return, yield, return! and yield!` error reporting. ([PR #17792](https://github.com/dotnet/fsharp/pull/17792)) * Better ranges for CE `match!`. ([PR #17789](https://github.com/dotnet/fsharp/pull/17789)) +* Better ranges for CE `use` error reporting. ([PR #17811](https://github.com/dotnet/fsharp/pull/17811)) +* Better ranges for `inherit` error reporting. ([PR #17879](https://github.com/dotnet/fsharp/pull/17879)) ### Breaking Changes diff --git a/eng/TSAConfig.gdntsa b/eng/TSAConfig.gdntsa index 56d3d0d457a..f4621b68272 100644 --- a/eng/TSAConfig.gdntsa +++ b/eng/TSAConfig.gdntsa @@ -1,7 +1,7 @@ { "codebaseName": "FSharp-GitHub", "notificationAliases": [ - "mlinfraswat@microsoft.com" + "fsharp@microsoft.com" ], "codebaseAdmins": [ "EUROPE\\vlza", diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a6fe9dd9339..e9557ab4f4e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,9 +1,9 @@ - + https://github.com/dotnet/source-build-reference-packages - 08649fed58d668737a54913f7d4c649a8da5dc6e + fd609e3b427601180d23633e2f1a4cdac6c42c20 diff --git a/eng/Versions.props b/eng/Versions.props index d89aec3f3cd..4252f548c66 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -37,7 +37,7 @@ $(FSMajorVersion).$(FSMinorVersion).$(FSBuildVersion) - 8.0.400 + 9.0.100-beta.24466.6 $(FSCorePackageVersionValue)-$(PreReleaseVersionLabel).* diff --git a/global.json b/global.json index b66eed16d21..3f653af33e0 100644 --- a/global.json +++ b/global.json @@ -1,10 +1,10 @@ { "sdk": { - "version": "9.0.100-rc.1.24452.12", + "version": "9.0.100-rc.2.24474.11", "allowPrerelease": true }, "tools": { - "dotnet": "9.0.100-rc.1.24452.12", + "dotnet": "9.0.100-rc.2.24474.11", "vs": { "version": "17.8", "components": [ diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index e739169ea9c..814374417d3 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -3622,7 +3622,11 @@ module EstablishTypeDefinitionCores = // Note: for a mutually recursive set we can't check this condition // until "isSealedTy" and "isClassTy" give reliable results. superTy |> Option.iter (fun ty -> - let m = match inherits with | [] -> m | (_, m, _) :: _ -> m + let m = + match inherits with + | [] -> m + | (synType, _, _) :: _ -> synType.Range + if isSealedTy g ty then errorR(Error(FSComp.SR.tcCannotInheritFromSealedType(), m)) elif not (isClassTy g ty) then @@ -4292,7 +4296,7 @@ module TcDeclarations = | SynMemberDefn.AutoProperty (range=m) :: _ -> errorR(InternalError("List.takeUntil is wrong, have auto property", m)) | SynMemberDefn.ImplicitInherit (range=m) :: _ -> errorR(Error(FSComp.SR.tcTypeDefinitionsWithImplicitConstructionMustHaveOneInherit(), m)) | SynMemberDefn.LetBindings (range=m) :: _ -> errorR(Error(FSComp.SR.tcTypeDefinitionsWithImplicitConstructionMustHaveLocalBindingsBeforeMembers(), m)) - | SynMemberDefn.Inherit (range=m) :: _ -> errorR(Error(FSComp.SR.tcInheritDeclarationMissingArguments(), m)) + | SynMemberDefn.Inherit (trivia= { InheritKeyword = m }) :: _ -> errorR(Error(FSComp.SR.tcInheritDeclarationMissingArguments(), m)) | SynMemberDefn.NestedType (range=m) :: _ -> errorR(Error(FSComp.SR.tcTypesCannotContainNestedTypes(), m)) | _ -> () | ds -> @@ -4464,7 +4468,7 @@ module TcDeclarations = let implements2 = members |> List.choose (function SynMemberDefn.Interface (interfaceType=ty) -> Some(ty, ty.Range) | _ -> None) let inherits = members |> List.choose (function - | SynMemberDefn.Inherit (ty, idOpt, m) -> Some(ty, m, idOpt) + | SynMemberDefn.Inherit (ty, idOpt, m, _) -> Some(ty, m, idOpt) | SynMemberDefn.ImplicitInherit (ty, _, idOpt, m) -> Some(ty, m, idOpt) | _ -> None) diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index c1aa4dafc5d..645897a6793 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -1805,11 +1805,8 @@ let rec TryTranslateComputationExpression | SynExpr.LetOrUse( isUse = true bindings = [ SynBinding(kind = SynBindingKind.Normal; headPat = pat; expr = rhsExpr; debugPoint = spBind) ] - body = innerComp) -> - let mBind = - match spBind with - | DebugPointAtBinding.Yes m -> m - | _ -> rhsExpr.Range + body = innerComp + trivia = { LetOrUseKeyword = mBind }) -> if ceenv.isQuery then error (Error(FSComp.SR.tcUseMayNotBeUsedInQueries (), mBind)) diff --git a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs index 781060c8af4..3154d3e1e74 100644 --- a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs @@ -232,9 +232,10 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT // 'use x = expr in expr' | SynExpr.LetOrUse( isUse = true - bindings = [ SynBinding(kind = SynBindingKind.Normal; headPat = pat; expr = rhsExpr; debugPoint = spBind) ] + bindings = [ SynBinding(kind = SynBindingKind.Normal; headPat = pat; expr = rhsExpr) ] body = innerComp - range = wholeExprMark) -> + range = wholeExprMark + trivia = { LetOrUseKeyword = mBind }) -> let bindPatTy = NewInferenceType g let inputExprTy = NewInferenceType g @@ -252,11 +253,6 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT let envinner = { envinner with eIsControlFlow = true } tcSequenceExprBody envinner genOuterTy tpenv innerComp - let mBind = - match spBind with - | DebugPointAtBinding.Yes m -> m.NoteSourceConstruct(NotedSourceConstruct.Binding) - | _ -> inputExpr.Range - let inputExprMark = inputExpr.Range let matchv, matchExpr = diff --git a/src/Compiler/Driver/GraphChecking/FileContentMapping.fs b/src/Compiler/Driver/GraphChecking/FileContentMapping.fs index 5fd190b1995..938034623ba 100644 --- a/src/Compiler/Driver/GraphChecking/FileContentMapping.fs +++ b/src/Compiler/Driver/GraphChecking/FileContentMapping.fs @@ -220,7 +220,7 @@ let visitSynMemberDefn (md: SynMemberDefn) : FileContentEntry list = | SynMemberDefn.Interface(interfaceType, _, members, _) -> yield! visitSynType interfaceType yield! collectFromOption (List.collect visitSynMemberDefn) members - | SynMemberDefn.Inherit(baseType, _, _) -> yield! visitSynType baseType + | SynMemberDefn.Inherit(baseType = t) -> yield! visitSynType t | SynMemberDefn.ValField(fieldInfo, _) -> yield! visitSynField fieldInfo | SynMemberDefn.NestedType _ -> () | SynMemberDefn.AutoProperty(attributes = attributes; typeOpt = typeOpt; synExpr = synExpr) -> diff --git a/src/Compiler/FSharp.Compiler.Service.fsproj b/src/Compiler/FSharp.Compiler.Service.fsproj index 45b5bda0d10..36b184502f1 100644 --- a/src/Compiler/FSharp.Compiler.Service.fsproj +++ b/src/Compiler/FSharp.Compiler.Service.fsproj @@ -24,8 +24,11 @@ $(FSharpNetCoreProductDefaultTargetFramework);$(TargetFrameworks) $(DefineConstants);FSHARPCORE_USE_PACKAGE $(OtherFlags) --extraoptimizationloops:1 + + - $(OtherFlags) --warnon:1182 + $(OtherFlags) --nowarn:1182 + $(OtherFlags) --warnon:3218 diff --git a/src/Compiler/Facilities/prim-parsing.fs b/src/Compiler/Facilities/prim-parsing.fs index bb61e76e5f3..7fb0d7fca41 100644 --- a/src/Compiler/Facilities/prim-parsing.fs +++ b/src/Compiler/Facilities/prim-parsing.fs @@ -151,7 +151,10 @@ module internal Implementation = //------------------------------------------------------------------------- // Read the tables written by FSYACC. - type AssocTable(elemTab: uint16[], offsetTab: uint16[], cache: int[], cacheSize: int) = + type AssocTable(elemTab: uint16[], offsetTab: uint16[], cache: int[]) = + + do Array.fill cache 0 cache.Length -1 + let cacheSize = cache.Length / 2 member t.ReadAssoc(minElemNum, maxElemNum, defaultValueOfAssoc, keyToFind) = // do a binary chop on the table @@ -273,13 +276,8 @@ module internal Implementation = let lhsPos = (Array.zeroCreate 2: Position[]) let reductions = tables.reductions let cacheSize = 7919 // the 1000'th prime - // Use a simpler hash table with faster lookup, but only one - // hash bucket per key. let actionTableCache = ArrayPool.Shared.Rent(cacheSize * 2) let gotoTableCache = ArrayPool.Shared.Rent(cacheSize * 2) - // Clear the arrays since ArrayPool does not - Array.Clear(actionTableCache, 0, actionTableCache.Length) - Array.Clear(gotoTableCache, 0, gotoTableCache.Length) use _cacheDisposal = { new IDisposable with @@ -289,10 +287,10 @@ module internal Implementation = } let actionTable = - AssocTable(tables.actionTableElements, tables.actionTableRowOffsets, actionTableCache, cacheSize) + AssocTable(tables.actionTableElements, tables.actionTableRowOffsets, actionTableCache) let gotoTable = - AssocTable(tables.gotos, tables.sparseGotoTableRowOffsets, gotoTableCache, cacheSize) + AssocTable(tables.gotos, tables.sparseGotoTableRowOffsets, gotoTableCache) let stateToProdIdxsTable = IdxToIdxListTable(tables.stateToProdIdxsTableElements, tables.stateToProdIdxsTableRowOffsets) diff --git a/src/Compiler/Service/FSharpParseFileResults.fs b/src/Compiler/Service/FSharpParseFileResults.fs index 2623cbde347..7b273f71430 100644 --- a/src/Compiler/Service/FSharpParseFileResults.fs +++ b/src/Compiler/Service/FSharpParseFileResults.fs @@ -814,7 +814,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput, | SynMemberDefn.Interface(members = Some membs) -> for m in membs do yield! walkMember m - | SynMemberDefn.Inherit(_, _, m) -> + | SynMemberDefn.Inherit(range = m) -> // can break on the "inherit" clause yield! checkRange m | SynMemberDefn.ImplicitInherit(_, arg, _, m) -> diff --git a/src/Compiler/Service/ServiceLexing.fs b/src/Compiler/Service/ServiceLexing.fs index 37990b026d1..083bae1d6d8 100644 --- a/src/Compiler/Service/ServiceLexing.fs +++ b/src/Compiler/Service/ServiceLexing.fs @@ -734,7 +734,7 @@ module internal LexerStateEncoding = ) | LexCont.EndLine(ifdefs, stringNest, econt) -> match econt with - | LexerEndlineContinuation.Skip(n, m) -> + | LexerEndlineContinuation.IfdefSkip(n, m) -> encodeLexCont ( FSharpTokenizerColorState.EndLineThenSkip, int64 n, @@ -834,7 +834,7 @@ module internal LexerStateEncoding = | FSharpTokenizerColorState.ExtendedInterpolatedString -> LexCont.String(ifdefs, stringNest, LexerStringStyle.ExtendedInterpolated, stringKind, delimLen, mkRange "file" p1 p1) | FSharpTokenizerColorState.EndLineThenSkip -> - LexCont.EndLine(ifdefs, stringNest, LexerEndlineContinuation.Skip(n1, mkRange "file" p1 p1)) + LexCont.EndLine(ifdefs, stringNest, LexerEndlineContinuation.IfdefSkip(n1, mkRange "file" p1 p1)) | FSharpTokenizerColorState.EndLineThenToken -> LexCont.EndLine(ifdefs, stringNest, LexerEndlineContinuation.Token) | _ -> LexCont.Token([], stringNest) diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fs b/src/Compiler/Service/ServiceParseTreeWalk.fs index e0957fe0140..ca1a1c5e657 100644 --- a/src/Compiler/Service/ServiceParseTreeWalk.fs +++ b/src/Compiler/Service/ServiceParseTreeWalk.fs @@ -996,7 +996,7 @@ module SyntaxTraversal = |> pick x | ok -> ok - | SynMemberDefn.Inherit(synType, _identOption, range) -> traverseInherit (synType, range) + | SynMemberDefn.Inherit(synType, _identOption, range, _) -> traverseInherit (synType, range) | SynMemberDefn.ValField _ -> None | SynMemberDefn.NestedType(synTypeDefn, _synAccessOption, _range) -> traverseSynTypeDefn path synTypeDefn diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index 0b3f0134545..cfbefd49ade 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -913,7 +913,7 @@ module ParsedInput = walkType t |> Option.orElseWith (fun () -> members |> Option.bind (List.tryPick walkMember)) - | SynMemberDefn.Inherit(t, _, _) -> walkType t + | SynMemberDefn.Inherit(baseType = t) -> walkType t | SynMemberDefn.ValField(fieldInfo = field) -> walkField field @@ -2240,7 +2240,7 @@ module ParsedInput = | SynMemberDefn.Interface(interfaceType = t; members = members) -> walkType t members |> Option.iter (List.iter walkMember) - | SynMemberDefn.Inherit(t, _, _) -> walkType t + | SynMemberDefn.Inherit(baseType = t) -> walkType t | SynMemberDefn.ValField(fieldInfo = field) -> walkField field | SynMemberDefn.NestedType(tdef, _, _) -> walkTypeDefn tdef | SynMemberDefn.AutoProperty(attributes = Attributes attrs; typeOpt = t; synExpr = e) -> diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs index 525faf3be3d..5f6588bd770 100644 --- a/src/Compiler/Service/service.fs +++ b/src/Compiler/Service/service.fs @@ -72,10 +72,10 @@ module CompileHelpers = try f exiter - 0 + None with e -> stopProcessingRecovery e range0 - 1 + Some e /// Compile using the given flags. Source files names are resolved via the FileSystem API. The output file must be given by a -o flag. let compileFromArgs (ctok, argv: string[], legacyReferenceResolver, tcImportsCapture, dynamicAssemblyCreator) = diff --git a/src/Compiler/Service/service.fsi b/src/Compiler/Service/service.fsi index 0e48a0d6360..3e4fde2229c 100644 --- a/src/Compiler/Service/service.fsi +++ b/src/Compiler/Service/service.fsi @@ -400,11 +400,12 @@ type public FSharpChecker = /// Compile using the given flags. Source files names are resolved via the FileSystem API. /// The output file must be given by a -o flag. /// The first argument is ignored and can just be "fsc.exe". + /// The method returns the collected diagnostics, and (possibly) a terminating exception. /// /// /// The command line arguments for the project build. /// An optional string used for tracing compiler operations associated with this request. - member Compile: argv: string[] * ?userOpName: string -> Async + member Compile: argv: string[] * ?userOpName: string -> Async /// /// Try to get type check results for a file. This looks up the results of recent type checks of the diff --git a/src/Compiler/SyntaxTree/LexHelpers.fs b/src/Compiler/SyntaxTree/LexHelpers.fs index 736e4be04f5..96b4a9a570b 100644 --- a/src/Compiler/SyntaxTree/LexHelpers.fs +++ b/src/Compiler/SyntaxTree/LexHelpers.fs @@ -249,7 +249,7 @@ let errorsInByteStringBuffer (buf: ByteBuffer) = else None -let newline (lexbuf: LexBuffer<_>) = lexbuf.EndPos <- lexbuf.EndPos.NextLine +let incrLine (lexbuf: LexBuffer<_>) = lexbuf.EndPos <- lexbuf.EndPos.NextLine let advanceColumnBy (lexbuf: LexBuffer<_>) n = lexbuf.EndPos <- lexbuf.EndPos.ShiftColumnBy(n) diff --git a/src/Compiler/SyntaxTree/LexHelpers.fsi b/src/Compiler/SyntaxTree/LexHelpers.fsi index 0ba901a05e0..63997f08988 100644 --- a/src/Compiler/SyntaxTree/LexHelpers.fsi +++ b/src/Compiler/SyntaxTree/LexHelpers.fsi @@ -101,7 +101,7 @@ type LargerThanOneByte = int type LargerThan127ButInsideByte = int val errorsInByteStringBuffer: ByteBuffer -> Option -val newline: Lexing.LexBuffer<'a> -> unit +val incrLine: Lexing.LexBuffer<'a> -> unit val advanceColumnBy: Lexing.LexBuffer<'a> -> n: int -> unit diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fs b/src/Compiler/SyntaxTree/ParseHelpers.fs index 8d62a724972..c11647ab0a5 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fs +++ b/src/Compiler/SyntaxTree/ParseHelpers.fs @@ -165,9 +165,10 @@ type LexerIfdefStack = LexerIfdefStackEntries /// Specifies how the 'endline' function in the lexer should continue after /// it reaches end of line or eof. The options are to continue with 'token' function /// or to continue with 'skip' function. +[] type LexerEndlineContinuation = | Token - | Skip of int * range: range + | IfdefSkip of int * range: range type LexerIfdefExpression = | IfdefAnd of LexerIfdefExpression * LexerIfdefExpression @@ -967,7 +968,7 @@ let checkEndOfFileError t = | LexCont.MLOnly(_, _, m) -> reportParseErrorAt m (FSComp.SR.parsEofInIfOcaml ()) - | LexCont.EndLine(_, _, LexerEndlineContinuation.Skip(_, m)) -> reportParseErrorAt m (FSComp.SR.parsEofInDirective ()) + | LexCont.EndLine(_, _, LexerEndlineContinuation.IfdefSkip(_, m)) -> reportParseErrorAt m (FSComp.SR.parsEofInDirective ()) | LexCont.EndLine(endifs, nesting, LexerEndlineContinuation.Token) | LexCont.Token(endifs, nesting) -> @@ -1049,7 +1050,22 @@ let mkLocalBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs, else Some mIn) - SynExpr.LetOrUse(isRec, isUse, decls, body, mWhole, { InKeyword = mIn }) + let mLetOrUse = + match decls with + | SynBinding(trivia = trivia) :: _ -> trivia.LeadingKeyword.Range + | _ -> Range.Zero + + SynExpr.LetOrUse( + isRec, + isUse, + decls, + body, + mWhole, + { + LetOrUseKeyword = mLetOrUse + InKeyword = mIn + } + ) let mkDefnBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs, _bindingSetRange), attrs, vis, attrsm) = if isUse then diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fsi b/src/Compiler/SyntaxTree/ParseHelpers.fsi index 52f4257d4c2..c98e7897a32 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fsi +++ b/src/Compiler/SyntaxTree/ParseHelpers.fsi @@ -67,7 +67,7 @@ type LexerIfdefStack = LexerIfdefStackEntries type LexerEndlineContinuation = | Token - | Skip of int * range: range + | IfdefSkip of int * range: range type LexerIfdefExpression = | IfdefAnd of LexerIfdefExpression * LexerIfdefExpression diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index fc0c811e55d..81e893592b8 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fs +++ b/src/Compiler/SyntaxTree/SyntaxTree.fs @@ -1496,7 +1496,7 @@ type SynMemberDefn = | Interface of interfaceType: SynType * withKeyword: range option * members: SynMemberDefns option * range: range - | Inherit of baseType: SynType * asIdent: Ident option * range: range + | Inherit of baseType: SynType * asIdent: Ident option * range: range * trivia: SynMemberDefnInheritTrivia | ValField of fieldInfo: SynField * range: range diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fsi b/src/Compiler/SyntaxTree/SyntaxTree.fsi index 45b03ad3b75..379362f407c 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTree.fsi @@ -1670,7 +1670,7 @@ type SynMemberDefn = | Interface of interfaceType: SynType * withKeyword: range option * members: SynMemberDefns option * range: range /// An 'inherit' definition within a class - | Inherit of baseType: SynType * asIdent: Ident option * range: range + | Inherit of baseType: SynType * asIdent: Ident option * range: range * trivia: SynMemberDefnInheritTrivia /// A 'val' definition within a class | ValField of fieldInfo: SynField * range: range diff --git a/src/Compiler/SyntaxTree/SyntaxTrivia.fs b/src/Compiler/SyntaxTree/SyntaxTrivia.fs index 10aee262292..2cd42701e70 100644 --- a/src/Compiler/SyntaxTree/SyntaxTrivia.fs +++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fs @@ -85,10 +85,15 @@ type SynExprDotLambdaTrivia = [] type SynExprLetOrUseTrivia = { + LetOrUseKeyword: range InKeyword: range option } - static member Zero: SynExprLetOrUseTrivia = { InKeyword = None } + static member Zero: SynExprLetOrUseTrivia = + { + InKeyword = None + LetOrUseKeyword = Range.Zero + } [] type SynExprLetOrUseBangTrivia = @@ -415,6 +420,9 @@ type SynMemberDefnAbstractSlotTrivia = static member Zero = { GetSetKeywords = None } +[] +type SynMemberDefnInheritTrivia = { InheritKeyword: range } + [] type SynFieldTrivia = { diff --git a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi index fff834beb41..ab6525bc010 100644 --- a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi @@ -129,6 +129,8 @@ type SynExprDotLambdaTrivia = [] type SynExprLetOrUseTrivia = { + /// The syntax range of the `let` or `use` keyword. + LetOrUseKeyword: range /// The syntax range of the `in` keyword. InKeyword: range option } @@ -520,6 +522,10 @@ type SynMemberDefnAbstractSlotTrivia = static member Zero: SynMemberDefnAbstractSlotTrivia +/// Represents additional information for SynMemberDefn.Inherit +[] +type SynMemberDefnInheritTrivia = { InheritKeyword: range } + /// Represents additional information for SynField [] type SynFieldTrivia = diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index b948e91fb65..b5e620c6bd6 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -4358,6 +4358,12 @@ type NullnessVar() = member nv.IsSolved = solution.IsSome + member nv.IsFullySolved = + match solution with + | None -> false + | Some (Nullness.Known _) -> true + | Some (Nullness.Variable v) -> v.IsFullySolved + member nv.Set(nullness) = assert (not nv.IsSolved) solution <- Some nullness diff --git a/src/Compiler/TypedTree/TypedTree.fsi b/src/Compiler/TypedTree/TypedTree.fsi index d357895728d..5f96fba2266 100644 --- a/src/Compiler/TypedTree/TypedTree.fsi +++ b/src/Compiler/TypedTree/TypedTree.fsi @@ -3100,6 +3100,7 @@ type NullnessVar = member Evaluate: unit -> NullnessInfo member TryEvaluate: unit -> NullnessInfo voption member IsSolved: bool + member IsFullySolved: bool member Set: Nullness -> unit member Unset: unit -> unit member Solution: Nullness diff --git a/src/Compiler/TypedTree/TypedTreeBasics.fs b/src/Compiler/TypedTree/TypedTreeBasics.fs index c8268ffcf8a..0ad62482b6a 100644 --- a/src/Compiler/TypedTree/TypedTreeBasics.fs +++ b/src/Compiler/TypedTree/TypedTreeBasics.fs @@ -284,7 +284,7 @@ let tryAddNullnessToTy nullnessNew (ty:TType) = let addNullnessToTy (nullness: Nullness) (ty:TType) = match nullness with | Nullness.Known NullnessInfo.WithoutNull -> ty - | Nullness.Variable nv when nv.IsSolved && nv.Evaluate() = NullnessInfo.WithoutNull -> ty + | Nullness.Variable nv when nv.IsFullySolved && nv.TryEvaluate() = ValueSome NullnessInfo.WithoutNull -> ty | _ -> match ty with | TType_var (tp, nullnessOrig) -> TType_var (tp, combineNullness nullnessOrig nullness) diff --git a/src/Compiler/lex.fsl b/src/Compiler/lex.fsl index fd95cd3ebce..9de91ebab74 100644 --- a/src/Compiler/lex.fsl +++ b/src/Compiler/lex.fsl @@ -194,9 +194,8 @@ let tryAppendXmlDoc (buff: (range * StringBuilder) option) (s:string) = // Utilities for parsing #if/#else/#endif -let shouldStartLine args lexbuf (m:range) err tok = - if (m.StartColumn <> 0) then fail args lexbuf err tok - else tok +let shouldStartLine args lexbuf (m:range) err = + if (m.StartColumn <> 0) then fail args lexbuf err () let shouldStartFile args lexbuf (m:range) err tok = if (m.StartColumn <> 0 || m.StartLine <> 1) then fail args lexbuf err tok @@ -334,6 +333,8 @@ let ident_char = let ident = ident_start_char ident_char* +// skip = true: skip whitespace (used by compiler, fsi etc) +// skip = false: send artificial tokens for whitespace (used by VS) rule token (args: LexArgs) (skip: bool) = parse | ident { Keywords.KeywordOrIdentifierToken args lexbuf (lexeme lexbuf) } @@ -752,7 +753,7 @@ rule token (args: LexArgs) (skip: bool) = parse else singleLineComment (None,1,m,m,args) skip lexbuf } | newline - { newline lexbuf + { incrLine lexbuf if not skip then WHITESPACE (LexCont.Token(args.ifdefStack, args.stringNest)) else token args skip lexbuf } @@ -819,12 +820,12 @@ rule token (args: LexArgs) (skip: bool) = parse lexbuf.EndPos <- pos.ApplyLineDirective((match file with Some f -> FileIndex.fileIndexOfFile f | None -> pos.FileIndex), line) else // add a newline when we don't apply a directive since we consumed a newline getting here - newline lexbuf + incrLine lexbuf token args skip lexbuf else // add a newline when we don't apply a directive since we consumed a newline getting here - newline lexbuf + incrLine lexbuf HASH_LINE (LexCont.Token (args.ifdefStack, args.stringNest)) } @@ -1030,56 +1031,47 @@ rule token (args: LexArgs) (skip: bool) = parse | anywhite* "#if" anywhite+ anystring { let m = lexbuf.LexemeRange + shouldStartLine args lexbuf m (FSComp.SR.lexHashIfMustBeFirst()) let lookup id = List.contains id args.conditionalDefines let lexed = lexeme lexbuf let isTrue, expr = evalIfDefExpression lexbuf.StartPos lexbuf.ReportLibraryOnlyFeatures lexbuf.LanguageVersion lexbuf.StrictIndentation args lookup lexed args.ifdefStack <- (IfDefIf,m) :: args.ifdefStack LexbufIfdefStore.SaveIfHash(lexbuf, lexed, expr, m) + let contCase = if isTrue then LexerEndlineContinuation.Token else LexerEndlineContinuation.IfdefSkip(0, m) + let tok = HASH_IF(m, lexed, LexCont.EndLine(args.ifdefStack, args.stringNest, contCase)) + if skip then endline contCase args skip lexbuf else tok } - // Get the token; make sure it starts at zero position & return - let cont, f = - if isTrue then - let cont = LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Token) - let f = endline LexerEndlineContinuation.Token args skip - cont, f - else - let cont = LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Skip(0, m)) - let f = endline (LexerEndlineContinuation.Skip(0, m)) args skip - cont, f - - let tok = shouldStartLine args lexbuf m (FSComp.SR.lexHashIfMustBeFirst()) (HASH_IF(m,lexed,cont)) - if not skip then tok else f lexbuf } - - | anywhite* "#else" anywhite* ("//" [^'\n''\r']*)? + | anywhite* "#else" anywhite* ("//" anystring)? { let lexed = (lexeme lexbuf) match args.ifdefStack with | [] -> LEX_FAILURE (FSComp.SR.lexHashElseNoMatchingIf()) | (IfDefElse,_) :: _rest -> LEX_FAILURE (FSComp.SR.lexHashEndifRequiredForElse()) | (IfDefIf,_) :: rest -> let m = lexbuf.LexemeRange + shouldStartLine args lexbuf m (FSComp.SR.lexHashElseMustBeFirst()) args.ifdefStack <- (IfDefElse,m) :: rest LexbufIfdefStore.SaveElseHash(lexbuf, lexed, m) - let tok = HASH_ELSE(m, lexed, LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Skip(0, m))) - let tok = shouldStartLine args lexbuf m (FSComp.SR.lexHashElseMustBeFirst()) tok - if not skip then tok else endline (LexerEndlineContinuation.Skip(0, m)) args skip lexbuf } + let tok = HASH_ELSE(m, lexed, LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.IfdefSkip(0, m))) + if skip then endline (LexerEndlineContinuation.IfdefSkip(0, m)) args skip lexbuf else tok } - | anywhite* "#endif" anywhite* ("//" [^'\n''\r']*)? + | anywhite* "#endif" anywhite* ("//" anystring)? { let lexed = (lexeme lexbuf) let m = lexbuf.LexemeRange match args.ifdefStack with | []-> LEX_FAILURE (FSComp.SR.lexHashEndingNoMatchingIf()) | _ :: rest -> + shouldStartLine args lexbuf m (FSComp.SR.lexHashEndifMustBeFirst()) args.ifdefStack <- rest LexbufIfdefStore.SaveEndIfHash(lexbuf, lexed, m) let tok = HASH_ENDIF(m,lexed,LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Token)) - let tok = shouldStartLine args lexbuf m (FSComp.SR.lexHashEndifMustBeFirst()) tok if not skip then tok else endline LexerEndlineContinuation.Token args skip lexbuf } | "#if" { let tok = WHITESPACE (LexCont.Token (args.ifdefStack, args.stringNest)) let tok = fail args lexbuf (FSComp.SR.lexHashIfMustHaveIdent()) tok - if not skip then tok else token args skip lexbuf } + if skip then token args skip lexbuf else tok } + // Let the parser deal with these invalid directives | anywhite* "#if" ident_char+ | anywhite* "#else" ident_char+ | anywhite* "#endif" ident_char+ @@ -1104,17 +1096,17 @@ and ifdefSkip (n: int) (m: range) (args: LexArgs) (skip: bool) = parse // If #if is the first thing on the line then increase depth, otherwise skip, because it is invalid (e.g. "(**) #if ...") if (m.StartColumn <> 0) then - if not skip then INACTIVECODE (LexCont.IfDefSkip(args.ifdefStack, args.stringNest, n, m)) - else ifdefSkip n m args skip lexbuf + if skip then ifdefSkip n m args skip lexbuf + else INACTIVECODE (LexCont.IfDefSkip(args.ifdefStack, args.stringNest, n, m)) else let lexed = lexeme lexbuf let lookup id = List.contains id args.conditionalDefines let _, expr = evalIfDefExpression lexbuf.StartPos lexbuf.ReportLibraryOnlyFeatures lexbuf.LanguageVersion lexbuf.StrictIndentation args lookup lexed LexbufIfdefStore.SaveIfHash(lexbuf, lexed, expr, m) - let tok = INACTIVECODE(LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Skip(n+1, m))) - if not skip then tok else endline (LexerEndlineContinuation.Skip(n+1, m)) args skip lexbuf } + let tok = INACTIVECODE(LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.IfdefSkip(n+1, m))) + if skip then endline (LexerEndlineContinuation.IfdefSkip(n+1, m)) args skip lexbuf else tok } - | anywhite* "#else" anywhite* ("//" [^'\n''\r']*)? + | anywhite* "#else" anywhite* ("//" anystring)? { let lexed = (lexeme lexbuf) let m = lexbuf.LexemeRange @@ -1132,12 +1124,12 @@ and ifdefSkip (n: int) (m: range) (args: LexArgs) (skip: bool) = parse args.ifdefStack <- (IfDefElse,m) :: rest if not skip then HASH_ELSE(m,lexed,LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Token)) else endline LexerEndlineContinuation.Token args skip lexbuf - else + else LexbufIfdefStore.SaveElseHash(lexbuf, lexed, m) - if not skip then INACTIVECODE(LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Skip(n, m))) - else endline (LexerEndlineContinuation.Skip(n, m)) args skip lexbuf } + if not skip then INACTIVECODE(LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.IfdefSkip(n, m))) + else endline (LexerEndlineContinuation.IfdefSkip(n, m)) args skip lexbuf } - | anywhite* "#endif" anywhite* ("//" [^'\n''\r']*)? + | anywhite* "#endif" anywhite* ("//" anystring)? { let lexed = lexeme lexbuf let m = lexbuf.LexemeRange @@ -1154,13 +1146,13 @@ and ifdefSkip (n: int) (m: range) (args: LexArgs) (skip: bool) = parse if not skip then HASH_ENDIF(m,lexed,LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Token)) else endline LexerEndlineContinuation.Token args skip lexbuf else + shouldStartLine args lexbuf m (FSComp.SR.lexWrongNestedHashEndif()) LexbufIfdefStore.SaveEndIfHash(lexbuf, lexed, m) - let tok = INACTIVECODE(LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Skip(n-1, m))) - let tok = shouldStartLine args lexbuf m (FSComp.SR.lexWrongNestedHashEndif()) tok - if not skip then tok else endline (LexerEndlineContinuation.Skip(n-1, m)) args skip lexbuf } + let tok = INACTIVECODE(LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.IfdefSkip(n-1, m))) + if not skip then tok else endline (LexerEndlineContinuation.IfdefSkip(n-1, m)) args skip lexbuf } | newline - { newline lexbuf; ifdefSkip n m args skip lexbuf } + { incrLine lexbuf; ifdefSkip n m args skip lexbuf } | [^ ' ' '\n' '\r' ]+ @@ -1180,13 +1172,13 @@ and ifdefSkip (n: int) (m: range) (args: LexArgs) (skip: bool) = parse // or end of file and then calls the lexing function specified by 'cont' - either token or ifdefSkip and endline (cont: LexerEndlineContinuation) (args: LexArgs) (skip: bool) = parse | newline - { newline lexbuf + { incrLine lexbuf match cont with | LexerEndlineContinuation.Token -> if not skip then WHITESPACE(LexCont.Token (args.ifdefStack, args.stringNest)) else token args skip lexbuf - | LexerEndlineContinuation.Skip(n, m) -> + | LexerEndlineContinuation.IfdefSkip(n, m) -> if not skip then INACTIVECODE (LexCont.IfDefSkip(args.ifdefStack, args.stringNest, n, m)) else ifdefSkip n m args skip lexbuf } @@ -1195,7 +1187,7 @@ and endline (cont: LexerEndlineContinuation) (args: LexArgs) (skip: bool) = pars { match cont with | LexerEndlineContinuation.Token -> EOF(LexCont.Token(args.ifdefStack, args.stringNest)) - | LexerEndlineContinuation.Skip(n, m) -> + | LexerEndlineContinuation.IfdefSkip(n, m) -> EOF(LexCont.IfDefSkip(args.ifdefStack, args.stringNest, n, m)) } @@ -1209,7 +1201,7 @@ and endline (cont: LexerEndlineContinuation) (args: LexArgs) (skip: bool) = pars and singleQuoteString (sargs: LexerStringArgs) (skip: bool) = parse | '\\' newline anywhite* { let (_buf, _fin, m, kind, args) = sargs - newline lexbuf + incrLine lexbuf let text = lexeme lexbuf let text2 = text |> String.filter (fun c -> c <> ' ' && c <> '\t') advanceColumnBy lexbuf (text.Length - text2.Length) @@ -1338,7 +1330,7 @@ and singleQuoteString (sargs: LexerStringArgs) (skip: bool) = parse | newline { let (buf, _fin, m, kind, args) = sargs - newline lexbuf + incrLine lexbuf addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.SingleQuote, kind, args.interpolationDelimiterLength, m)) @@ -1407,7 +1399,7 @@ and verbatimString (sargs: LexerStringArgs) (skip: bool) = parse | newline { let (buf, _fin, m, kind, args) = sargs - newline lexbuf + incrLine lexbuf addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.Verbatim, kind, args.interpolationDelimiterLength, m)) @@ -1500,7 +1492,7 @@ and tripleQuoteString (sargs: LexerStringArgs) (skip: bool) = parse | newline { let (buf, _fin, m, kind, args) = sargs - newline lexbuf + incrLine lexbuf addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.TripleQuote, kind, args.interpolationDelimiterLength, m)) @@ -1594,7 +1586,7 @@ and extendedInterpolatedString (sargs: LexerStringArgs) (skip: bool) = parse | newline { let (buf, _fin, m, kind, args) = sargs - newline lexbuf + incrLine lexbuf addUnicodeString buf (lexeme lexbuf) if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.ExtendedInterpolated, kind, args.interpolationDelimiterLength, m)) @@ -1711,7 +1703,7 @@ and singleLineComment (cargs: SingleLineCommentArgs) (skip: bool) = parse | newline { let buff,_n, mStart, mEnd, args = cargs trySaveXmlDoc lexbuf buff - newline lexbuf + incrLine lexbuf // Saves the documentation (if we're collecting any) into a buffer-local variable. if not skip then LINE_COMMENT (LexCont.Token(args.ifdefStack, args.stringNest)) else @@ -1773,7 +1765,7 @@ and comment (cargs: BlockCommentArgs) (skip: bool) = parse | newline { let n, m, args = cargs - newline lexbuf + incrLine lexbuf if not skip then COMMENT (LexCont.Comment(args.ifdefStack, args.stringNest, n, m)) else comment cargs skip lexbuf } | "*)" @@ -1807,7 +1799,7 @@ and comment (cargs: BlockCommentArgs) (skip: bool) = parse and stringInComment (n: int) (m: range) (args: LexArgs) (skip: bool) = parse // Follow string lexing, skipping tokens until it finishes | '\\' newline anywhite* - { newline lexbuf + { incrLine lexbuf if not skip then COMMENT (LexCont.StringInComment(args.ifdefStack, args.stringNest, LexerStringStyle.SingleQuote, n, m)) else stringInComment n m args skip lexbuf } @@ -1829,7 +1821,7 @@ and stringInComment (n: int) (m: range) (args: LexArgs) (skip: bool) = parse else comment (n, m, args) skip lexbuf } | newline - { newline lexbuf + { incrLine lexbuf if not skip then COMMENT (LexCont.StringInComment(args.ifdefStack, args.stringNest, LexerStringStyle.SingleQuote, n, m)) else stringInComment n m args skip lexbuf } @@ -1859,7 +1851,7 @@ and verbatimStringInComment (n: int) (m: range) (args: LexArgs) (skip: bool) = p else verbatimStringInComment n m args skip lexbuf } | newline - { newline lexbuf + { incrLine lexbuf if not skip then COMMENT (LexCont.StringInComment(args.ifdefStack, args.stringNest, LexerStringStyle.Verbatim, n, m)) else verbatimStringInComment n m args skip lexbuf } @@ -1885,7 +1877,7 @@ and tripleQuoteStringInComment (n: int) (m: range) (args: LexArgs) (skip: bool) else tripleQuoteStringInComment n m args skip lexbuf } | newline - { newline lexbuf + { incrLine lexbuf if not skip then COMMENT (LexCont.StringInComment(args.ifdefStack, args.stringNest, LexerStringStyle.TripleQuote, n, m)) else tripleQuoteStringInComment n m args skip lexbuf } @@ -1907,7 +1899,7 @@ and mlOnly (m: range) (args: LexArgs) (skip: bool) = parse else mlOnly m args skip lexbuf } | newline - { newline lexbuf + { incrLine lexbuf if not skip then COMMENT (LexCont.MLOnly(args.ifdefStack, args.stringNest, m)) else mlOnly m args skip lexbuf } diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 185bd1ed842..fac3f30a073 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -2316,7 +2316,8 @@ opt_classDefn: inheritsDefn: | INHERIT atomTypeNonAtomicDeprecated optBaseSpec { let mDecl = unionRanges (rhs parseState 1) $2.Range - SynMemberDefn.Inherit($2, $3, mDecl) } + let trivia = { InheritKeyword = rhs parseState 1 } + SynMemberDefn.Inherit($2, $3, mDecl, trivia) } | INHERIT atomTypeNonAtomicDeprecated opt_HIGH_PRECEDENCE_APP atomicExprAfterType optBaseSpec { let mDecl = unionRanges (rhs parseState 1) $4.Range @@ -2324,8 +2325,9 @@ inheritsDefn: | INHERIT ends_coming_soon_or_recover { let mDecl = (rhs parseState 1) + let trivia = { InheritKeyword = (rhs parseState 1) } if not $2 then errorR (Error(FSComp.SR.parsTypeNameCannotBeEmpty (), mDecl)) - SynMemberDefn.Inherit(SynType.LongIdent(SynLongIdent([], [], [])), None, mDecl) } + SynMemberDefn.Inherit(SynType.LongIdent(SynLongIdent([], [], [])), None, mDecl, trivia) } optAsSpec: | asSpec diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Ifdef.fs b/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Ifdef.fs new file mode 100644 index 00000000000..99d019504d6 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Ifdef.fs @@ -0,0 +1,57 @@ +namespace CompilerDirectives + +open Xunit +open FSharp.Test.Compiler + +module Ifdef = + + let ifdefSource = """ +[] +let main _ = + #if MYDEFINE1 + 1 + #else + 2 + #endif +""" + + [] + [] + [] + let ifdefTest (mydefine, expectedExitCode) = + + FSharp ifdefSource + |> withDefines [mydefine] + |> compileExeAndRun + |> withExitCode expectedExitCode + + + let sourceExtraEndif = """ +#if MYDEFINE1 +printf "1" +#endif +(**)#endif(**) +0 +""" + + [] + let extraEndif () = + + FSharp sourceExtraEndif + |> withDefines ["MYDEFINE1"] + |> asExe + |> compile + |> withDiagnosticMessage "#endif has no matching #if in implementation file" + + let sourceUnknownHash = """ +module A +#ifxx +#abc +""" + + [] + let unknownHashDirectiveIsIgnored () = + + FSharp sourceUnknownHash + |> compile + |> shouldSucceed \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs index 72dd62e397c..7b65ba798fe 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs @@ -2,164 +2,149 @@ module CompilerService.AsyncMemoize open System open System.Threading -open Xunit open Internal.Utilities.Collections open System.Threading.Tasks open System.Diagnostics -open System.Collections.Concurrent + open FSharp.Compiler.DiagnosticsLogger open FSharp.Compiler.Diagnostics -open FSharp.Compiler.BuildGraph +open Xunit -let timeout = TimeSpan.FromSeconds 10. +[] +module internal JobEvents = -let waitFor (mre: ManualResetEvent) = - if not <| mre.WaitOne timeout then - failwith "waitFor timed out" + let publishEvent (cache: AsyncMemoize<_, _, _>) = + let wrapper = Event<_>() + cache.OnEvent (fun e -> lock wrapper <| fun () -> wrapper.Trigger e) + wrapper.Publish |> Event.map (fun (jobEvent, (_,k,_)) -> jobEvent, k) -let waitUntil condition value = - task { - let sw = Stopwatch.StartNew() - while not <| condition value do - if sw.Elapsed > timeout then - failwith "waitUntil timed out" - do! Task.Delay 10 - } + let collectEvents cache = + cache |> publishEvent |> Event.scan (fun es e -> e :: es) [] |> Event.map List.rev -let rec internal spinFor (duration: TimeSpan) = - async { - let sw = Stopwatch.StartNew() - do! Async.Sleep 10 - let remaining = duration - sw.Elapsed - if remaining > TimeSpan.Zero then - return! spinFor remaining - } - -#if BUILDING_WITH_LKG -type internal EventRecorder<'a, 'b, 'c when 'a : equality and 'b : equality>(memoize: AsyncMemoize<'a,'b,'c>) as self = -#else -type internal EventRecorder<'a, 'b, 'c when 'a : equality and 'b : equality and 'a:not null and 'b:not null>(memoize: AsyncMemoize<'a,'b,'c>) as self = -#endif + /// Exposes a live view of the list of JobEvents generated by AsyncMemoize. + let observe cache = + let updateAvailable = new AutoResetEvent(false) + let mutable recorded = [] - let events = ConcurrentQueue() + let update next = + Debug.WriteLine $"%A{next}" + recorded <- next + updateAvailable.Set() |> ignore - do memoize.OnEvent self.Add + collectEvents cache |> Event.add update - member _.Add (e, (_label, k, _version)) = events.Enqueue (e, k) + let waitForUpdate = updateAvailable |> Async.AwaitWaitHandle |> Async.Ignore - member _.Received value = events |> Seq.exists (fst >> (=) value) - - member _.CountOf value count = events |> Seq.filter (fst >> (=) value) |> Seq.length |> (=) count + async { + Debug.WriteLine $"current: %A{recorded}" + return recorded, waitForUpdate + } - member _.ShouldBe (expected) = - let expected = expected |> Seq.toArray - let actual = events |> Seq.toArray - Assert.Equal<_ array>(expected, actual) + let countOf value count events = events |> Seq.filter (fst >> (=) value) |> Seq.length |> (=) count - member _.Sequence = events |> Seq.map id + let received value events = events |> Seq.exists (fst >> (=) value) + let waitUntil observedCache condition = + let rec loop() = async { + let! current, waitForUpdate = observedCache + if current |> condition |> not then + do! waitForUpdate + return! loop() + } + loop() [] let ``Basics``() = - - let computation key = async { - do! Async.Sleep 1 - return key * 2 - } - - let memoize = AsyncMemoize() - let events = EventRecorder(memoize) - - let result = - seq { - memoize.Get'(5, computation 5) - memoize.Get'(5, computation 5) - memoize.Get'(2, computation 2) - memoize.Get'(5, computation 5) - memoize.Get'(3, computation 3) - memoize.Get'(2, computation 2) + task { + let computation key = async { + do! Async.Sleep 1 + return key * 2 } - |> Async.Parallel - |> Async.RunSynchronously - let expected = [| 10; 10; 4; 10; 6; 4|] + let memoize = AsyncMemoize() + let events = observe memoize + + let result = + seq { + memoize.Get'(5, computation 5) + memoize.Get'(5, computation 5) + memoize.Get'(2, computation 2) + memoize.Get'(5, computation 5) + memoize.Get'(3, computation 3) + memoize.Get'(2, computation 2) + } + |> Async.Parallel + |> Async.RunSynchronously - Assert.Equal(expected, result) + let expected = [| 10; 10; 4; 10; 6; 4|] - (waitUntil (events.CountOf Finished) 3).Wait() + Assert.Equal(expected, result) - let groups = events.Sequence |> Seq.groupBy snd |> Seq.toList - Assert.Equal(3, groups.Length) - for key, events in groups do - Assert.Equal>(Set [ Requested, key; Started, key; Finished, key ], Set events) + do! waitUntil events (countOf Finished 3) + let! current, _ = events + let groups = current |> Seq.groupBy snd |> Seq.toList + Assert.Equal(3, groups.Length) + for key, events in groups do + Assert.Equal>(Set [ Requested, key; Started, key; Finished, key ], Set events) + } [] let ``We can cancel a job`` () = task { - let jobStarted = new ManualResetEvent(false) + let jobStarted = new ManualResetEventSlim(false) + let cts = new CancellationTokenSource() + let ctsCancelled = new ManualResetEventSlim(false) - let computation action = async { - action() |> ignore - do! spinFor timeout + let computation = async { + use! _catch = Async.OnCancel ignore + jobStarted.Set() + ctsCancelled.Wait() + do! async { } failwith "Should be canceled before it gets here" } let memoize = AsyncMemoize<_, int, _>() - let events = EventRecorder(memoize) - - use cts1 = new CancellationTokenSource() - use cts2 = new CancellationTokenSource() - use cts3 = new CancellationTokenSource() + let events = observe memoize let key = 1 - let _task1 = Async.StartAsTask( memoize.Get'(key, computation jobStarted.Set), cancellationToken = cts1.Token) - - waitFor jobStarted - jobStarted.Reset() |> ignore + let _task1 = Async.StartAsTask( memoize.Get'(1, computation), cancellationToken = cts.Token) - let _task2 = Async.StartAsTask( memoize.Get'(key, computation ignore), cancellationToken = cts2.Token) - let _task3 = Async.StartAsTask( memoize.Get'(key, computation ignore), cancellationToken = cts3.Token) + jobStarted.Wait() + cts.Cancel() + ctsCancelled.Set() - do! waitUntil (events.CountOf Requested) 3 + do! waitUntil events (received Canceled) + let! current, _ = events - cts1.Cancel() - cts2.Cancel() - - waitFor jobStarted - - cts3.Cancel() - - do! waitUntil events.Received Canceled - - events.ShouldBe [ - Requested, key - Started, key - Requested, key - Requested, key - Restarted, key - Canceled, key - ] + Assert.Equal<_ list>( + [ + Requested, key + Started, key + Canceled, key + ], + current + ) } [] let ``Job is restarted if first requestor cancels`` () = task { - let jobStarted = new ManualResetEvent(false) + let jobStarted = new SemaphoreSlim(0) - let jobCanComplete = new ManualResetEvent(false) + let jobCanComplete = new ManualResetEventSlim(false) let computation key = async { - jobStarted.Set() |> ignore - waitFor jobCanComplete + jobStarted.Release() |> ignore + + jobCanComplete.Wait() return key * 2 } let memoize = AsyncMemoize<_, int, _>() - let events = EventRecorder(memoize) - + let events = observe memoize use cts1 = new CancellationTokenSource() use cts2 = new CancellationTokenSource() @@ -169,48 +154,49 @@ let ``Job is restarted if first requestor cancels`` () = let _task1 = Async.StartAsTask( memoize.Get'(key, computation key), cancellationToken = cts1.Token) - waitFor jobStarted - jobStarted.Reset() |> ignore - + do! jobStarted.WaitAsync() let _task2 = Async.StartAsTask( memoize.Get'(key, computation key), cancellationToken = cts2.Token) let _task3 = Async.StartAsTask( memoize.Get'(key, computation key), cancellationToken = cts3.Token) - do! waitUntil (events.CountOf Requested) 3 + do! waitUntil events (countOf Requested 3) cts1.Cancel() - waitFor jobStarted - jobCanComplete.Set() |> ignore + do! jobStarted.WaitAsync() + let! result = _task2 Assert.Equal(2, result) - events.ShouldBe [ - Requested, key + let! current, _ = events + + Assert.Equal<_ list>( + [ Requested, key Started, key Requested, key Requested, key Restarted, key - Finished, key ] + Finished, key ], + current + ) } [] let ``Job is restarted if first requestor cancels but keeps running if second requestor cancels`` () = task { - let jobStarted = new ManualResetEvent(false) + let jobStarted = new ManualResetEventSlim(false) - let jobCanComplete = new ManualResetEvent(false) + let jobCanComplete = new ManualResetEventSlim(false) let computation key = async { jobStarted.Set() |> ignore - waitFor jobCanComplete + jobCanComplete.Wait() return key * 2 } let memoize = AsyncMemoize<_, int, _>() - let events = EventRecorder(memoize) - + let events = observe memoize use cts1 = new CancellationTokenSource() use cts2 = new CancellationTokenSource() @@ -220,17 +206,17 @@ let ``Job is restarted if first requestor cancels but keeps running if second re let _task1 = Async.StartAsTask( memoize.Get'(key, computation key), cancellationToken = cts1.Token) - waitFor jobStarted + jobStarted.Wait() jobStarted.Reset() |> ignore let _task2 = Async.StartAsTask( memoize.Get'(key, computation key), cancellationToken = cts2.Token) let _task3 = Async.StartAsTask( memoize.Get'(key, computation key), cancellationToken = cts3.Token) - do! waitUntil (events.CountOf Requested) 3 + do! waitUntil events (countOf Requested 3) cts1.Cancel() - waitFor jobStarted + jobStarted.Wait() cts2.Cancel() @@ -239,13 +225,17 @@ let ``Job is restarted if first requestor cancels but keeps running if second re let! result = _task3 Assert.Equal(2, result) - events.ShouldBe [ - Requested, key + let! current, _ = events + + Assert.Equal<_ list>( + [ Requested, key Started, key Requested, key Requested, key Restarted, key - Finished, key ] + Finished, key ], + current + ) } @@ -376,59 +366,56 @@ let ``Stress test`` () = [] [] let ``Cancel running jobs with the same key`` cancelDuplicate expectFinished = - task { - let cache = AsyncMemoize(cancelDuplicateRunningJobs=cancelDuplicate) - - let mutable started = 0 - let mutable finished = 0 + let cache = AsyncMemoize(cancelDuplicateRunningJobs=cancelDuplicate) - let job1started = new ManualResetEvent(false) - let job1finished = new ManualResetEvent(false) + let mutable started = 0 + let mutable finished = 0 - let jobCanContinue = new ManualResetEvent(false) + let job1started = new ManualResetEventSlim(false) + let job1finished = new ManualResetEventSlim(false) - let job2started = new ManualResetEvent(false) - let job2finished = new ManualResetEvent(false) + let jobCanContinue = new ManualResetEventSlim(false) - let work onStart onFinish = async { - Interlocked.Increment &started |> ignore - onStart() |> ignore - waitFor jobCanContinue - do! spinFor (TimeSpan.FromMilliseconds 100) - Interlocked.Increment &finished |> ignore - onFinish() |> ignore - } + let job2started = new ManualResetEventSlim(false) + let job2finished = new ManualResetEventSlim(false) - let key1 = - { new ICacheKey<_, _> with - member _.GetKey() = 1 - member _.GetVersion() = 1 - member _.GetLabel() = "key1" } + let work onStart onFinish = async { + Interlocked.Increment &started |> ignore + onStart() |> ignore + jobCanContinue.Wait() + do! Async.Sleep 100 + Interlocked.Increment &finished |> ignore + onFinish() |> ignore + } - cache.Get(key1, work job1started.Set job1finished.Set) |> Async.Start + let key1 = + { new ICacheKey<_, _> with + member _.GetKey() = 1 + member _.GetVersion() = 1 + member _.GetLabel() = "key1" } - waitFor job1started + cache.Get(key1, work job1started.Set job1finished.Set) |> Async.Catch |> Async.Ignore |> Async.Start - let key2 = - { new ICacheKey<_, _> with - member _.GetKey() = key1.GetKey() - member _.GetVersion() = key1.GetVersion() + 1 - member _.GetLabel() = "key2" } + job1started.Wait() - cache.Get(key2, work job2started.Set job2finished.Set ) |> Async.Start + let key2 = + { new ICacheKey<_, _> with + member _.GetKey() = key1.GetKey() + member _.GetVersion() = key1.GetVersion() + 1 + member _.GetLabel() = "key2" } - waitFor job2started + cache.Get(key2, work job2started.Set job2finished.Set ) |> Async.Catch |> Async.Ignore |> Async.Start - jobCanContinue.Set() |> ignore + job2started.Wait() - waitFor job2finished + jobCanContinue.Set() |> ignore - if not cancelDuplicate then - waitFor job1finished - - Assert.Equal((2, expectFinished), (started, finished)) - } + job2finished.Wait() + + if not cancelDuplicate then + job1finished.Wait() + Assert.Equal((2, expectFinished), (started, finished)) type DummyException(msg) = inherit Exception(msg) @@ -490,7 +477,7 @@ let ``Preserve thread static diagnostics`` () = let diagnostics = diagnosticsLogger.GetDiagnostics() - //Assert.Equal(3, diagnostics.Length) + Assert.Equal(4, diagnostics.Length) return result, diagnostics } @@ -498,9 +485,9 @@ let ``Preserve thread static diagnostics`` () = let results = (Task.WhenAll tasks).Result - let _diagnosticCounts = results |> Seq.map snd |> Seq.map Array.length |> Seq.groupBy id |> Seq.map (fun (k, v) -> k, v |> Seq.length) |> Seq.sortBy fst |> Seq.toList + let diagnosticCounts = results |> Seq.map snd |> Seq.map Array.length |> Seq.groupBy id |> Seq.map (fun (k, v) -> k, v |> Seq.length) |> Seq.sortBy fst |> Seq.toList - //Assert.Equal<(int * int) list>([4, 100], diagnosticCounts) + Assert.Equal<(int * int) list>([4, 100], diagnosticCounts) let diagnosticMessages = results |> Seq.map snd |> Seq.map (Array.map (fun (d, _) -> d.Exception.Message) >> Array.toList) |> Set @@ -523,7 +510,7 @@ let ``Preserve thread static diagnostics already completed job`` () = return Ok input } - async { + task { let diagnosticsLogger = CompilationDiagnosticLogger($"Testing", FSharpDiagnosticOptions.Default) @@ -534,10 +521,9 @@ let ``Preserve thread static diagnostics already completed job`` () = let diagnosticMessages = diagnosticsLogger.GetDiagnostics() |> Array.map (fun (d, _) -> d.Exception.Message) |> Array.toList - Assert.Equal>(["job 1 error"; "job 1 error"], diagnosticMessages) + Assert.Equal<_ list>(["job 1 error"; "job 1 error"], diagnosticMessages) } - |> Async.StartAsTask [] @@ -550,34 +536,22 @@ let ``We get diagnostics from the job that failed`` () = member _.GetVersion() = 1 member _.GetLabel() = "job1" } - let job (input: int) = async { - let ex = DummyException($"job {input} error") - do! Async.Sleep 100 - DiagnosticsThreadStatics.DiagnosticsLogger.Error(ex) + let job = async { + let ex = DummyException($"job error") + + // no recovery + DiagnosticsThreadStatics.DiagnosticsLogger.Error ex return 5 } - let result = - [1; 2] - |> Seq.map (fun i -> - async { - let diagnosticsLogger = CompilationDiagnosticLogger($"Testing", FSharpDiagnosticOptions.Default) - - use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Optimize) - try - let! _ = cache.Get(key, job i ) - () - with _ -> - () - let diagnosticMessages = diagnosticsLogger.GetDiagnostics() |> Array.map (fun (d, _) -> d.Exception.Message) |> Array.toList - - return diagnosticMessages - }) - |> Async.Parallel - |> Async.StartAsTask - |> (fun t -> t.Result) - |> Array.toList - - Assert.True( - result = [["job 1 error"]; ["job 1 error"]] || - result = [["job 2 error"]; ["job 2 error"]] ) + task { + let logger = CapturingDiagnosticsLogger("AsyncMemoize diagnostics test") + + SetThreadDiagnosticsLoggerNoUnwind logger + + do! cache.Get(key, job ) |> Async.Catch |> Async.Ignore + + let messages = logger.Diagnostics |> List.map fst |> List.map _.Exception.Message + + Assert.Equal<_ list>(["job error"], messages) + } diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs index f6d8a0cc530..9b7cdc5a053 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs @@ -933,3 +933,36 @@ and [] |> verifyCompile |> shouldSucceed #endif + + [] // Regression for https://github.com/dotnet/fsharp/issues/14304 + let ``Construct an object with default and params parameters using parameterless constructor`` () = + Fsx """ +open System +open System.Runtime.InteropServices + +type DefaultAndParams([]x: int, [] value: string[]) = + inherit Attribute() + +type ParamsOnly([] value: string[]) = + inherit Attribute() + +type DefaultOnly([]x: int) = + inherit Attribute() + +[] +type Q1 = struct end + +[] // ok +type Q11 = struct end + +[] // ok +type Q12 = struct end + +[] +type Q2 = struct end + +[] +type Q3 = struct end + """ + |> typecheck + |> shouldSucceed \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ExceptionDefinitions/ExceptionDefinitions.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ExceptionDefinitions/ExceptionDefinitions.fs index fb7785d3758..1ec630b6e98 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ExceptionDefinitions/ExceptionDefinitions.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ExceptionDefinitions/ExceptionDefinitions.fs @@ -289,7 +289,7 @@ module ExceptionDefinition = |> compile |> shouldFail |> withDiagnostics [ - (Error 945, Line 9, Col 5, Line 9, Col 24, "Cannot inherit a sealed type") + (Error 945, Line 9, Col 13, Line 9, Col 22, "Cannot inherit a sealed type") (Error 1133, Line 9, Col 5, Line 9, Col 24, "No constructors are available for the type 'FSharpExn'") ] diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/TypeAbbreviations/TypeAbbreviations.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/TypeAbbreviations/TypeAbbreviations.fs index 80db08b3025..365f1af46b7 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/TypeAbbreviations/TypeAbbreviations.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/TypeAbbreviations/TypeAbbreviations.fs @@ -157,7 +157,7 @@ module TypeAbbreviations = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 945, Line 9, Col 9, Line 9, Col 22, "Cannot inherit a sealed type") + (Error 945, Line 9, Col 17, Line 9, Col 22, "Cannot inherit a sealed type") ] //SOURCE=E_PrivateTypeAbbreviation02.fs SCFLAGS="--test:ErrorRanges" # E_PrivateTypeAbbreviation02.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs index 26acb4b9d0f..0c61d444a9d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs @@ -195,8 +195,8 @@ module UnionTypes = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 961, Line 10, Col 5, Line 10, Col 22, "This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e.g. 'inherit BaseType(args)'.") - (Error 945, Line 10, Col 5, Line 10, Col 22, "Cannot inherit a sealed type") + (Error 961, Line 10, Col 5, Line 10, Col 12, "This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e.g. 'inherit BaseType(args)'.") + (Error 945, Line 10, Col 13, Line 10, Col 22, "Cannot inherit a sealed type") ] //SOURCE=E_LowercaseDT.fs # E_LowercaseDT.fs diff --git a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs index b3c33031acb..c560008da0c 100644 --- a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs +++ b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs @@ -45,7 +45,6 @@ else () |> compile |> run |> shouldSucceed - |> withExitCode 0 [] let ``Respect nowarn 957 for extension method`` () = diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs index d2dc41a3235..1477db7754c 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs @@ -176,37 +176,118 @@ let [] x = System.Int32.MaxValue + 1 } [] - let ``Arithmetic can be used for constructing decimal literals``() = + let ``Decimal literals are properly initialized``() = FSharp """ -module LiteralArithmetic +module DecimalInit [] -let x = 1m + 2m +let x = 5.5m """ |> withLangVersion80 |> compile |> shouldSucceed |> verifyIL [ - """.field public static initonly valuetype [runtime]System.Decimal x""" - """.custom instance void [runtime]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + """ +.class public abstract auto ansi sealed DecimalInit + extends [runtime]System.Object +{ + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .field public static initonly valuetype [runtime]System.Decimal x + .custom instance void [runtime]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, uint8, int32, int32, - int32) = ( 01 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 - 00 00 )""" - """.maxstack 8""" - """IL_0000: ldc.i4.3""" - """IL_0001: ldc.i4.0""" - """IL_0002: ldc.i4.0""" - """IL_0003: ldc.i4.0""" - """IL_0004: ldc.i4.0""" - """IL_0005: newobj instance void [runtime]System.Decimal::.ctor(int32, + int32) = ( 01 00 01 00 00 00 00 00 00 00 00 00 37 00 00 00 + 00 00 ) + .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) + .method private specialname rtspecialname static void .cctor() cil managed + { + + .maxstack 8 + IL_0000: ldc.i4.0 + IL_0001: stsfld int32 ''.$DecimalInit::init@ + IL_0006: ldsfld int32 ''.$DecimalInit::init@ + IL_000b: pop + IL_000c: ret + } + + .method assembly specialname static void staticInitialization@() cil managed + { + + .maxstack 8 + IL_0000: ldc.i4.s 55 + IL_0002: ldc.i4.0 + IL_0003: ldc.i4.0 + IL_0004: ldc.i4.0 + IL_0005: ldc.i4.1 + IL_0006: newobj instance void [runtime]System.Decimal::.ctor(int32, int32, int32, bool, - uint8)""" - """IL_000a: stsfld valuetype [runtime]System.Decimal LiteralArithmetic::x""" - """IL_000f: ret""" + uint8) + IL_000b: stsfld valuetype [runtime]System.Decimal DecimalInit::x + IL_0010: ret + } + +} + +.class private abstract auto ansi sealed ''.$DecimalInit + extends [runtime]System.Object +{ + .field static assembly int32 init@ + .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) + .method private specialname rtspecialname static void .cctor() cil managed + { + + .maxstack 8 + IL_0000: call void DecimalInit::staticInitialization@() + IL_0005: ret + } + +} +""" + ] + + [] + let ``Arithmetic can be used for constructing decimal literals``() = + FSharp """ +module LiteralArithmetic + +[] +let x = 1m + 2m + """ + |> withLangVersion80 + |> compile + |> shouldSucceed + |> verifyIL [ + """.field public static initonly valuetype [runtime]System.Decimal x +.custom instance void [runtime]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + uint8, + int32, + int32, + int32) = ( 01 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 + 00 00 )""" + """ +.method assembly specialname static void staticInitialization@() cil managed +{ + +.maxstack 8 +IL_0000: ldc.i4.3 +IL_0001: ldc.i4.0 +IL_0002: ldc.i4.0 +IL_0003: ldc.i4.0 +IL_0004: ldc.i4.0 +IL_0005: newobj instance void [runtime]System.Decimal::.ctor(int32, + int32, + int32, + bool, + uint8) +IL_000a: stsfld valuetype [runtime]System.Decimal LiteralArithmetic::x +IL_000f: ret +} +""" ] [] @@ -226,28 +307,45 @@ let test () = |> compile |> shouldSucceed |> verifyIL [ - """.field public static initonly valuetype [runtime]System.Decimal x""" - """ .custom instance void [runtime]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, - uint8, - int32, - int32, - int32) = ( 01 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 - 00 00 )""" - """IL_0016: call bool [netstandard]System.Decimal::op_Equality(valuetype [netstandard]System.Decimal, - valuetype [netstandard]System.Decimal)""" - """.maxstack 8""" - """IL_0000: ldc.i4.5""" - """IL_0001: ldc.i4.0""" - """IL_0002: ldc.i4.0""" - """IL_0003: ldc.i4.0""" - """IL_0004: ldc.i4.0""" - """IL_0005: newobj instance void [runtime]System.Decimal::.ctor(int32, - int32, - int32, - bool, - uint8)""" - """IL_000a: stsfld valuetype [runtime]System.Decimal PatternMatch::x""" - """IL_000f: ret""" + """ +.field public static initonly valuetype [runtime]System.Decimal x +.custom instance void [runtime]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + uint8, + int32, + int32, + int32) = ( 01 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 + 00 00 )""" + """ +.method public static int32 test() cil managed + { + +.maxstack 8 +.locals init (valuetype [runtime]System.Decimal V_0) +IL_0000: ldc.i4.5 +IL_0001: ldc.i4.0 +IL_0002: ldc.i4.0 +IL_0003: ldc.i4.0 +IL_0004: ldc.i4.0 +IL_0005: newobj instance void [netstandard]System.Decimal::.ctor(int32, + int32, + int32, + bool, + uint8) +IL_000a: stloc.0 +IL_000b: ldloc.0 +IL_000c: ldc.i4.5 +IL_000d: ldc.i4.0 +IL_000e: ldc.i4.0 +IL_000f: ldc.i4.0 +IL_0010: ldc.i4.0 +IL_0011: newobj instance void [netstandard]System.Decimal::.ctor(int32, + int32, + int32, + bool, + uint8) +IL_0016: call bool [netstandard]System.Decimal::op_Equality(valuetype [netstandard]System.Decimal, + valuetype [netstandard]System.Decimal) + """ ] [] @@ -264,6 +362,56 @@ let y = 42m |> withLangVersion80 |> compile |> shouldSucceed + |> verifyIL [ + """ +.field public static initonly valuetype [runtime]System.Decimal x +.custom instance void [runtime]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + uint8, + int32, + int32, + int32) = ( 01 00 00 00 00 00 00 00 00 00 00 00 29 00 00 00 + 00 00 ) +""" + """ +.field public static initonly valuetype [runtime]System.Decimal y +.custom instance void [runtime]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, + uint8, + int32, + int32, + int32) = ( 01 00 00 00 00 00 00 00 00 00 00 00 2A 00 00 00 + 00 00 ) +""" + """ +.method assembly specialname static void staticInitialization@() cil managed +{ + +.maxstack 8 +IL_0000: ldc.i4.s 41 +IL_0002: ldc.i4.0 +IL_0003: ldc.i4.0 +IL_0004: ldc.i4.0 +IL_0005: ldc.i4.0 +IL_0006: newobj instance void [runtime]System.Decimal::.ctor(int32, + int32, + int32, + bool, + uint8) +IL_000b: stsfld valuetype [runtime]System.Decimal DecimalLiterals::x +IL_0010: ldc.i4.s 42 +IL_0012: ldc.i4.0 +IL_0013: ldc.i4.0 +IL_0014: ldc.i4.0 +IL_0015: ldc.i4.0 +IL_0016: newobj instance void [runtime]System.Decimal::.ctor(int32, + int32, + int32, + bool, + uint8) +IL_001b: stsfld valuetype [runtime]System.Decimal DecimalLiterals::y +IL_0020: ret +} +""" + ] [] let ``Compilation fails when using arithmetic with a non-literal in literal``() = diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/TryCatch/TryCatch.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/TryCatch/TryCatch.fs index 9a43d34d429..1e5187167a7 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/TryCatch/TryCatch.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/TryCatch/TryCatch.fs @@ -56,9 +56,9 @@ let ``Stackoverflow reproduction`` compilation = | CompilationResult.Success ({OutputPath = Some dllFile} as s) -> let fsharpCoreFile = typeof>.Assembly.Location File.Copy(fsharpCoreFile, Path.Combine(Path.GetDirectoryName(dllFile), Path.GetFileName(fsharpCoreFile)), true) - let exitCode, _stdout, _stderr = CompilerAssert.ExecuteAndReturnResult (dllFile, isFsx=false, deps = s.Dependencies, newProcess=true) + let _exitCode, _stdout, stderr, _exn = CompilerAssert.ExecuteAndReturnResult (dllFile, isFsx=false, deps = s.Dependencies, newProcess=true) - Assert.NotEqual(0,exitCode) + Assert.True(stderr.Contains "stack overflow" || stderr.Contains "StackOverflow") | _ -> failwith (sprintf "%A" compilationResult) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs index 55f4d1cbf1b..44e8e202a94 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs @@ -815,4 +815,19 @@ type A() = default this.M() = () """ |> typecheck - |> shouldSucceed \ No newline at end of file + |> shouldSucceed + + [] + let ``This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e. g. 'inherit BaseType(args)'`` () = + Fsx """ +type IA = interface end + +type Class() = + inherit IA + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 961, Line 5, Col 5, Line 5, Col 12, "This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e.g. 'inherit BaseType(args)'.") + (Error 946, Line 5, Col 13, Line 5, Col 15, "Cannot inherit from interface type. Use interface ... with instead.") + ] \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 4b50b28aa12..029ec14b0b4 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -32,6 +32,7 @@ FsUnit.fs + diff --git a/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs index 9d276c13629..3555e97fd2d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs @@ -644,4 +644,85 @@ let indexHandler (): Task = 'string' but here has type 'Task' ") + ] + + [] + let ``use expressions may not be used in queries(SynExpr.Sequential)`` () = + Fsx """ +let x11 = + query { for c in [1..10] do + use x = { new System.IDisposable with __.Dispose() = () } + yield 1 } + """ + |> ignoreWarnings + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 3142, Line 4, Col 13, Line 4, Col 16, "'use' expressions may not be used in queries") + ] + + [] + let ``use, This control construct may only be used if the computation expression builder defines a 'Using' method`` () = + Fsx """ +module Result = + let zip x1 x2 = + match x1,x2 with + | Ok x1res, Ok x2res -> Ok (x1res, x2res) + | Error e, _ -> Error e + | _, Error e -> Error e + +type ResultBuilder() = + member _.MergeSources(t1: Result<'T,'U>, t2: Result<'T1,'U>) = Result.zip t1 t2 + member _.BindReturn(x: Result<'T,'U>, f) = Result.map f x + + member _.YieldReturn(x: Result<'T,'U>) = x + member _.Return(x: 'T) = Ok x + +let result = ResultBuilder() + +let run r2 r3 = + result { + use b = r2 + return Ok 0 + } + """ + |> ignoreWarnings + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 708, Line 20, Col 9, Line 20, Col 12, "This control construct may only be used if the computation expression builder defines a 'Using' method") + ] + + [] + let ``This 'let' definition may not be used in a query. Only simple value definitions may be used in queries.`` () = + Fsx """ +let x18rec2 = + query { + for d in [1..10] do + let rec f x = x + 1 // error expected here - no recursive functions + and g x = f x + 2 + select (f d) + } + +let x18inline = + query { + for d in [1..10] do + let inline f x = x + 1 // error expected here - no inline functions + select (f d) + } + +let x18mutable = + query { + for d in [1..10] do + let mutable v = 1 // error expected here - no mutable values + select (f d) + } + + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 3147, Line 5, Col 17, Line 5, Col 20, "This 'let' definition may not be used in a query. Only simple value definitions may be used in queries.") + (Error 3147, Line 13, Col 20, Line 13, Col 23, "This 'let' definition may not be used in a query. Only simple value definitions may be used in queries.") + (Error 3147, Line 20, Col 21, Line 20, Col 22, "This 'let' definition may not be used in a query. Only simple value definitions may be used in queries.") ] \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs index 1edfbfd7961..0da1169b9a8 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs @@ -144,6 +144,21 @@ let nonStrictFunc(x:string | null) = strictFunc(x) |> shouldFail |> withDiagnostics [ Error 3261, Line 4, Col 49, Line 4, Col 50, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability."] + +[] +let ``Can have nullable prop of same type T within a custom type T``() = + FSharp """ +module MyLib +type T () = + let mutable v : T | null = null + member val P : T | null = null with get, set + member this.M() = + v <- null + this.P <- null + """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldSucceed [] [] diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/CompilationFromCmdlineArgsTests.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/CompilationFromCmdlineArgsTests.fs index 9cfbbb9df80..294db344223 100644 --- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/CompilationFromCmdlineArgsTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/CompilationFromCmdlineArgsTests.fs @@ -38,12 +38,12 @@ module CompilationFromCmdlineArgsTests = yield! methodOptions method |] - let diagnostics, exitCode = checker.Compile(args) |> Async.RunSynchronously + let diagnostics, exn = checker.Compile(args) |> Async.RunSynchronously for diag in diagnostics do printfn "%A" diag - Assert.Equal(exitCode, 0) + Assert.Equal(exn, None) finally Environment.CurrentDirectory <- oldWorkDir diff --git a/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs b/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs index aff47308ad2..bf3a9cbaac6 100644 --- a/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs +++ b/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs @@ -12,12 +12,16 @@ open System.Threading.Tasks open FSharp.Compiler.Interactive open FSharp.Compiler.Interactive.Shell open FSharp.Test.ScriptHelpers -open FSharp.Test.Utilities open Xunit type InteractiveTests() = + let copyHousingToTemp() = + let tempName = TestFramework.getTemporaryFileName() + File.Copy(__SOURCE_DIRECTORY__ ++ "housing.csv", tempName + ".csv") + tempName + [] member _.``ValueRestriction error message should not have type variables fully solved``() = use script = new FSharpScript() @@ -248,10 +252,10 @@ System.Configuration.ConfigurationManager.AppSettings.Item "Environment" <- "LOC if RuntimeInformation.ProcessArchitecture = Architecture.Arm64 then () else - let code = @" -#r ""nuget:Microsoft.ML,version=1.4.0-preview"" -#r ""nuget:Microsoft.ML.AutoML,version=0.16.0-preview"" -#r ""nuget:Microsoft.Data.Analysis,version=0.4.0"" + let code = $""" +#r "nuget:Microsoft.ML,version=1.4.0-preview" +#r "nuget:Microsoft.ML.AutoML,version=0.16.0-preview" +#r "nuget:Microsoft.Data.Analysis,version=0.4.0" open System open System.IO @@ -267,7 +271,7 @@ let Shuffle (arr:int[]) = arr.[i] <- temp arr -let housingPath = ""housing.csv"" +let housingPath = @"{copyHousingToTemp()}.csv" let housingData = DataFrame.LoadCsv(housingPath) let randomIndices = (Shuffle(Enumerable.Range(0, (int (housingData.Rows.Count) - 1)).ToArray())) let testSize = int (float (housingData.Rows.Count) * 0.1) @@ -281,11 +285,11 @@ open Microsoft.ML.AutoML let mlContext = MLContext() let experiment = mlContext.Auto().CreateRegressionExperiment(maxExperimentTimeInSeconds = 15u) -let result = experiment.Execute(housing_train, labelColumnName = ""median_house_value"") +let result = experiment.Execute(housing_train, labelColumnName = "median_house_value") let details = result.RunDetails -printfn ""%A"" result +printfn "{@"%A"}" result 123 -" +""" use script = new FSharpScript(additionalArgs=[| |]) let opt = script.Eval(code) |> getValue let value = opt.Value @@ -511,3 +515,4 @@ let add (col:IServiceCollection) = use script = new FSharpScript(additionalArgs=[| |]) let _value,diag = script.Eval(code) Assert.Empty(diag) + diff --git a/tests/FSharp.Compiler.Service.Tests/BuildGraphTests.fs b/tests/FSharp.Compiler.Service.Tests/BuildGraphTests.fs index 16b0ff7b878..4769b4c322d 100644 --- a/tests/FSharp.Compiler.Service.Tests/BuildGraphTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/BuildGraphTests.fs @@ -385,22 +385,17 @@ module BuildGraphTests = for i in 1 .. 300 do async { - Interlocked.Increment(&count) |> ignore - errorR (ExampleException $"{i}") + errorR (ExampleException $"{Interlocked.Increment(&count)}") + error (ExampleException $"{Interlocked.Increment(&count)}") } ] - let run = - tasks |> MultipleDiagnosticsLoggers.Parallel |> Async.Catch |> Async.StartAsTask - - Assert.True( - run.Wait(1000), - "MultipleDiagnosticsLoggers.Parallel did not finish." - ) - - // Diagnostics from all started tasks should be collected despite the exception. - errorCountShouldBe count + task { + do! tasks |> MultipleDiagnosticsLoggers.Parallel |> Async.Catch |> Async.Ignore + // Diagnostics from all started tasks should be collected despite the exception. + errorCountShouldBe count + } [] let ``AsyncLocal diagnostics context flows correctly`` () = diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index 42ec38ee366..f08d67883b7 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -2166,7 +2166,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] GetBackgroundCheckResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]]] GetProjectOptionsFromScript(System.String, FSharp.Compiler.Text.ISourceText, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]]] GetProjectSnapshotFromScript(System.String, FSharp.Compiler.Text.ISourceTextNew, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String]) -FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Diagnostics.FSharpDiagnostic[],System.Int32]] Compile(System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.String]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Diagnostics.FSharpDiagnostic[],Microsoft.FSharp.Core.FSharpOption`1[System.Exception]]] Compile(System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Text.Range,FSharp.Compiler.Text.Range][]] MatchBraces(System.String, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpParsingOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Text.Range,FSharp.Compiler.Text.Range][]] MatchBraces(System.String, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions],FSharp.Compiler.CodeAnalysis.FSharpProjectOptions] ProjectChecked @@ -8151,7 +8151,13 @@ FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewAu FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewGetSetMember(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynBinding], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynBinding], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberGetSetTrivia) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitCtor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynAccess], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList], FSharp.Compiler.Syntax.SynPat, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Xml.PreXmlDoc, FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnImplicitCtorTrivia) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitInherit(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynExpr, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range) -FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range) +FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia get_trivia() +FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia trivia +FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia) +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: FSharp.Compiler.Text.Range InheritKeyword +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: FSharp.Compiler.Text.Range get_InheritKeyword() +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: System.String ToString() +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: Void .ctor(FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInterface(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynMemberDefn]], FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewLetBindings(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynBinding], Boolean, Boolean, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewMember(FSharp.Compiler.Syntax.SynBinding, FSharp.Compiler.Text.Range) @@ -10231,7 +10237,9 @@ FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: FSharp.Compiler.SyntaxTrivia FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] InKeyword FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] get_InKeyword() FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: System.String ToString() -FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Void .ctor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range]) +FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: FSharp.Compiler.Text.Range LetOrUseKeyword +FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: FSharp.Compiler.Text.Range get_LetOrUseKeyword() +FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Void .ctor(FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range]) FSharp.Compiler.SyntaxTrivia.SynExprMatchBangTrivia: FSharp.Compiler.Text.Range MatchBangKeyword FSharp.Compiler.SyntaxTrivia.SynExprMatchBangTrivia: FSharp.Compiler.Text.Range WithKeyword FSharp.Compiler.SyntaxTrivia.SynExprMatchBangTrivia: FSharp.Compiler.Text.Range get_MatchBangKeyword() diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index 42ec38ee366..f08d67883b7 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -2166,7 +2166,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] GetBackgroundCheckResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]]] GetProjectOptionsFromScript(System.String, FSharp.Compiler.Text.ISourceText, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.ProjectSnapshot+FSharpProjectSnapshot,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Diagnostics.FSharpDiagnostic]]] GetProjectSnapshotFromScript(System.String, FSharp.Compiler.Text.ISourceTextNew, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.DocumentSource], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.DateTime], Microsoft.FSharp.Core.FSharpOption`1[System.String[]], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Int64], Microsoft.FSharp.Core.FSharpOption`1[System.String]) -FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Diagnostics.FSharpDiagnostic[],System.Int32]] Compile(System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.String]) +FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Diagnostics.FSharpDiagnostic[],Microsoft.FSharp.Core.FSharpOption`1[System.Exception]]] Compile(System.String[], Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Text.Range,FSharp.Compiler.Text.Range][]] MatchBraces(System.String, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpParsingOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.Text.Range,FSharp.Compiler.Text.Range][]] MatchBraces(System.String, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String]) FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.IEvent`2[Microsoft.FSharp.Control.FSharpHandler`1[FSharp.Compiler.CodeAnalysis.FSharpProjectOptions],FSharp.Compiler.CodeAnalysis.FSharpProjectOptions] ProjectChecked @@ -8151,7 +8151,13 @@ FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewAu FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewGetSetMember(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynBinding], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynBinding], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberGetSetTrivia) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitCtor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynAccess], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList], FSharp.Compiler.Syntax.SynPat, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Xml.PreXmlDoc, FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnImplicitCtorTrivia) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitInherit(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynExpr, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range) -FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range) +FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia get_trivia() +FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia trivia +FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia) +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: FSharp.Compiler.Text.Range InheritKeyword +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: FSharp.Compiler.Text.Range get_InheritKeyword() +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: System.String ToString() +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: Void .ctor(FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInterface(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynMemberDefn]], FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewLetBindings(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynBinding], Boolean, Boolean, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewMember(FSharp.Compiler.Syntax.SynBinding, FSharp.Compiler.Text.Range) @@ -10231,7 +10237,9 @@ FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: FSharp.Compiler.SyntaxTrivia FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] InKeyword FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] get_InKeyword() FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: System.String ToString() -FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Void .ctor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range]) +FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: FSharp.Compiler.Text.Range LetOrUseKeyword +FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: FSharp.Compiler.Text.Range get_LetOrUseKeyword() +FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Void .ctor(FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range]) FSharp.Compiler.SyntaxTrivia.SynExprMatchBangTrivia: FSharp.Compiler.Text.Range MatchBangKeyword FSharp.Compiler.SyntaxTrivia.SynExprMatchBangTrivia: FSharp.Compiler.Text.Range WithKeyword FSharp.Compiler.SyntaxTrivia.SynExprMatchBangTrivia: FSharp.Compiler.Text.Range get_MatchBangKeyword() diff --git a/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs b/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs index 78d03ac8a9b..5752f9de41c 100644 --- a/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs @@ -123,7 +123,14 @@ let ``Test project1 and make sure TcImports gets cleaned up`` () = let weakTcImports = test () checker.InvalidateConfiguration Project1.options checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() - GC.Collect(2, GCCollectionMode.Forced, blocking = true) + + //collect 2 more times for good measure, + // See for example: https://github.com/dotnet/runtime/discussions/108081 + GC.Collect() + GC.WaitForPendingFinalizers() + GC.Collect() + GC.WaitForPendingFinalizers() + Assert.False weakTcImports.IsAlive [] diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs index 145d9a70c3e..213ff435adf 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs @@ -7,6 +7,7 @@ namespace FSharp.Core.UnitTests.Control open System open System.Threading +open System.Threading.Tasks open FSharp.Core.UnitTests.LibraryTestFx open Xunit open FsCheck @@ -273,8 +274,7 @@ type AsyncModule() = } Async.RunSynchronously test - // test is flaky: https://github.com/dotnet/fsharp/issues/11586 - //[] + [] member _.``OnCancel.RaceBetweenCancellationHandlerAndDisposingHandlerRegistration``() = let test() = use flag = new ManualResetEvent(false) @@ -297,8 +297,7 @@ type AsyncModule() = for _i = 1 to 300 do test() - // test is flaky: https://github.com/dotnet/fsharp/issues/11586 - //[] + [] member _.``OnCancel.RaceBetweenCancellationAndDispose``() = let mutable flag = 0 let cts = new System.Threading.CancellationTokenSource() @@ -316,8 +315,7 @@ type AsyncModule() = :? System.OperationCanceledException -> () Assert.AreEqual(1, flag) - // test is flaky: https://github.com/dotnet/fsharp/issues/11586 - //[] + [] member _.``OnCancel.CancelThatWasSignalledBeforeRunningTheComputation``() = let test() = let cts = new System.Threading.CancellationTokenSource() @@ -379,23 +377,25 @@ type AsyncModule() = [] member _.``AwaitWaitHandle.DisposedWaitHandle2``() = - let wh = new System.Threading.ManualResetEvent(false) - let barrier = new System.Threading.ManualResetEvent(false) + let wh = new ManualResetEvent(false) + let started = new ManualResetEventSlim(false) - let test = async { - let! timeout = Async.AwaitWaitHandle(wh, 10000) - Assert.False(timeout, "Timeout expected") - barrier.Set() |> ignore + let test = + async { + started.Set() + let! timeout = Async.AwaitWaitHandle(wh, 5000) + Assert.False(timeout, "Timeout expected") } - Async.Start test - - // await 3 secs then dispose waithandle - nothing should happen - let timeout = wait barrier 3000 - Assert.False(timeout, "Barrier was reached too early") - dispose wh - - let ok = wait barrier 10000 - if not ok then Assert.Fail("Async computation was not completed in given time") + |> Async.StartAsTask + + task { + started.Wait() + // Wait a moment then dispose waithandle - nothing should happen + do! Task.Delay 500 + Assert.False(test.IsCompleted, "Test completed too early") + dispose wh + do! test + } [] member _.``RunSynchronously.NoThreadJumpsAndTimeout``() = @@ -467,22 +467,24 @@ type AsyncModule() = [] member _.``error on one workflow should cancel all others``() = - let counter = - async { - let mutable counter = 0 - let job i = async { - if i = 55 then failwith "boom" - else - do! Async.Sleep 1000 - counter <- counter + 1 - } - - let! _ = Async.Parallel [ for i in 1 .. 100 -> job i ] |> Async.Catch - do! Async.Sleep 5000 - return counter - } |> Async.RunSynchronously + task { + use failOnlyOne = new Semaphore(0, 1) + let mutable cancelled = 0 + let mutable started = 0 + + let job i = async { + Interlocked.Increment &started |> ignore + use! holder = Async.OnCancel (fun () -> Interlocked.Increment &cancelled |> ignore) + do! failOnlyOne |> Async.AwaitWaitHandle |> Async.Ignore + failwith "boom" + } - Assert.AreEqual(0, counter) + let test = Async.Parallel [ for i in 1 .. 100 -> job i ] |> Async.Catch |> Async.Ignore |> Async.StartAsTask + do! Task.Delay 100 + failOnlyOne.Release() |> ignore + do! test + Assert.Equal(started - 1, cancelled) + } [] member _.``AwaitWaitHandle.ExceptionsAfterTimeout``() = @@ -641,7 +643,6 @@ type AsyncModule() = member _.``Parallel with maxDegreeOfParallelism`` () = let mutable i = 1 let action j = async { - do! Async.Sleep 1 Assert.Equal(j, i) i <- i + 1 } diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs index 950432ccc8e..1b15be8fa98 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs @@ -54,16 +54,20 @@ type AsyncType() = [] member _.AsyncRunSynchronouslyReusesThreadPoolThread() = - let action = async { async { () } |> Async.RunSynchronously } - let computation = - [| for i in 1 .. 1000 -> action |] - |> Async.Parallel + let action _ = + async { + return + async { return Thread.CurrentThread.ManagedThreadId } + |> Async.RunSynchronously + } // This test needs approximately 1000 ThreadPool threads // if Async.RunSynchronously doesn't reuse them. - // In such case TimeoutException is raised - // since ThreadPool cannot provide 1000 threads in 1 second - // (the number of threads in ThreadPool is adjusted slowly). - Async.RunSynchronously(computation, timeout = 1000) |> ignore + let usedThreads = + Seq.init 1000 action + |> Async.Parallel + |> Async.RunSynchronously + |> Set.ofArray + Assert.True(usedThreads.Count < 256, $"RunSynchronously used {usedThreads.Count} threads.") [] [] @@ -231,7 +235,8 @@ type AsyncType() = use t = Async.StartAsTask a let mutable exceptionThrown = false try - waitASec t + // waitASec t + t.Wait() with e -> exceptionThrown <- true Assert.True (t.IsFaulted) @@ -269,7 +274,7 @@ type AsyncType() = // printfn "%A" t.Status let mutable exceptionThrown = false try - waitASec t + t.Wait() with e -> exceptionThrown <- true Assert.True (exceptionThrown) Assert.True(t.IsCanceled) @@ -302,56 +307,50 @@ type AsyncType() = use t = Async.StartImmediateAsTask a let mutable exceptionThrown = false try - waitASec t + t.Wait() with e -> exceptionThrown <- true Assert.True (t.IsFaulted) Assert.True(exceptionThrown) -#if IGNORED [] - [] member _.CancellationPropagatesToImmediateTask () = let a = async { - while true do () + while true do + do! Async.Sleep 100 } use t = Async.StartImmediateAsTask a Async.CancelDefaultToken () let mutable exceptionThrown = false try - waitASec t + t.Wait() with e -> exceptionThrown <- true Assert.True (exceptionThrown) Assert.True(t.IsCanceled) -#endif -#if IGNORED [] - [] member _.CancellationPropagatesToGroupImmediate () = let ewh = new ManualResetEvent(false) - let cancelled = ref false + let mutable cancelled = false let a = async { - use! holder = Async.OnCancel (fun _ -> cancelled := true) + use! holder = Async.OnCancel (fun _ -> cancelled <- true) ewh.Set() |> Assert.True - while true do () + while true do + do! Async.Sleep 100 } let cts = new CancellationTokenSource() let token = cts.Token use t = Async.StartImmediateAsTask(a, cancellationToken=token) -// printfn "%A" t.Status ewh.WaitOne() |> Assert.True cts.Cancel() -// printfn "%A" t.Status let mutable exceptionThrown = false try - waitASec t + t.Wait() with e -> exceptionThrown <- true Assert.True (exceptionThrown) Assert.True(t.IsCanceled) - Assert.True(!cancelled) -#endif + Assert.True(cancelled) [] member _.TaskAsyncValue () = @@ -411,8 +410,7 @@ type AsyncType() = } Async.RunSynchronously(a) |> Assert.True - // test is flaky: https://github.com/dotnet/fsharp/issues/11586 - //[] + [] member _.TaskAsyncValueCancellation () = use ewh = new ManualResetEvent(false) let cts = new CancellationTokenSource() @@ -430,9 +428,11 @@ type AsyncType() = :? TaskCanceledException -> ewh.Set() |> ignore // this is ok } - Async.Start a + let t1 = Async.StartAsTask a cts.Cancel() ewh.WaitOne(10000) |> ignore + // Don't leave unobserved background tasks, because they can crash the test run. + t1.Wait() [] member _.NonGenericTaskAsyncValue () = @@ -473,9 +473,10 @@ type AsyncType() = :? TaskCanceledException -> ewh.Set() |> ignore // this is ok } - Async.Start a + let t1 = Async.StartAsTask a cts.Cancel() ewh.WaitOne(10000) |> ignore + t1.Wait() [] member _.CancellationExceptionThrown () = diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Cancellation.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Cancellation.fs index 4e04f64bc1f..cecfaec7590 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Cancellation.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Cancellation.fs @@ -5,7 +5,9 @@ namespace FSharp.Core.UnitTests.Control open System open FSharp.Core.UnitTests.LibraryTestFx open Xunit +open FSharp.Test open System.Threading +open System.Threading.Tasks type CancellationType() = @@ -229,6 +231,7 @@ type CancellationType() = } asyncs |> Async.Parallel |> Async.RunSynchronously |> ignore + // See https://github.com/dotnet/fsharp/issues/3254 [] member this.AwaitTaskCancellationAfterAsyncTokenCancellation() = let StartCatchCancellation cancellationToken (work) = @@ -262,11 +265,11 @@ type CancellationType() = let cts = new CancellationTokenSource() let tcs = System.Threading.Tasks.TaskCompletionSource<_>() - let t = + let test() = async { do! tcs.Task |> Async.AwaitTask } - |> StartAsTaskProperCancel None (Some cts.Token) + |> StartAsTaskProperCancel None (Some cts.Token) :> Task // First cancel the token, then set the task as cancelled. async { @@ -274,15 +277,31 @@ type CancellationType() = cts.Cancel() do! Async.Sleep 100 tcs.TrySetException (TimeoutException "Task timed out after token.") - |> ignore + |> ignore } |> Async.Start - try - let res = t.Wait(2000) - let msg = sprintf "Excepted TimeoutException wrapped in an AggregateException, but got %A" res - printfn "failure msg: %s" msg - Assert.Fail (msg) - with :? AggregateException as agg -> () + task { + let! agg = Assert.ThrowsAsync(test) + let inner = agg.InnerException + Assert.True(inner :? TimeoutException, $"Excepted TimeoutException wrapped in an AggregateException, but got %A{inner}") + } + + // Simpler regression test for https://github.com/dotnet/fsharp/issues/3254 + [] + member this.AwaitTaskCancellationAfterAsyncTokenCancellation2() = + let tcs = new TaskCompletionSource() + let cts = new CancellationTokenSource() + let _ = cts.Token.Register(fun () -> tcs.SetResult 42) + Assert.ThrowsAsync( fun () -> + Async.StartAsTask( + async { + cts.CancelAfter 100 + let! result = tcs.Task |> Async.AwaitTask + return result + }, + cancellationToken = cts.Token + ) + ) [] member this.Equality() = diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/MailboxProcessorType.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/MailboxProcessorType.fs index 904bc7dc622..f3964aaa78c 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/MailboxProcessorType.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/MailboxProcessorType.fs @@ -125,7 +125,7 @@ type MailboxProcessorType() = use mre2 = new ManualResetEventSlim(false) // https://github.com/dotnet/fsharp/issues/3337 - let cts = new CancellationTokenSource () + use cts = new CancellationTokenSource () let addMsg msg = match result with @@ -204,25 +204,24 @@ type MailboxProcessorType() = [] member this.``Receive Races with Post``() = - let receiveEv = new ManualResetEvent(false) - let postEv = new ManualResetEvent(false) - let finishedEv = new ManualResetEvent(false) + let receiveEv = new AutoResetEvent(false) + let postEv = new AutoResetEvent(false) + let finishedEv = new AutoResetEvent(false) + use cts = new CancellationTokenSource() let mb = MailboxProcessor.Start ( fun inbox -> async { while true do - let w = receiveEv.WaitOne() - receiveEv.Reset() |> ignore + receiveEv.WaitOne() |> ignore let! (msg) = inbox.Receive () finishedEv.Set() |> ignore }) let post = async { - while true do - let r = postEv.WaitOne() - postEv.Reset() |> ignore + while not cts.IsCancellationRequested do + postEv.WaitOne() |> ignore mb.Post(fun () -> ()) - } |> Async.Start + } |> Async.StartAsTask for i in 0 .. 100000 do if i % 2 = 0 then receiveEv.Set() |> ignore @@ -232,19 +231,23 @@ type MailboxProcessorType() = receiveEv.Set() |> ignore finishedEv.WaitOne() |> ignore - finishedEv.Reset() |> ignore + + cts.Cancel() + // Let the post task finish. + postEv.Set() |> ignore + post.Wait() [] member this.``Receive Races with Post on timeout``() = - let receiveEv = new ManualResetEvent(false) - let postEv = new ManualResetEvent(false) - let finishedEv = new ManualResetEvent(false) + let receiveEv = new AutoResetEvent(false) + let postEv = new AutoResetEvent(false) + let finishedEv = new AutoResetEvent(false) + use cts = new CancellationTokenSource() let mb = MailboxProcessor.Start ( fun inbox -> async { while true do - let w = receiveEv.WaitOne() - receiveEv.Reset() |> ignore + receiveEv.WaitOne() |> ignore let! (msg) = inbox.Receive (5000) finishedEv.Set() |> ignore }) @@ -252,12 +255,11 @@ type MailboxProcessorType() = let isErrored = mb.Error |> Async.AwaitEvent |> Async.StartAsTask let post = - async { - while true do - let r = postEv.WaitOne() - postEv.Reset() |> ignore + backgroundTask { + while not cts.IsCancellationRequested do + postEv.WaitOne() |> ignore mb.Post(fun () -> ()) - } |> Async.Start + } for i in 0 .. 10000 do if i % 2 = 0 then @@ -271,32 +273,35 @@ type MailboxProcessorType() = if isErrored.IsCompleted then raise <| Exception("Mailbox should not fail!", isErrored.Result) - finishedEv.Reset() |> ignore + cts.Cancel() + // Let the post task finish. + postEv.Set() |> ignore + post.Wait() [] member this.``TryReceive Races with Post on timeout``() = - let receiveEv = new ManualResetEvent(false) - let postEv = new ManualResetEvent(false) - let finishedEv = new ManualResetEvent(false) + let receiveEv = new AutoResetEvent(false) + let postEv = new AutoResetEvent(false) + let finishedEv = new AutoResetEvent(false) + use cts = new CancellationTokenSource() let mb = MailboxProcessor.Start ( fun inbox -> async { while true do - let w = receiveEv.WaitOne() - receiveEv.Reset() |> ignore + receiveEv.WaitOne() |> ignore let! (msg) = inbox.TryReceive (5000) finishedEv.Set() |> ignore - }) + } + ) let isErrored = mb.Error |> Async.AwaitEvent |> Async.StartAsTask let post = - async { - while true do - let r = postEv.WaitOne() - postEv.Reset() |> ignore + backgroundTask { + while not cts.IsCancellationRequested do + postEv.WaitOne() |> ignore mb.Post(fun () -> ()) - } |> Async.Start + } for i in 0 .. 10000 do if i % 2 = 0 then @@ -310,7 +315,9 @@ type MailboxProcessorType() = if isErrored.IsCompleted then raise <| Exception("Mailbox should not fail!", isErrored.Result) - finishedEv.Reset() |> ignore + cts.Cancel() + postEv.Set() |> ignore + post.Wait() [] member this.``After dispose is called, mailbox should stop receiving and processing messages``() = task { @@ -397,6 +404,7 @@ type MailboxProcessorType() = Assert.Equal(expectedMessagesCount, actualMessagesCount) Assert.Equal(0, actualSkipMessagesCount) Assert.Equal(0, mb.CurrentQueueLength) + } [] @@ -496,3 +504,56 @@ type MailboxProcessorType() = // If StartImmediate worked correctly, the information should be identical since // the threads should be the same. Assert.Equal(callingThreadInfo, mailboxThreadInfo) + +module MailboxProcessorType = + + [] + let TryScan () = + let tcs = TaskCompletionSource<_>() + use mailbox = + new MailboxProcessor(fun inbox -> async { + do! + inbox.TryScan( function + | Reset -> async { tcs.SetResult "Reset processed" } |> Some + | _ -> None) + |> Async.Ignore + }) + mailbox.Start() + + for i in 1 .. 100 do + mailbox.Post(Increment i) + mailbox.Post Reset + + Assert.Equal("Reset processed", tcs.Task.Result) + Assert.Equal(100, mailbox.CurrentQueueLength) + + [] + let ``TryScan with timeout`` () = + let tcs = TaskCompletionSource<_>() + use mailbox = + new MailboxProcessor(fun inbox -> + let rec loop i = async { + match! + inbox.TryScan( function + | Reset -> async { tcs.SetResult i } |> Some + | _ -> None) + with + | None -> do! loop (i + 1) + | _ -> () + } + loop 1 + ) + mailbox.DefaultTimeout <- 10 + mailbox.Start() + + let iteration = + task { + for i in 1 .. 100 do + mailbox.Post(Increment 1) + do! Task.Delay 10 + mailbox.Post Reset + + return! tcs.Task + } + + Assert.True(iteration.Result > 1, "TryScan did not timeout") diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Tasks.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Tasks.fs index 5d533b880c3..8097c2d10f5 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Tasks.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Tasks.fs @@ -236,15 +236,16 @@ type Basics() = [] member _.testNonBlocking() = printfn "Running testNonBlocking..." - let sw = Stopwatch() - sw.Start() + let allowContinue = new SemaphoreSlim(0) + let finished = new ManualResetEventSlim() let t = task { - do! Task.Yield() + do! allowContinue.WaitAsync() Thread.Sleep(100) + finished.Set() } - sw.Stop() - require (sw.ElapsedMilliseconds < 50L) "sleep blocked caller" + allowContinue.Release() |> ignore + require (not finished.IsSet) "sleep blocked caller" t.Wait() [] @@ -908,58 +909,60 @@ type Basics() = [] member _.testExceptionThrownInFinally() = printfn "running testExceptionThrownInFinally" - for i in 1 .. 5 do - let mutable ranInitial = false - let mutable ranNext = false + for i in 1 .. 5 do + use stepOutside = new SemaphoreSlim(0) + use ranInitial = new ManualResetEventSlim() + use ranNext = new ManualResetEventSlim() let mutable ranFinally = 0 let t = task { try - ranInitial <- true + ranInitial.Set() do! Task.Yield() Thread.Sleep(100) // shouldn't be blocking so we should get through to requires before this finishes - ranNext <- true + ranNext.Set() finally ranFinally <- ranFinally + 1 failtest "finally exn!" } - require ranInitial "didn't run initial" - require (not ranNext) "ran next too early" + require ranInitial.IsSet "didn't run initial" + require (not ranNext.IsSet) "ran next too early" try t.Wait() require false "shouldn't get here" with | _ -> () - require ranNext "didn't run next" + require ranNext.IsSet "didn't run next" require (ranFinally = 1) "didn't run finally exactly once" [] member _.test2ndExceptionThrownInFinally() = printfn "running test2ndExceptionThrownInFinally" for i in 1 .. 5 do - let mutable ranInitial = false - let mutable ranNext = false + use ranInitial = new ManualResetEventSlim() + use continueTask = new SemaphoreSlim(0) + use ranNext = new ManualResetEventSlim() let mutable ranFinally = 0 let t = task { try - ranInitial <- true + ranInitial.Set() + do! continueTask.WaitAsync() + ranNext.Set() do! Task.Yield() - Thread.Sleep(100) // shouldn't be blocking so we should get through to requires before this finishes - ranNext <- true failtest "uhoh" finally ranFinally <- ranFinally + 1 failtest "2nd exn!" } - require ranInitial "didn't run initial" - require (not ranNext) "ran next too early" + ranInitial.Wait() + continueTask.Release() |> ignore try t.Wait() require false "shouldn't get here" with | _ -> () - require ranNext "didn't run next" + require ranNext.IsSet "didn't run next" require (ranFinally = 1) "didn't run finally exactly once" [] diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TasksDynamic.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TasksDynamic.fs index c811aecaa5c..7f844e99d96 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TasksDynamic.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TasksDynamic.fs @@ -357,15 +357,16 @@ type Basics() = [] member _.testNonBlocking() = printfn "Running testNonBlocking..." - let sw = Stopwatch() - sw.Start() + let allowContinue = new SemaphoreSlim(0) + let finished = new ManualResetEventSlim() let t = taskDynamic { - do! Task.Yield() + do! allowContinue.WaitAsync() Thread.Sleep(100) + finished.Set() } - sw.Stop() - require (sw.ElapsedMilliseconds < 50L) "sleep blocked caller" + allowContinue.Release() |> ignore + require (not finished.IsSet) "sleep blocked caller" t.Wait() [] @@ -982,58 +983,60 @@ type Basics() = [] member _.testExceptionThrownInFinally() = printfn "running testExceptionThrownInFinally" - for i in 1 .. 5 do - let mutable ranInitial = false - let mutable ranNext = false + for i in 1 .. 5 do + use stepOutside = new SemaphoreSlim(0) + use ranInitial = new ManualResetEventSlim() + use ranNext = new ManualResetEventSlim() let mutable ranFinally = 0 let t = taskDynamic { try - ranInitial <- true + ranInitial.Set() do! Task.Yield() Thread.Sleep(100) // shouldn't be blocking so we should get through to requires before this finishes - ranNext <- true + ranNext.Set() finally ranFinally <- ranFinally + 1 failtest "finally exn!" } - require ranInitial "didn't run initial" - require (not ranNext) "ran next too early" + require ranInitial.IsSet "didn't run initial" + require (not ranNext.IsSet) "ran next too early" try t.Wait() require false "shouldn't get here" with | _ -> () - require ranNext "didn't run next" + require ranNext.IsSet "didn't run next" require (ranFinally = 1) "didn't run finally exactly once" [] member _.test2ndExceptionThrownInFinally() = printfn "running test2ndExceptionThrownInFinally" for i in 1 .. 5 do - let mutable ranInitial = false - let mutable ranNext = false + use ranInitial = new ManualResetEventSlim() + use continueTask = new SemaphoreSlim(0) + use ranNext = new ManualResetEventSlim() let mutable ranFinally = 0 let t = taskDynamic { try - ranInitial <- true + ranInitial.Set() + do! continueTask.WaitAsync() + ranNext.Set() do! Task.Yield() - Thread.Sleep(100) // shouldn't be blocking so we should get through to requires before this finishes - ranNext <- true failtest "uhoh" finally ranFinally <- ranFinally + 1 failtest "2nd exn!" } - require ranInitial "didn't run initial" - require (not ranNext) "ran next too early" + ranInitial.Wait() + continueTask.Release() |> ignore try t.Wait() require false "shouldn't get here" with | _ -> () - require ranNext "didn't run next" + require ranNext.IsSet "didn't run next" require (ranFinally = 1) "didn't run finally exactly once" [] diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index f535bc21c5a..5e5629b089f 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -170,10 +170,13 @@ module rec Compiler = Message: string SubCategory: string } + // This type is used either for the output of the compiler (typically in CompilationResult coming from 'compile') + // or for the output of the code generated by the compiler (in CompilationResult coming from 'run') type ExecutionOutput = - { ExitCode: int + { ExitCode: int option StdOut: string - StdErr: string } + StdErr: string + Exn: exn option } type RunOutput = | EvalOutput of Result @@ -699,7 +702,7 @@ module rec Compiler = let private compileFSharpCompilation compilation ignoreWarnings (cUnit: CompilationUnit) : CompilationResult = use redirect = new RedirectConsole() - let ((err: FSharpDiagnostic[], rc: int, outputFilePath: string), deps) = + let ((err: FSharpDiagnostic[], exn, outputFilePath: string), deps) = CompilerAssert.CompileRaw(compilation, ignoreWarnings) // Create and stash the console output @@ -711,7 +714,7 @@ module rec Compiler = Adjust = 0 PerFileErrors = diagnostics Diagnostics = diagnostics |> List.map snd - Output = Some (RunOutput.ExecutionOutput { ExitCode = rc; StdOut = redirect.Output(); StdErr = redirect.ErrorOutput() }) + Output = Some (RunOutput.ExecutionOutput { ExitCode = None; StdOut = redirect.Output(); StdErr = redirect.ErrorOutput(); Exn = exn }) Compilation = cUnit } @@ -978,14 +981,13 @@ module rec Compiler = | SourceCodeFileKind.Fsx _ -> true | _ -> false | _ -> false - let exitCode, output, errors = CompilerAssert.ExecuteAndReturnResult (p, isFsx, s.Dependencies, false) + let exitCode, output, errors, exn = CompilerAssert.ExecuteAndReturnResult (p, isFsx, s.Dependencies, false) printfn "---------output-------\n%s\n-------" output printfn "---------errors-------\n%s\n-------" errors - let executionResult = { s with Output = Some (ExecutionOutput { ExitCode = exitCode; StdOut = output; StdErr = errors }) } - if exitCode = 0 then - CompilationResult.Success executionResult - else - CompilationResult.Failure executionResult + let executionResult = { s with Output = Some (ExecutionOutput { ExitCode = exitCode; StdOut = output; StdErr = errors; Exn = exn }) } + match exn with + | None -> CompilationResult.Success executionResult + | Some _ -> CompilationResult.Failure executionResult let compileAndRun = compile >> run @@ -1080,27 +1082,25 @@ module rec Compiler = opts.ToArray() let errors, stdOut = CompilerAssert.RunScriptWithOptionsAndReturnResult options source - let executionOutputwithStdOut: RunOutput option = - ExecutionOutput { StdOut = stdOut; ExitCode = 0; StdErr = "" } - |> Some - let result = + let mkResult output = { OutputPath = None Dependencies = [] Adjust = 0 Diagnostics = [] PerFileErrors= [] - Output = executionOutputwithStdOut + Output = Some output Compilation = cUnit } - - if errors.Count > 0 then - let output = ExecutionOutput { - ExitCode = -1 - StdOut = String.Empty - StdErr = ((errors |> String.concat "\n").Replace("\r\n","\n")) } - CompilationResult.Failure { result with Output = Some output } + + if errors.Count = 0 then + let output = + ExecutionOutput { ExitCode = None; StdOut = stdOut; StdErr = ""; Exn = None } + CompilationResult.Success (mkResult output) else - CompilationResult.Success result - + let err = (errors |> String.concat "\n").Replace("\r\n","\n") + let output = + ExecutionOutput {ExitCode = None; StdOut = String.Empty; StdErr = err; Exn = None } + CompilationResult.Failure (mkResult output) + finally disposals |> Seq.iter (fun x -> x.Dispose()) @@ -1190,7 +1190,7 @@ Actual: | Some p -> match ILChecker.verifyILAndReturnActual [] p expected with | true, _, _ -> result - | false, errorMsg, _actualIL -> CompilationResult.Failure( {s with Output = Some (ExecutionOutput { StdOut = errorMsg; ExitCode = 0; StdErr = "" })} ) + | false, errorMsg, _actualIL -> CompilationResult.Failure( {s with Output = Some (ExecutionOutput {ExitCode = None; StdOut = errorMsg; StdErr = ""; Exn = None })} ) | CompilationResult.Failure f -> failwith $"Result should be \"Success\" in order to get IL. Failure: {Environment.NewLine}{f}" @@ -1706,7 +1706,7 @@ Actual: | None -> failwith "Execution output is missing, cannot check exit code." | Some o -> match o with - | ExecutionOutput e -> Assert.Equal(expectedExitCode, e.ExitCode) + | ExecutionOutput {ExitCode = Some exitCode} -> Assert.Equal(expectedExitCode, exitCode) | _ -> failwith "Cannot check exit code on this run result." result diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index fc2875d8955..37a8e25e164 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -322,7 +322,7 @@ module rec CompilerAssertHelpers = else entryPoint let args = mkDefaultArgs entryPoint - captureConsoleOutputs (fun () -> entryPoint.Invoke(Unchecked.defaultof, args) |> ignore) + captureConsoleOutputs (fun () -> entryPoint.Invoke(Unchecked.defaultof, args)) #if NETCOREAPP let executeBuiltApp assembly deps isFsx = @@ -409,8 +409,8 @@ module rec CompilerAssertHelpers = // Generate a response file, purely for diagnostic reasons. File.WriteAllLines(Path.ChangeExtension(outputFilePath, ".rsp"), args) - let errors, rc = checker.Compile args |> Async.RunImmediate - errors, rc, outputFilePath + let errors, ex = checker.Compile args |> Async.RunImmediate + errors, ex, outputFilePath let compileDisposable (outputDirectory:DirectoryInfo) isExe options targetFramework nameOpt (sources:SourceCodeFileKind list) = let disposeFile path = @@ -537,7 +537,7 @@ module rec CompilerAssertHelpers = let tmp = Path.Combine(outputPath.FullName, Path.ChangeExtension(fileName, ".dll")) disposals.Add({ new IDisposable with member _.Dispose() = File.Delete tmp }) cmpl.EmitAsFile tmp - (([||], 0, tmp), []), false) + (([||], None, tmp), []), false) let compilationRefs = compiledRefs @@ -559,7 +559,7 @@ module rec CompilerAssertHelpers = compilationRefs, deps - let compileCompilationAux outputDirectory (disposals: ResizeArray) ignoreWarnings (cmpl: Compilation) : (FSharpDiagnostic[] * int * string) * string list = + let compileCompilationAux outputDirectory (disposals: ResizeArray) ignoreWarnings (cmpl: Compilation) : (FSharpDiagnostic[] * exn option * string) * string list = let compilationRefs, deps = evaluateReferences outputDirectory disposals ignoreWarnings cmpl let isExe, sources, options, targetFramework, name = @@ -604,7 +604,7 @@ module rec CompilerAssertHelpers = outputDirectory.Create() compileCompilationAux outputDirectory (ResizeArray()) ignoreWarnings cmpl - let captureConsoleOutputs (func: unit -> unit) = + let captureConsoleOutputs (func: unit -> obj) = let out = Console.Out let err = Console.Error @@ -614,29 +614,30 @@ module rec CompilerAssertHelpers = use outWriter = new StringWriter (stdout) use errWriter = new StringWriter (stderr) - let succeeded, exn = + let rc, exn = try try Console.SetOut outWriter Console.SetError errWriter - func () - true, None + let rc = func() + match rc with + | :? int as rc -> Some rc, None + | _ -> None, None with e -> let errorMessage = if e.InnerException <> null then e.InnerException.ToString() else e.ToString() stderr.Append errorMessage |> ignore - false, Some e + None, Some e finally Console.SetOut out Console.SetError err outWriter.Close() errWriter.Close() - succeeded, stdout.ToString(), stderr.ToString(), exn + rc, stdout.ToString(), stderr.ToString(), exn - let executeBuiltAppAndReturnResult (outputFilePath: string) (deps: string list) isFsx : (int * string * string) = - let succeeded, stdout, stderr, _ = executeBuiltApp outputFilePath deps isFsx - let exitCode = if succeeded then 0 else -1 - exitCode, stdout, stderr + let executeBuiltAppAndReturnResult (outputFilePath: string) (deps: string list) isFsx : (int option * string * string * exn option) = + let rc, stdout, stderr, exn = executeBuiltApp outputFilePath deps isFsx + rc, stdout, stderr, exn let executeBuiltAppNewProcessAndReturnResult (outputFilePath: string) : (int * string * string) = #if !NETCOREAPP @@ -663,7 +664,7 @@ module rec CompilerAssertHelpers = member _.Dispose() = try File.Delete runtimeconfigPath with | _ -> () } #endif let timeout = 30000 - let exitCode, output, errors = Commands.executeProcess (Some fileName) arguments (Path.GetDirectoryName(outputFilePath)) timeout + let exitCode, output, errors = Commands.executeProcess fileName arguments (Path.GetDirectoryName(outputFilePath)) timeout (exitCode, output |> String.concat "\n", errors |> String.concat "\n") open CompilerAssertHelpers @@ -677,7 +678,7 @@ type CompilerAssert private () = if errors.Length > 0 then Assert.Fail (sprintf "Compile had warnings and/or errors: %A" errors) - executeBuiltApp outputExe [] false |> ignore + executeBuiltApp outputExe [] false |> ignore ) static let compileLibraryAndVerifyILWithOptions options (source: SourceCodeFileKind) (f: ILVerifier -> unit) = @@ -739,11 +740,13 @@ Updated automatically, please check diffs in your pull request, changes must be returnCompilation cmpl (defaultArg ignoreWarnings false) static member ExecuteAndReturnResult (outputFilePath: string, isFsx: bool, deps: string list, newProcess: bool) = - // If we execute in-process (true by default), then the only way of getting STDOUT is to redirect it to SB, and STDERR is from catching an exception. if not newProcess then - executeBuiltAppAndReturnResult outputFilePath deps isFsx + let entryPointReturnCode, deps, isFsx, exn = executeBuiltAppAndReturnResult outputFilePath deps isFsx + entryPointReturnCode, deps, isFsx, exn else - executeBuiltAppNewProcessAndReturnResult outputFilePath + let processExitCode, deps, isFsx = executeBuiltAppNewProcessAndReturnResult outputFilePath + Some processExitCode, deps, isFsx, None + static member Execute(cmpl: Compilation, ?ignoreWarnings, ?beforeExecute, ?newProcess, ?onOutput) = @@ -767,7 +770,7 @@ Updated automatically, please check diffs in your pull request, changes must be Assert.Fail errors onOutput output else - let _succeeded, _stdout, _stderr, exn = executeBuiltApp outputFilePath deps false + let _rc, _stdout, _stderr, exn = executeBuiltApp outputFilePath deps false exn |> Option.iter raise) static member ExecutionHasOutput(cmpl: Compilation, expectedOutput: string) = diff --git a/tests/FSharp.Test.Utilities/ILChecker.fs b/tests/FSharp.Test.Utilities/ILChecker.fs index 4474ef01c10..de0fbd8050b 100644 --- a/tests/FSharp.Test.Utilities/ILChecker.fs +++ b/tests/FSharp.Test.Utilities/ILChecker.fs @@ -16,7 +16,7 @@ module ILChecker = let private exec exe args = let arguments = args |> String.concat " " let timeout = 30000 - let exitCode, _output, errors = Commands.executeProcess (Some exe) arguments "" timeout + let exitCode, _output, errors = Commands.executeProcess exe arguments "" timeout let errors = errors |> String.concat Environment.NewLine errors, exitCode diff --git a/tests/FSharp.Test.Utilities/Peverifier.fs b/tests/FSharp.Test.Utilities/Peverifier.fs index 35db5b208fb..f3ccc7de2b1 100644 --- a/tests/FSharp.Test.Utilities/Peverifier.fs +++ b/tests/FSharp.Test.Utilities/Peverifier.fs @@ -25,7 +25,7 @@ module PEVerifier = let private exec exe args = let arguments = args |> String.concat " " let timeout = 30000 - let exitCode, _output, errors = Commands.executeProcess (Some exe) arguments "" timeout + let exitCode, _output, errors = Commands.executeProcess exe arguments "" timeout let errors = errors |> String.concat Environment.NewLine errors, exitCode diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs index 78feb049435..a75784240dd 100644 --- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs +++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs @@ -1360,9 +1360,8 @@ type ProjectWorkflowBuilder yield! projectOptions.OtherOptions yield! projectOptions.SourceFiles |] - let! _diagnostics, exitCode = checker.Compile(arguments) - if exitCode <> 0 then - exn $"Compilation failed with exit code {exitCode}" |> raise + let! _diagnostics, ex = checker.Compile(arguments) + if ex.IsSome then raise ex.Value return ctx } diff --git a/tests/FSharp.Test.Utilities/TestFramework.fs b/tests/FSharp.Test.Utilities/TestFramework.fs index 6e1611beb5c..dfde63f2352 100644 --- a/tests/FSharp.Test.Utilities/TestFramework.fs +++ b/tests/FSharp.Test.Utilities/TestFramework.fs @@ -63,69 +63,66 @@ module Commands = // Execute the process pathToExe passing the arguments: arguments with the working directory: workingDir timeout after timeout milliseconds -1 = wait forever // returns exit code, stdio and stderr as string arrays let executeProcess pathToExe arguments workingDir (timeout:int) = - match pathToExe with - | Some path -> - let commandLine = ResizeArray() - let errorsList = ResizeArray() - let outputList = ResizeArray() - let errorslock = obj() - let outputlock = obj() - let outputDataReceived (message: string) = - if not (isNull message) then - lock outputlock (fun () -> outputList.Add(message)) - - let errorDataReceived (message: string) = - if not (isNull message) then - lock errorslock (fun () -> errorsList.Add(message)) - - commandLine.Add $"cd {workingDir}" - commandLine.Add $"{path} {arguments} /bl" - - let psi = ProcessStartInfo() - psi.FileName <- path - psi.WorkingDirectory <- workingDir - psi.RedirectStandardOutput <- true - psi.RedirectStandardError <- true - psi.Arguments <- arguments - psi.CreateNoWindow <- true - // When running tests, we want to roll forward to minor versions (including previews). - psi.EnvironmentVariables["DOTNET_ROLL_FORWARD"] <- "LatestMajor" - psi.EnvironmentVariables["DOTNET_ROLL_FORWARD_TO_PRERELEASE"] <- "1" - psi.EnvironmentVariables.Remove("MSBuildSDKsPath") // Host can sometimes add this, and it can break things - psi.UseShellExecute <- false - - use p = new Process() - p.StartInfo <- psi - - p.OutputDataReceived.Add(fun a -> outputDataReceived a.Data) - p.ErrorDataReceived.Add(fun a -> errorDataReceived a.Data) - - if p.Start() then - p.BeginOutputReadLine() - p.BeginErrorReadLine() - if not(p.WaitForExit(timeout)) then - // Timed out resolving throw a diagnostic. - raise (new TimeoutException(sprintf "Timeout executing command '%s' '%s'" (psi.FileName) (psi.Arguments))) - else - p.WaitForExit() - #if DEBUG - let workingDir' = - if workingDir = "" - then - // Assign working dir to prevent default to C:\Windows\System32 - let executionLocation = Assembly.GetExecutingAssembly().Location - Path.GetDirectoryName executionLocation - else - workingDir - - lock gate (fun () -> - File.WriteAllLines(Path.Combine(workingDir', "commandline.txt"), commandLine) - File.WriteAllLines(Path.Combine(workingDir', "StandardOutput.txt"), outputList) - File.WriteAllLines(Path.Combine(workingDir', "StandardError.txt"), errorsList) - ) - #endif - p.ExitCode, outputList.ToArray(), errorsList.ToArray() - | None -> -1, Array.empty, Array.empty + let commandLine = ResizeArray() + let errorsList = ResizeArray() + let outputList = ResizeArray() + let errorslock = obj() + let outputlock = obj() + let outputDataReceived (message: string) = + if not (isNull message) then + lock outputlock (fun () -> outputList.Add(message)) + + let errorDataReceived (message: string) = + if not (isNull message) then + lock errorslock (fun () -> errorsList.Add(message)) + + commandLine.Add $"cd {workingDir}" + commandLine.Add $"{pathToExe} {arguments} /bl" + + let psi = ProcessStartInfo() + psi.FileName <- pathToExe + psi.WorkingDirectory <- workingDir + psi.RedirectStandardOutput <- true + psi.RedirectStandardError <- true + psi.Arguments <- arguments + psi.CreateNoWindow <- true + // When running tests, we want to roll forward to minor versions (including previews). + psi.EnvironmentVariables["DOTNET_ROLL_FORWARD"] <- "LatestMajor" + psi.EnvironmentVariables["DOTNET_ROLL_FORWARD_TO_PRERELEASE"] <- "1" + psi.EnvironmentVariables.Remove("MSBuildSDKsPath") // Host can sometimes add this, and it can break things + psi.UseShellExecute <- false + + use p = new Process() + p.StartInfo <- psi + + p.OutputDataReceived.Add(fun a -> outputDataReceived a.Data) + p.ErrorDataReceived.Add(fun a -> errorDataReceived a.Data) + + if p.Start() then + p.BeginOutputReadLine() + p.BeginErrorReadLine() + if not(p.WaitForExit(timeout)) then + // Timed out resolving throw a diagnostic. + raise (new TimeoutException(sprintf "Timeout executing command '%s' '%s'" (psi.FileName) (psi.Arguments))) + else + p.WaitForExit() +#if DEBUG + let workingDir' = + if workingDir = "" + then + // Assign working dir to prevent default to C:\Windows\System32 + let executionLocation = Assembly.GetExecutingAssembly().Location + Path.GetDirectoryName executionLocation + else + workingDir + + lock gate (fun () -> + File.WriteAllLines(Path.Combine(workingDir', "commandline.txt"), commandLine) + File.WriteAllLines(Path.Combine(workingDir', "StandardOutput.txt"), outputList) + File.WriteAllLines(Path.Combine(workingDir', "StandardError.txt"), errorsList) + ) +#endif + p.ExitCode, outputList.ToArray(), errorsList.ToArray() let getfullpath workDir (path:string) = let rooted = diff --git a/tests/FSharp.Test.Utilities/Utilities.fs b/tests/FSharp.Test.Utilities/Utilities.fs index 6ed885d4e44..1a6d0ff60f8 100644 --- a/tests/FSharp.Test.Utilities/Utilities.fs +++ b/tests/FSharp.Test.Utilities/Utilities.fs @@ -245,7 +245,7 @@ let main argv = 0""" File.WriteAllText(directoryBuildTargetsFileName, directoryBuildTargets) let timeout = 120000 - let exitCode, dotnetoutput, dotneterrors = Commands.executeProcess (Some config.DotNetExe) "build" projectDirectory timeout + let exitCode, dotnetoutput, dotneterrors = Commands.executeProcess config.DotNetExe "build" projectDirectory timeout if exitCode <> 0 || errors.Length > 0 then errors <- dotneterrors diff --git a/tests/fsharp/Compiler/Libraries/Core/Async/AsyncTests.fs b/tests/fsharp/Compiler/Libraries/Core/Async/AsyncTests.fs index 708e7e58e2e..3b83b97db7a 100644 --- a/tests/fsharp/Compiler/Libraries/Core/Async/AsyncTests.fs +++ b/tests/fsharp/Compiler/Libraries/Core/Async/AsyncTests.fs @@ -8,7 +8,7 @@ open FSharp.Test module AsyncTests = // Regression for FSHARP1.0:5969 // Async.StartChild: error when wait async is executed more than once - [] + [] let ``Execute Async multiple times``() = CompilerAssert.CompileExeAndRun """ @@ -24,13 +24,12 @@ let a = async { return result } |> Async.RunSynchronously -exit 0 """ // Regression for FSHARP1.0:5970 // Async.StartChild: race in implementation of ResultCell in FSharp.Core - [] + [] let ``Joining StartChild``() = CompilerAssert.CompileExeAndRun """ @@ -54,12 +53,10 @@ let r = with _ -> (0,0) -exit 0 - """ // Regression test for FSHARP1.0:6086 - [] + [] let ``Mailbox Async dot not StackOverflow``() = CompilerAssert.CompileExeAndRun """ @@ -128,12 +125,11 @@ for meet in meets do printfn "%d" meet printfn "Total: %d in %O" (Seq.sum meets) (watch.Elapsed) -exit 0 """ // Regression for FSHARP1.0:5971 - [] + [] let ``StartChild do not throw ObjectDisposedException``() = CompilerAssert.CompileExeAndRun """ @@ -142,10 +138,9 @@ module M let b = async {return 5} |> Async.StartChild printfn "%A" (b |> Async.RunSynchronously |> Async.RunSynchronously) -exit 0 """ - [] + [] let ``StartChild test Trampoline HijackLimit``() = CompilerAssert.CompileExeAndRun """ @@ -164,5 +159,4 @@ let r = () } |> Async.RunSynchronously -exit 0 """ diff --git a/tests/fsharp/core/controlMailbox/test.fsx b/tests/fsharp/core/controlMailbox/test.fsx index 98d6a7d2f31..5aa65035ecd 100644 --- a/tests/fsharp/core/controlMailbox/test.fsx +++ b/tests/fsharp/core/controlMailbox/test.fsx @@ -6,9 +6,7 @@ module Core_controlMailBox #nowarn "40" // recursive references -#if NETCOREAPP open System.Threading.Tasks -#endif let biggerThanTrampoliningLimit = 10000 @@ -49,22 +47,27 @@ let checkQuiet s x1 x2 = (test s false; log (sprintf "expected: %A, got %A" x2 x1)) -let check s x1 x2 = +let check s x1 x2 = if x1 = x2 then test s true else (test s false; log (sprintf "expected: %A, got %A" x2 x1)) +let checkAsync s (x1: Task<_>) x2 = check s x1.Result x2 + open Microsoft.FSharp.Control -open Microsoft.FSharp.Control.WebExtensions module MailboxProcessorBasicTests = + let test() = check "c32398u6: MailboxProcessor null" - (let mb1 = new MailboxProcessor(fun inbox -> async { return () }) - mb1.Start(); - 100) - 100 + ( + let mb1 = new MailboxProcessor(fun inbox -> async { return () }) + mb1.Start() + 100 + ) + + 100 check "c32398u7: MailboxProcessor Receive/PostAndReply" @@ -197,9 +200,10 @@ module MailboxProcessorBasicTests = 200 for n in [0; 1; 100; 1000; 100000 ] do - check + checkAsync (sprintf "c32398u: MailboxProcessor Post/Receive, n=%d" n) - (let received = ref 0 + (task { + let received = ref 0 let mb1 = new MailboxProcessor(fun inbox -> async { for i in 0 .. n-1 do let! _ = inbox.Receive() @@ -208,48 +212,37 @@ module MailboxProcessorBasicTests = for i in 0 .. n-1 do mb1.Post(i) while !received < n do - if !received % 100 = 0 then - printfn "received = %d" !received -#if NETCOREAPP - Task.Delay(1).Wait() -#else - System.Threading.Thread.Sleep(1) -#endif - !received) + do! Task.Yield() + return !received}) n for timeout in [0; 10] do for n in [0; 1; 100] do - check + checkAsync (sprintf "c32398u: MailboxProcessor Post/TryReceive, n=%d, timeout=%d" n timeout) - (let received = ref 0 + (task { + let received = ref 0 let mb1 = new MailboxProcessor(fun inbox -> async { while !received < n do - let! msgOpt = inbox.TryReceive(timeout=timeout) - match msgOpt with - | None -> - do if !received % 100 = 0 then - printfn "timeout!, received = %d" !received - | Some _ -> do incr received }) + match! inbox.TryReceive(timeout=timeout) with + | Some _ -> incr received + | _ -> () + }) + + mb1.Post(0) + mb1.Start(); for i in 0 .. n-1 do -#if NETCOREAPP - Task.Delay(1).Wait(); -#else - System.Threading.Thread.Sleep(1) -#endif mb1.Post(i) + do! Task.Yield() while !received < n do - if !received % 100 = 0 then - printfn "main thread: received = %d" !received -#if NETCOREAPP - Task.Delay(1).Wait(); -#else - System.Threading.Thread.Sleep(1) -#endif - !received) + do! Task.Yield() + return !received}) n + +(* Disabled for timing issues. Some replacement TryScan tests were added to FSharp.Core.UnitTests. + for i in 1..10 do for sleep in [0;1;10] do for timeout in [10;1;0] do @@ -284,8 +277,11 @@ module MailboxProcessorBasicTests = !timedOut) (Some true) - check "cf72361: MailboxProcessor TryScan wo/timeout" - (let timedOut = ref None +*) + + checkAsync "cf72361: MailboxProcessor TryScan wo/timeout" + (task { + let timedOut = ref None let mb = new MailboxProcessor(fun inbox -> async { let! result = inbox.TryScan((fun i -> if i then async { return () } |> Some else None)) @@ -298,65 +294,58 @@ module MailboxProcessorBasicTests = w.Start() while w.ElapsedMilliseconds < 100L do mb.Post(false) -#if NETCOREAPP - Task.Delay(0).Wait(); -#else - System.Threading.Thread.Sleep(0) -#endif + do! Task.Yield() let r = !timedOut mb.Post(true) - r) + return r}) None module MailboxProcessorErrorEventTests = exception Err of int let test() = // Make sure the event doesn't get raised if no error - check + checkAsync "c32398u9330: MailboxProcessor Error (0)" - (let mb1 = new MailboxProcessor(fun inbox -> async { return () }) - let res = ref 100 - mb1.Error.Add(fun _ -> res := 0) + (task { + let mb1 = new MailboxProcessor(fun inbox -> async { return () }) + mb1.Error.Add(fun _ -> failwith "unexpected error event") mb1.Start(); -#if NETCOREAPP - Task.Delay(200).Wait(); -#else - System.Threading.Thread.Sleep(200) -#endif - !res) + do! Task.Delay(200) + return 100}) 100 // Make sure the event does get raised if error - check + check "c32398u9331: MailboxProcessor Error (1)" (let mb1 = new MailboxProcessor(fun inbox -> async { failwith "fail" }) - let res = ref 0 - mb1.Error.Add(fun _ -> res := 100) + use res = new System.Threading.ManualResetEventSlim(false) + mb1.Error.Add(fun _ -> res.Set()) mb1.Start(); -#if NETCOREAPP - Task.Delay(200).Wait(); -#else - System.Threading.Thread.Sleep(200) -#endif - !res) - 100 + res.Wait() + true) + true // Make sure the event does get raised after message receive - check + checkAsync "c32398u9332: MailboxProcessor Error (2)" - (let mb1 = new MailboxProcessor(fun inbox -> - async { let! msg = inbox.Receive() - raise (Err msg) }) - let res = ref 0 - mb1.Error.Add(function Err n -> res := n | _ -> check "rwe90r - unexpected error" 0 1) - mb1.Start(); - mb1.Post 100 -#if NETCOREAPP - Task.Delay(200).Wait(); -#else - System.Threading.Thread.Sleep(200) -#endif - !res) + ( + let errorNumber = TaskCompletionSource<_>() + + let mb1 = new MailboxProcessor( fun inbox -> async { + let! msg = inbox.Receive() + raise (Err msg) + }) + + mb1.Error.Add(function + | Err n -> errorNumber.SetResult n + | _ -> + check "rwe90r - unexpected error" 0 1 ) + + mb1.Start(); + mb1.Post 100 + + errorNumber.Task + ) 100 type msg = Increment of int | Fetch of AsyncReplyChannel | Reset @@ -472,13 +461,10 @@ let test7() = let timeoutboxes str = new MailboxProcessor<'b>(fun inbox -> - async { for i in 1 .. 10 do -#if NETCOREAPP - Task.Delay(200).Wait() -#else - do System.Threading.Thread.Sleep 200 -#endif - }) + async { + for i in 1 .. 10 do + do! Async.Sleep 200 + }) // Timeout let timeout_tpar() = @@ -553,17 +539,9 @@ let timeout_para_def() = test "default timeout & PostAndAsyncReply" false with _ -> test "default timeout & PostAndAsyncReply" true -// Useful class: put "checkpoints" in the code. -// Check they are called in the right order. -type Path(str) = - let mutable current = 0 - member p.Check n = check (str + " #" + string (current+1)) n (current+1) - current <- n - - - module LotsOfMessages = let test () = + task { let N = 200000 let count = ref N @@ -586,12 +564,9 @@ module LotsOfMessages = check "celrv09ervkn" (queueLength >= logger.CurrentQueueLength) true queueLength <- logger.CurrentQueueLength -#if NETCOREAPP - Task.Delay(10).Wait() -#else - System.Threading.Thread.Sleep(10) -#endif + do! Task.Delay(10) check "celrv09ervknf3ew" logger.CurrentQueueLength 0 + } let RunAll() = MailboxProcessorBasicTests.test() @@ -608,11 +583,11 @@ let RunAll() = timeout_tpar_def() // ToDo: 7/31/2008: Disabled because of probable timing issue. QA needs to re-enable post-CTP. // Tracked by bug FSharp 1.0:2891 - //test15() + // test15() // ToDo: 7/31/2008: Disabled because of probable timing issue. QA needs to re-enable post-CTP. // Tracked by bug FSharp 1.0:2891 - //test15b() - LotsOfMessages.test() + // test15b() + LotsOfMessages.test().Wait() #if TESTS_AS_APP let RUN() = RunAll(); failures @@ -621,6 +596,9 @@ RunAll() let aa = if not failures.IsEmpty then stdout.WriteLine "Test Failed" + stdout.WriteLine() + stdout.WriteLine "failures:" + failures |> List.iter stdout.WriteLine exit 1 else stdout.WriteLine "Test Passed" diff --git a/tests/fsharp/typecheck/sigs/neg06.bsl b/tests/fsharp/typecheck/sigs/neg06.bsl index d55e3e948d2..4e28da2b6d7 100644 --- a/tests/fsharp/typecheck/sigs/neg06.bsl +++ b/tests/fsharp/typecheck/sigs/neg06.bsl @@ -10,7 +10,7 @@ neg06.fs(24,6,24,30): typecheck error FS0944: Abbreviated types cannot be given neg06.fs(27,6,27,33): typecheck error FS0942: Delegate types are always sealed -neg06.fs(31,9,31,29): typecheck error FS0945: Cannot inherit a sealed type +neg06.fs(31,17,31,27): typecheck error FS0945: Cannot inherit a sealed type neg06.fs(37,6,37,29): typecheck error FS0954: This type definition involves an immediate cyclic reference through a struct field or inheritance relation diff --git a/tests/fsharp/typecheck/sigs/neg10.bsl b/tests/fsharp/typecheck/sigs/neg10.bsl index 60e9056de56..31bcdb1882e 100644 --- a/tests/fsharp/typecheck/sigs/neg10.bsl +++ b/tests/fsharp/typecheck/sigs/neg10.bsl @@ -1,9 +1,9 @@ neg10.fsi(9,6,9,7): typecheck error FS0249: Two type definitions named 'x' occur in namespace 'N' in two parts of this assembly -neg10.fs(11,17,11,27): typecheck error FS0946: Cannot inherit from interface type. Use interface ... with instead. +neg10.fs(11,25,11,27): typecheck error FS0946: Cannot inherit from interface type. Use interface ... with instead. -neg10.fs(13,17,13,26): typecheck error FS0945: Cannot inherit a sealed type +neg10.fs(13,25,13,26): typecheck error FS0945: Cannot inherit a sealed type neg10.fs(15,22,15,32): typecheck error FS0887: The type 'C1' is not an interface type diff --git a/tests/fsharp/typecheck/sigs/neg59.bsl b/tests/fsharp/typecheck/sigs/neg59.bsl index a938f0d271c..77a9c8caf46 100644 --- a/tests/fsharp/typecheck/sigs/neg59.bsl +++ b/tests/fsharp/typecheck/sigs/neg59.bsl @@ -33,9 +33,9 @@ neg59.fs(89,15,89,18): typecheck error FS3141: 'try/finally' expressions may not neg59.fs(95,15,95,18): typecheck error FS3141: 'try/finally' expressions may not be used in queries -neg59.fs(102,15,102,64): typecheck error FS3142: 'use' expressions may not be used in queries +neg59.fs(102,15,102,18): typecheck error FS3142: 'use' expressions may not be used in queries -neg59.fs(108,15,108,64): typecheck error FS3142: 'use' expressions may not be used in queries +neg59.fs(108,15,108,18): typecheck error FS3142: 'use' expressions may not be used in queries neg59.fs(113,15,113,25): typecheck error FS3140: 'while' expressions may not be used in queries diff --git a/tests/fsharp/typecheck/sigs/neg61.bsl b/tests/fsharp/typecheck/sigs/neg61.bsl index b0e6b151a2c..d7011cef5ef 100644 --- a/tests/fsharp/typecheck/sigs/neg61.bsl +++ b/tests/fsharp/typecheck/sigs/neg61.bsl @@ -57,7 +57,7 @@ neg61.fs(79,13,79,16): typecheck error FS3146: 'try/with' expressions may not be neg61.fs(86,13,86,16): typecheck error FS3141: 'try/finally' expressions may not be used in queries -neg61.fs(92,13,92,70): typecheck error FS3142: 'use' expressions may not be used in queries +neg61.fs(92,13,92,16): typecheck error FS3142: 'use' expressions may not be used in queries neg61.fs(97,13,97,17): typecheck error FS3143: 'let!', 'use!' and 'do!' expressions may not be used in queries diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/ComputationExpressions/E_MissingUsing.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/ComputationExpressions/E_MissingUsing.fs index 90018a3a6a5..e83604cfdf9 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/ComputationExpressions/E_MissingUsing.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/ComputationExpressions/E_MissingUsing.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions #ComputationExpressions // Regression test for FSHARP1.0:6149 -//This control construct may only be used if the computation expression builder defines a 'Using' method$ +//This control construct may only be used if the computation expression builder defines a 'Using' method$ type R = S of string diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_StructInheritance01b.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_StructInheritance01b.fs index c8771146df5..38184a2ac82 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_StructInheritance01b.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_StructInheritance01b.fs @@ -2,7 +2,7 @@ // Verify error when trying to inherit from a struct type // Regression test for FSHARP1.0:2803 //FS0191: Cannot inherit from interface type -//Cannot inherit a sealed type +//Cannot inherit a sealed type type StructType = struct diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs index 4f9a24e00a8..e5998a72c51 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs @@ -2,10 +2,10 @@ // attribute must match inferred type //The kind of the type specified by its attributes does not match the kind implied by its definition //Structs, interfaces, enums and delegates cannot inherit from other types -//Cannot inherit from interface type\. Use interface \.\.\. with instead +//Cannot inherit from interface type\. Use interface \.\.\. with instead //The kind of the type specified by its attributes does not match the kind implied by its definition //Structs, interfaces, enums and delegates cannot inherit from other types -//Cannot inherit from interface type\. Use interface \.\.\. with instead +//Cannot inherit from interface type\. Use interface \.\.\. with instead // An interface type TK_I_003 = interface diff --git a/tests/service/data/SyntaxTree/Binding/InlineKeywordInBinding.fs.bsl b/tests/service/data/SyntaxTree/Binding/InlineKeywordInBinding.fs.bsl index 5a7bf976186..596eb100812 100644 --- a/tests/service/data/SyntaxTree/Binding/InlineKeywordInBinding.fs.bsl +++ b/tests/service/data/SyntaxTree/Binding/InlineKeywordInBinding.fs.bsl @@ -44,11 +44,12 @@ ImplFile { LeadingKeyword = Let (3,4--3,7) InlineKeyword = Some (3,8--3,14) EqualsRange = Some (3,21--3,22) })], - Const (Unit, (4,4--4,6)), (3,4--4,6), { InKeyword = None }), - (2,11--2,16), NoneAtLet, { LeadingKeyword = Let (2,0--2,3) - InlineKeyword = Some (2,4--2,10) - EqualsRange = Some (2,17--2,18) })], - (2,0--4,6))], PreXmlDocEmpty, [], None, (2,0--5,0), - { LeadingKeyword = None })], (true, true), - { ConditionalDirectives = [] - CodeComments = [] }, set [])) + Const (Unit, (4,4--4,6)), (3,4--4,6), + { LetOrUseKeyword = (3,4--3,7) + InKeyword = None }), (2,11--2,16), NoneAtLet, + { LeadingKeyword = Let (2,0--2,3) + InlineKeyword = Some (2,4--2,10) + EqualsRange = Some (2,17--2,18) })], (2,0--4,6))], + PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })], + (true, true), { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Binding/RangeOfEqualSignShouldBePresentInLocalLetBinding.fs.bsl b/tests/service/data/SyntaxTree/Binding/RangeOfEqualSignShouldBePresentInLocalLetBinding.fs.bsl index 844946e66c3..e3156b5c3b5 100644 --- a/tests/service/data/SyntaxTree/Binding/RangeOfEqualSignShouldBePresentInLocalLetBinding.fs.bsl +++ b/tests/service/data/SyntaxTree/Binding/RangeOfEqualSignShouldBePresentInLocalLetBinding.fs.bsl @@ -20,8 +20,9 @@ ImplFile Yes (3,4--3,13), { LeadingKeyword = Let (3,4--3,7) InlineKeyword = None EqualsRange = Some (3,10--3,11) })], - Const (Unit, (4,4--4,6)), (3,4--4,6), { InKeyword = None }), - (2,0--4,6)), (2,0--4,6))], PreXmlDocEmpty, [], None, (2,0--5,0), - { LeadingKeyword = None })], (true, true), - { ConditionalDirectives = [] - CodeComments = [] }, set [])) + Const (Unit, (4,4--4,6)), (3,4--4,6), + { LetOrUseKeyword = (3,4--3,7) + InKeyword = None }), (2,0--4,6)), (2,0--4,6))], + PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })], + (true, true), { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Binding/RangeOfEqualSignShouldBePresentInLocalLetBindingTyped.fs.bsl b/tests/service/data/SyntaxTree/Binding/RangeOfEqualSignShouldBePresentInLocalLetBindingTyped.fs.bsl index b0e567ed3bd..93dabea4c82 100644 --- a/tests/service/data/SyntaxTree/Binding/RangeOfEqualSignShouldBePresentInLocalLetBindingTyped.fs.bsl +++ b/tests/service/data/SyntaxTree/Binding/RangeOfEqualSignShouldBePresentInLocalLetBindingTyped.fs.bsl @@ -30,8 +30,9 @@ ImplFile { LeadingKeyword = Let (3,4--3,7) InlineKeyword = None EqualsRange = Some (3,15--3,16) })], - Const (Unit, (4,4--4,6)), (3,4--4,6), { InKeyword = None }), - (2,0--4,6)), (2,0--4,6))], PreXmlDocEmpty, [], None, (2,0--5,0), - { LeadingKeyword = None })], (true, true), - { ConditionalDirectives = [] - CodeComments = [] }, set [])) + Const (Unit, (4,4--4,6)), (3,4--4,6), + { LetOrUseKeyword = (3,4--3,7) + InKeyword = None }), (2,0--4,6)), (2,0--4,6))], + PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })], + (true, true), { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Binding/RangeOfLetKeywordShouldBePresentInSynExprLetOrUseBinding.fs.bsl b/tests/service/data/SyntaxTree/Binding/RangeOfLetKeywordShouldBePresentInSynExprLetOrUseBinding.fs.bsl index 31febede5b6..86775dec80c 100644 --- a/tests/service/data/SyntaxTree/Binding/RangeOfLetKeywordShouldBePresentInSynExprLetOrUseBinding.fs.bsl +++ b/tests/service/data/SyntaxTree/Binding/RangeOfLetKeywordShouldBePresentInSynExprLetOrUseBinding.fs.bsl @@ -34,11 +34,12 @@ ImplFile NoneAtLet, { LeadingKeyword = Let (3,4--3,7) InlineKeyword = None EqualsRange = Some (3,12--3,13) })], - Const (Unit, (4,4--4,6)), (3,4--4,6), { InKeyword = None }), - (2,4--2,5), NoneAtLet, { LeadingKeyword = Let (2,0--2,3) - InlineKeyword = None - EqualsRange = Some (2,6--2,7) })], - (2,0--4,6))], PreXmlDocEmpty, [], None, (2,0--5,0), - { LeadingKeyword = None })], (true, true), - { ConditionalDirectives = [] - CodeComments = [] }, set [])) + Const (Unit, (4,4--4,6)), (3,4--4,6), + { LetOrUseKeyword = (3,4--3,7) + InKeyword = None }), (2,4--2,5), NoneAtLet, + { LeadingKeyword = Let (2,0--2,3) + InlineKeyword = None + EqualsRange = Some (2,6--2,7) })], (2,0--4,6))], + PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })], + (true, true), { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Expression/NestedSynExprLetOrUseContainsTheRangeOfInKeyword.fs.bsl b/tests/service/data/SyntaxTree/Expression/NestedSynExprLetOrUseContainsTheRangeOfInKeyword.fs.bsl index 132e7030303..791f6099b9e 100644 --- a/tests/service/data/SyntaxTree/Expression/NestedSynExprLetOrUseContainsTheRangeOfInKeyword.fs.bsl +++ b/tests/service/data/SyntaxTree/Expression/NestedSynExprLetOrUseContainsTheRangeOfInKeyword.fs.bsl @@ -55,8 +55,10 @@ ImplFile [Some (OriginalNotation "+")]), None, (5,6--5,7)), Ident x, (5,4--5,7)), Ident y, (5,4--5,9)), (4,4--5,9), - { InKeyword = Some (4,14--4,16) }), (3,4--5,9), - { InKeyword = Some (3,14--3,16) }), (2,4--2,8), NoneAtLet, + { LetOrUseKeyword = (4,4--4,7) + InKeyword = Some (4,14--4,16) }), (3,4--5,9), + { LetOrUseKeyword = (3,4--3,7) + InKeyword = Some (3,14--3,16) }), (2,4--2,8), NoneAtLet, { LeadingKeyword = Let (2,0--2,3) InlineKeyword = None EqualsRange = Some (2,9--2,10) })], (2,0--5,9))], diff --git a/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseContainsTheRangeOfInKeyword.fs.bsl b/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseContainsTheRangeOfInKeyword.fs.bsl index f9ce333429a..5408f5d71d1 100644 --- a/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseContainsTheRangeOfInKeyword.fs.bsl +++ b/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseContainsTheRangeOfInKeyword.fs.bsl @@ -19,7 +19,8 @@ ImplFile InlineKeyword = None EqualsRange = Some (2,6--2,7) })], Const (Unit, (2,13--2,15)), (2,0--2,15), - { InKeyword = Some (2,10--2,12) }), (2,0--2,15))], + { LetOrUseKeyword = (2,0--2,3) + InKeyword = Some (2,10--2,12) }), (2,0--2,15))], PreXmlDocEmpty, [], None, (2,0--2,15), { LeadingKeyword = None })], (true, true), { ConditionalDirectives = [] CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseDoesNotContainTheRangeOfInKeyword.fs.bsl b/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseDoesNotContainTheRangeOfInKeyword.fs.bsl index 54c3f8180e4..bb9dcafe15f 100644 --- a/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseDoesNotContainTheRangeOfInKeyword.fs.bsl +++ b/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseDoesNotContainTheRangeOfInKeyword.fs.bsl @@ -21,8 +21,9 @@ ImplFile Yes (3,0--3,9), { LeadingKeyword = Let (3,0--3,3) InlineKeyword = None EqualsRange = Some (3,6--3,7) })], - Const (Unit, (4,0--4,2)), (3,0--4,2), { InKeyword = None }), - (2,0--4,2)), (2,0--4,2))], PreXmlDocEmpty, [], None, (2,0--5,0), - { LeadingKeyword = None })], (true, true), - { ConditionalDirectives = [] - CodeComments = [] }, set [])) + Const (Unit, (4,0--4,2)), (3,0--4,2), + { LetOrUseKeyword = (3,0--3,3) + InKeyword = None }), (2,0--4,2)), (2,0--4,2))], + PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })], + (true, true), { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseWhereBodyExprStartsWithTokenOfTwoCharactersDoesNotContainTheRangeOfInKeyword.fs.bsl b/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseWhereBodyExprStartsWithTokenOfTwoCharactersDoesNotContainTheRangeOfInKeyword.fs.bsl index a5d102356f1..554f4eb21ef 100644 --- a/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseWhereBodyExprStartsWithTokenOfTwoCharactersDoesNotContainTheRangeOfInKeyword.fs.bsl +++ b/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseWhereBodyExprStartsWithTokenOfTwoCharactersDoesNotContainTheRangeOfInKeyword.fs.bsl @@ -40,7 +40,8 @@ ImplFile SynLongIdent ([e1; Value], [(4,10--4,11)], [None; None]), None, (4,8--4,16))], [(4,6--4,7)], (4,0--4,16)), - (3,0--4,16), { InKeyword = None }), (2,0--4,16)), + (3,0--4,16), { LetOrUseKeyword = (3,0--3,3) + InKeyword = None }), (2,0--4,16)), (2,0--4,16))], PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })], (true, true), { ConditionalDirectives = [] diff --git a/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseWithRecursiveBindingContainsTheRangeOfInKeyword.fs.bsl b/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseWithRecursiveBindingContainsTheRangeOfInKeyword.fs.bsl index 72352706810..8b57f33b953 100644 --- a/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseWithRecursiveBindingContainsTheRangeOfInKeyword.fs.bsl +++ b/tests/service/data/SyntaxTree/Expression/SynExprLetOrUseWithRecursiveBindingContainsTheRangeOfInKeyword.fs.bsl @@ -35,7 +35,8 @@ ImplFile InlineKeyword = None EqualsRange = Some (4,10--4,11) })], Const (Unit, (5,4--5,6)), (3,4--5,6), - { InKeyword = Some (4,15--4,17) }), (2,0--5,6)), (2,0--5,6))], + { LetOrUseKeyword = (3,4--3,11) + InKeyword = Some (4,15--4,17) }), (2,0--5,6)), (2,0--5,6))], PreXmlDocEmpty, [], None, (2,0--6,0), { LeadingKeyword = None })], (true, true), { ConditionalDirectives = [] CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Expression/Try with - Missing expr 04.fs.bsl b/tests/service/data/SyntaxTree/Expression/Try with - Missing expr 04.fs.bsl index 94ee31ce8d1..74221e70a5f 100644 --- a/tests/service/data/SyntaxTree/Expression/Try with - Missing expr 04.fs.bsl +++ b/tests/service/data/SyntaxTree/Expression/Try with - Missing expr 04.fs.bsl @@ -19,7 +19,8 @@ ImplFile InlineKeyword = None EqualsRange = Some (5,6--5,7) })], ArbitraryAfterError ("seqExpr", (5,10--5,10)), (5,0--5,10), - { InKeyword = None }), [], (3,0--5,10), Yes (3,0--3,3), + { LetOrUseKeyword = (5,0--5,3) + InKeyword = None }), [], (3,0--5,10), Yes (3,0--3,3), Yes (5,10--5,10), { TryKeyword = (3,0--3,3) TryToWithRange = (3,0--5,10) WithKeyword = (5,10--5,10) diff --git a/tests/service/data/SyntaxTree/LeadingKeyword/UseKeyword.fs.bsl b/tests/service/data/SyntaxTree/LeadingKeyword/UseKeyword.fs.bsl index b2b3420c806..4571189344f 100644 --- a/tests/service/data/SyntaxTree/LeadingKeyword/UseKeyword.fs.bsl +++ b/tests/service/data/SyntaxTree/LeadingKeyword/UseKeyword.fs.bsl @@ -22,8 +22,9 @@ ImplFile { LeadingKeyword = Use (3,4--3,7) InlineKeyword = None EqualsRange = Some (3,10--3,11) })], - Const (Unit, (4,4--4,6)), (3,4--4,6), { InKeyword = None }), - (2,0--4,6)), (2,0--4,6))], PreXmlDocEmpty, [], None, (2,0--5,0), - { LeadingKeyword = None })], (true, true), - { ConditionalDirectives = [] - CodeComments = [] }, set [])) + Const (Unit, (4,4--4,6)), (3,4--4,6), + { LetOrUseKeyword = (3,4--3,7) + InKeyword = None }), (2,0--4,6)), (2,0--4,6))], + PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })], + (true, true), { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/LeadingKeyword/UseRecKeyword.fs.bsl b/tests/service/data/SyntaxTree/LeadingKeyword/UseRecKeyword.fs.bsl index 7dbbc35edd7..ac1d1ce9819 100644 --- a/tests/service/data/SyntaxTree/LeadingKeyword/UseRecKeyword.fs.bsl +++ b/tests/service/data/SyntaxTree/LeadingKeyword/UseRecKeyword.fs.bsl @@ -22,8 +22,9 @@ ImplFile { LeadingKeyword = UseRec ((3,4--3,7), (3,8--3,11)) InlineKeyword = None EqualsRange = Some (3,14--3,15) })], - Const (Unit, (4,4--4,6)), (3,4--4,6), { InKeyword = None }), - (2,0--4,6)), (2,0--4,6))], PreXmlDocEmpty, [], None, (2,0--5,0), - { LeadingKeyword = None })], (true, true), - { ConditionalDirectives = [] - CodeComments = [] }, set [])) + Const (Unit, (4,4--4,6)), (3,4--4,6), + { LetOrUseKeyword = (3,4--3,11) + InKeyword = None }), (2,0--4,6)), (2,0--4,6))], + PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })], + (true, true), { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/MatchClause/RangeOfMultipleSynMatchClause.fs.bsl b/tests/service/data/SyntaxTree/MatchClause/RangeOfMultipleSynMatchClause.fs.bsl index 84ce5019498..f4b3b9f7a39 100644 --- a/tests/service/data/SyntaxTree/MatchClause/RangeOfMultipleSynMatchClause.fs.bsl +++ b/tests/service/data/SyntaxTree/MatchClause/RangeOfMultipleSynMatchClause.fs.bsl @@ -25,7 +25,8 @@ ImplFile EqualsRange = Some (3,16--3,17) })], App (NonAtomic, false, Ident Some, Ident content, (4,4--4,16)), - (3,4--4,16), { InKeyword = None }), + (3,4--4,16), { LetOrUseKeyword = (3,4--3,7) + InKeyword = None }), [SynMatchClause (Named (SynIdent (ex, None), false, None, (6,2--6,4)), None, Sequential diff --git a/tests/service/data/SyntaxTree/MatchClause/RangeOfSingleSynMatchClause.fs.bsl b/tests/service/data/SyntaxTree/MatchClause/RangeOfSingleSynMatchClause.fs.bsl index dfa2ad58587..324463e7b2e 100644 --- a/tests/service/data/SyntaxTree/MatchClause/RangeOfSingleSynMatchClause.fs.bsl +++ b/tests/service/data/SyntaxTree/MatchClause/RangeOfSingleSynMatchClause.fs.bsl @@ -25,7 +25,8 @@ ImplFile EqualsRange = Some (3,16--3,17) })], App (NonAtomic, false, Ident Some, Ident content, (4,4--4,16)), - (3,4--4,16), { InKeyword = None }), + (3,4--4,16), { LetOrUseKeyword = (3,4--3,7) + InKeyword = None }), [SynMatchClause (Named (SynIdent (ex, None), false, None, (5,5--5,7)), None, Sequential diff --git a/tests/service/data/SyntaxTree/MatchClause/RangeOfSingleSynMatchClauseFollowedByBar.fs.bsl b/tests/service/data/SyntaxTree/MatchClause/RangeOfSingleSynMatchClauseFollowedByBar.fs.bsl index ea10cf70558..132cbd01cc0 100644 --- a/tests/service/data/SyntaxTree/MatchClause/RangeOfSingleSynMatchClauseFollowedByBar.fs.bsl +++ b/tests/service/data/SyntaxTree/MatchClause/RangeOfSingleSynMatchClauseFollowedByBar.fs.bsl @@ -25,7 +25,8 @@ ImplFile EqualsRange = Some (3,16--3,17) })], App (NonAtomic, false, Ident Some, Ident content, (4,4--4,16)), - (3,4--4,16), { InKeyword = None }), + (3,4--4,16), { LetOrUseKeyword = (3,4--3,7) + InKeyword = None }), [SynMatchClause (Named (SynIdent (ex, None), false, None, (6,2--6,4)), None, Const (Unit, (7,4--7,6)), (6,2--7,6), Yes, diff --git a/tests/service/data/SyntaxTree/Member/Inherit 01.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 01.fs.bsl index e138535c113..f10dc2c0997 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 01.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 01.fs.bsl @@ -13,7 +13,8 @@ ImplFile (Unspecified, [Inherit (LongIdent (SynLongIdent ([I], [], [None])), None, - (4,4--4,13))], (4,4--4,13)), [], None, (3,5--4,13), + (4,4--4,13), { InheritKeyword = (4,4--4,11) })], + (4,4--4,13)), [], None, (3,5--4,13), { LeadingKeyword = Type (3,0--3,4) EqualsRange = Some (3,7--3,8) WithKeyword = None })], (3,0--4,13))], diff --git a/tests/service/data/SyntaxTree/Member/Inherit 03.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 03.fs.bsl index eeab1704856..d0101bb0dd4 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 03.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 03.fs.bsl @@ -13,7 +13,8 @@ ImplFile (Unspecified, [Inherit (LongIdent (SynLongIdent ([], [], [])), None, - (4,4--4,11))], (4,4--4,11)), [], None, (3,5--4,11), + (4,4--4,11), { InheritKeyword = (4,4--4,11) })], + (4,4--4,11)), [], None, (3,5--4,11), { LeadingKeyword = Type (3,0--3,4) EqualsRange = Some (3,7--3,8) WithKeyword = None })], (3,0--4,11))], diff --git a/tests/service/data/SyntaxTree/Member/Inherit 04.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 04.fs.bsl index 9c03baf2b56..7d0dcfc450c 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 04.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 04.fs.bsl @@ -13,7 +13,8 @@ ImplFile (Unspecified, [Inherit (LongIdent (SynLongIdent ([], [], [])), None, - (4,4--4,11))], (4,4--4,11)), [], None, (3,5--4,11), + (4,4--4,11), { InheritKeyword = (4,4--4,11) })], + (4,4--4,11)), [], None, (3,5--4,11), { LeadingKeyword = Type (3,0--3,4) EqualsRange = Some (3,7--3,8) WithKeyword = None })], (3,0--4,11)); diff --git a/tests/service/data/SyntaxTree/Member/Inherit 05.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 05.fs.bsl index ddb47eb7ecc..ab71c976fe7 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 05.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 05.fs.bsl @@ -13,7 +13,7 @@ ImplFile (Unspecified, [Inherit (LongIdent (SynLongIdent ([], [], [])), None, - (4,4--4,11)); + (4,4--4,11), { InheritKeyword = (4,4--4,11) }); Member (SynBinding (None, Normal, false, false, [], diff --git a/tests/service/data/SyntaxTree/Member/Inherit 08.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 08.fs.bsl index fa0211259a4..757d0a30638 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 08.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 08.fs.bsl @@ -13,7 +13,7 @@ ImplFile (Unspecified, [Inherit (LongIdent (SynLongIdent ([], [], [])), None, - (4,4--4,11)); + (4,4--4,11), { InheritKeyword = (4,4--4,11) }); Member (SynBinding (None, Normal, false, false, [], diff --git a/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 05.fs.bsl b/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 05.fs.bsl index 54749497087..7bd27b958c6 100644 --- a/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 05.fs.bsl +++ b/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 05.fs.bsl @@ -30,7 +30,8 @@ ImplFile InlineKeyword = None EqualsRange = None })], ArbitraryAfterError ("seqExpr", (4,10--4,10)), - (4,4--4,10), { InKeyword = None }), (4,4--4,10)), + (4,4--4,10), { LetOrUseKeyword = (4,4--4,7) + InKeyword = None }), (4,4--4,10)), (3,0--4,10)), (3,0--4,10))], PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, (1,0--4,10), { LeadingKeyword = Module (1,0--1,6) })], (true, true), diff --git a/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 06.fs.bsl b/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 06.fs.bsl index 55a07b60288..6120ff4f5fd 100644 --- a/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 06.fs.bsl +++ b/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 06.fs.bsl @@ -26,8 +26,9 @@ ImplFile { LeadingKeyword = Let (4,4--4,7) InlineKeyword = None EqualsRange = Some (4,11--4,12) })], - Const (Unit, (6,4--6,6)), (4,4--6,6), { InKeyword = None }), - (3,0--6,6)), (3,0--6,6))], + Const (Unit, (6,4--6,6)), (4,4--6,6), + { LetOrUseKeyword = (4,4--4,7) + InKeyword = None }), (3,0--6,6)), (3,0--6,6))], PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, (1,0--6,6), { LeadingKeyword = Module (1,0--1,6) })], (true, true), { ConditionalDirectives = [] diff --git a/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 09.fs.bsl b/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 09.fs.bsl index 89a4af5ce5c..0f2e4604d2b 100644 --- a/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 09.fs.bsl +++ b/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 09.fs.bsl @@ -25,7 +25,8 @@ ImplFile { LeadingKeyword = Let (4,4--4,7) InlineKeyword = None EqualsRange = None })], Const (Unit, (6,4--6,6)), - (4,4--6,6), { InKeyword = None }), (3,0--6,6)), (3,0--6,6))], + (4,4--6,6), { LetOrUseKeyword = (4,4--4,7) + InKeyword = None }), (3,0--6,6)), (3,0--6,6))], PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, (1,0--6,6), { LeadingKeyword = Module (1,0--1,6) })], (true, true), { ConditionalDirectives = [] diff --git a/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 10.fs.bsl b/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 10.fs.bsl index f3fa83db96a..5e8ab0f26fd 100644 --- a/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 10.fs.bsl +++ b/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 10.fs.bsl @@ -24,8 +24,9 @@ ImplFile { LeadingKeyword = Let (4,4--4,7) InlineKeyword = None EqualsRange = Some (4,13--4,14) })], - Const (Unit, (6,4--6,6)), (4,4--6,6), { InKeyword = None }), - (3,0--6,6)), (3,0--6,6))], + Const (Unit, (6,4--6,6)), (4,4--6,6), + { LetOrUseKeyword = (4,4--4,7) + InKeyword = None }), (3,0--6,6)), (3,0--6,6))], PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, (1,0--6,6), { LeadingKeyword = Module (1,0--1,6) })], (true, true), { ConditionalDirectives = [] diff --git a/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 11.fs.bsl b/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 11.fs.bsl index e89431a48e0..dbf43bcf3b1 100644 --- a/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 11.fs.bsl +++ b/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 11.fs.bsl @@ -30,8 +30,9 @@ ImplFile { LeadingKeyword = Let (4,4--4,7) InlineKeyword = None EqualsRange = Some (4,15--4,16) })], - Const (Unit, (6,4--6,6)), (4,4--6,6), { InKeyword = None }), - (3,0--6,6)), (3,0--6,6))], + Const (Unit, (6,4--6,6)), (4,4--6,6), + { LetOrUseKeyword = (4,4--4,7) + InKeyword = None }), (3,0--6,6)), (3,0--6,6))], PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, (1,0--6,6), { LeadingKeyword = Module (1,0--1,6) })], (true, true), { ConditionalDirectives = [] diff --git a/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 12.fs.bsl b/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 12.fs.bsl index 97ad7191e25..416dc67c859 100644 --- a/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 12.fs.bsl +++ b/tests/service/data/SyntaxTree/Pattern/Typed - Missing type 12.fs.bsl @@ -38,8 +38,9 @@ ImplFile { LeadingKeyword = Let (4,4--4,7) InlineKeyword = None EqualsRange = Some (4,18--4,19) })], - Const (Unit, (6,4--6,6)), (4,4--6,6), { InKeyword = None }), - (3,0--6,6)), (3,0--6,6))], + Const (Unit, (6,4--6,6)), (4,4--6,6), + { LetOrUseKeyword = (4,4--4,7) + InKeyword = None }), (3,0--6,6)), (3,0--6,6))], PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, (1,0--6,6), { LeadingKeyword = Module (1,0--1,6) })], (true, true), { ConditionalDirectives = [] diff --git a/tests/service/data/SyntaxTree/String/InterpolatedStringOffsideInNestedLet.fs.bsl b/tests/service/data/SyntaxTree/String/InterpolatedStringOffsideInNestedLet.fs.bsl index d91bffd331d..1dfe5586b56 100644 --- a/tests/service/data/SyntaxTree/String/InterpolatedStringOffsideInNestedLet.fs.bsl +++ b/tests/service/data/SyntaxTree/String/InterpolatedStringOffsideInNestedLet.fs.bsl @@ -31,7 +31,8 @@ ImplFile { LeadingKeyword = Let (2,4--2,7) InlineKeyword = None EqualsRange = Some (2,10--2,11) })], Ident b, - (2,4--5,5), { InKeyword = None }), (1,4--1,5), NoneAtLet, + (2,4--5,5), { LetOrUseKeyword = (2,4--2,7) + InKeyword = None }), (1,4--1,5), NoneAtLet, { LeadingKeyword = Let (1,0--1,3) InlineKeyword = None EqualsRange = Some (1,6--1,7) })], (1,0--5,5))],