diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 4dbfc605554..b6cba414baa 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -5,37 +5,37 @@ "commands": [ "dotnet-counters" ], - "version": "8.0.460601" + "version": "8.0.547301" }, "dotnet-dump": { "commands": [ "dotnet-dump" ], - "version": "8.0.460601" + "version": "8.0.547301" }, "dotnet-gcdump": { "commands": [ "dotnet-gcdump" ], - "version": "8.0.460601" + "version": "8.0.547301" }, "dotnet-sos": { "commands": [ "dotnet-sos" ], - "version": "8.0.460601" + "version": "8.0.547301" }, "dotnet-symbol": { "commands": [ "dotnet-symbol" ], - "version": "1.0.460401" + "version": "8.0.547301" }, "dotnet-trace": { "commands": [ "dotnet-trace" ], - "version": "8.0.460601" + "version": "8.0.547301" }, "fantomas": { "commands": [ diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 16d61e579a1..b40e4b69c5b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,3 @@ * @dotnet/fsharp-team-msft -/eng/SourceBuild* @dotnet/source-build-internal +/eng/DotNetBuild.props @dotnet/product-construction +/eng/SourceBuild* @dotnet/source-build 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 fe3cde0444a..15b5f1248e6 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md @@ -5,9 +5,10 @@ * 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 - +* Deprecate places where `seq` can be omitted. ([Language suggestion #1033](https://github.com/fsharp/fslang-suggestions/issues/1033), [PR #17772](https://github.com/dotnet/fsharp/pull/17772)) * Support literal attribute on decimals ([PR #17769](https://github.com/dotnet/fsharp/pull/17769)) ### Changed @@ -19,5 +20,7 @@ * 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)) +* Better ranges for `inherit` `struct` error reporting. ([PR #17886](https://github.com/dotnet/fsharp/pull/17886)) ### Breaking Changes diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md index b18d08e30c3..a38e14215dc 100644 --- a/docs/release-notes/.Language/preview.md +++ b/docs/release-notes/.Language/preview.md @@ -1,6 +1,7 @@ ### Added * Better generic unmanaged structs handling. ([Language suggestion #692](https://github.com/fsharp/fslang-suggestions/issues/692), [PR #12154](https://github.com/dotnet/fsharp/pull/12154)) +* Deprecate places where `seq` can be omitted. ([Language suggestion #1033](https://github.com/fsharp/fslang-suggestions/issues/1033), [PR #17772](https://github.com/dotnet/fsharp/pull/17772)) ### Fixed diff --git a/docs/release-notes/.VisualStudio/17.13.md b/docs/release-notes/.VisualStudio/17.13.md new file mode 100644 index 00000000000..dae07600e1b --- /dev/null +++ b/docs/release-notes/.VisualStudio/17.13.md @@ -0,0 +1,8 @@ +### Fixed + +### Added +* Code fix for adding missing `seq`. ([PR #17772](https://github.com/dotnet/fsharp/pull/17772)) + +### Changed + +### Breaking Changes diff --git a/eng/DotNetBuild.props b/eng/DotNetBuild.props index c7bc688ba3e..6891541838a 100644 --- a/eng/DotNetBuild.props +++ b/eng/DotNetBuild.props @@ -1,4 +1,4 @@ - + diff --git a/eng/SourceBuildPrebuiltBaseline.xml b/eng/SourceBuildPrebuiltBaseline.xml index 4416e9693af..18f3b782d76 100644 --- a/eng/SourceBuildPrebuiltBaseline.xml +++ b/eng/SourceBuildPrebuiltBaseline.xml @@ -1,4 +1,4 @@ - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a6fe9dd9339..92075c52737 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,9 +1,9 @@ - + https://github.com/dotnet/source-build-reference-packages - 08649fed58d668737a54913f7d4c649a8da5dc6e + f3889ab90d78377122a3e427fe9a74c03611a4bd diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index e739169ea9c..31ce9be573c 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -3322,7 +3322,7 @@ module EstablishTypeDefinitionCores = | SynTypeDefnSimpleRepr.Record _ -> if tycon.IsStructRecordOrUnionTycon then Some(g.system_Value_ty) else None - | SynTypeDefnSimpleRepr.General (kind, _, slotsigs, fields, isConcrete, _, _, _) -> + | SynTypeDefnSimpleRepr.General (kind, inherits, slotsigs, fields, isConcrete, _, _, _) -> let kind = InferTyconKind g (kind, attrs, slotsigs, fields, inSig, isConcrete, m) match inheritedTys with @@ -3333,15 +3333,20 @@ module EstablishTypeDefinitionCores = | SynTypeDefnKind.Opaque | SynTypeDefnKind.Class | SynTypeDefnKind.Interface -> None | _ -> error(InternalError("should have inferred tycon kind", m)) - | [(ty, m)] -> - if not firstPass && not (match kind with SynTypeDefnKind.Class -> true | _ -> false) then - errorR (Error(FSComp.SR.tcStructsInterfacesEnumsDelegatesMayNotInheritFromOtherTypes(), m)) - CheckSuperType cenv ty m + | [(ty, m)] -> + let inheritRange = + match inherits with + | [] -> m + | (synType, _, _) :: _ -> synType.Range + if not firstPass && not (match kind with SynTypeDefnKind.Class -> true | _ -> false) then + errorR (Error(FSComp.SR.tcStructsInterfacesEnumsDelegatesMayNotInheritFromOtherTypes(), inheritRange)) + CheckSuperType cenv ty inheritRange if isTyparTy g ty then if firstPass then - errorR(Error(FSComp.SR.tcCannotInheritFromVariableType(), m)) + errorR(Error(FSComp.SR.tcCannotInheritFromVariableType(), inheritRange)) Some g.obj_ty_noNulls // a "super" that is a variable type causes grief later - else + else + Some ty | _ -> error(Error(FSComp.SR.tcTypesCannotInheritFromMultipleConcreteTypes(), m)) @@ -3622,7 +3627,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 +4301,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 +4473,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/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 4325d503206..9c14787d113 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -5891,6 +5891,17 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, pat, synEnumExpr, synBodyExpr, m, spFor, spIn, m) | SynExpr.ComputationExpr (hasSeqBuilder, comp, m) -> + let isIndexRange = match comp with | SynExpr.IndexRange _ -> true | _ -> false + let deprecatedPlacesWhereSeqCanBeOmitted = + cenv.g.langVersion.SupportsFeature LanguageFeature.DeprecatePlacesWhereSeqCanBeOmitted + if + deprecatedPlacesWhereSeqCanBeOmitted + && isIndexRange + && not hasSeqBuilder + && not cenv.g.compilingFSharpCore + then + warning (Error(FSComp.SR.chkDeprecatePlacesWhereSeqCanBeOmitted (), m)) + let env = ExitFamilyRegion env cenv.TcSequenceExpressionEntry cenv env overallTy tpenv (hasSeqBuilder, comp) m @@ -7140,7 +7151,7 @@ and CheckSuperType (cenv: cenv) ty m = typeEquiv g ty g.system_Array_ty || typeEquiv g ty g.system_MulticastDelegate_ty || typeEquiv g ty g.system_Delegate_ty then - error(Error(FSComp.SR.tcPredefinedTypeCannotBeUsedAsSuperType(), m)) + errorR(Error(FSComp.SR.tcPredefinedTypeCannotBeUsedAsSuperType(), m)) if isErasedType g ty then errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m)) 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/FSComp.txt b/src/Compiler/FSComp.txt index b5a50afc7c0..9a6b69fa2ff 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1783,4 +1783,6 @@ featureEmptyBodiedComputationExpressions,"Support for computation expressions wi featureAllowAccessModifiersToAutoPropertiesGettersAndSetters,"Allow access modifiers to auto properties getters and setters" 3871,tcAccessModifiersNotAllowedInSRTPConstraint,"Access modifiers cannot be applied to an SRTP constraint." featureAllowObjectExpressionWithoutOverrides,"Allow object expressions without overrides" -3872,tcPartialActivePattern,"Multi-case partial active patterns are not supported. Consider using a single-case partial active pattern or a full active pattern." \ No newline at end of file +3872,tcPartialActivePattern,"Multi-case partial active patterns are not supported. Consider using a single-case partial active pattern or a full active pattern." +3873,chkDeprecatePlacesWhereSeqCanBeOmitted,"This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}'" +featureDeprecatePlacesWhereSeqCanBeOmitted,"Deprecate places where 'seq' can be omitted" \ No newline at end of file diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 5c311237594..3488a3399e1 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -94,6 +94,7 @@ type LanguageFeature = | ParsedHashDirectiveArgumentNonQuotes | EmptyBodiedComputationExpressions | AllowObjectExpressionWithoutOverrides + | DeprecatePlacesWhereSeqCanBeOmitted /// LanguageVersion management type LanguageVersion(versionText) = @@ -219,6 +220,7 @@ type LanguageVersion(versionText) = LanguageFeature.FromEndSlicing, previewVersion // Unfinished features --- needs work LanguageFeature.AllowAccessModifiersToAutoPropertiesGettersAndSetters, previewVersion LanguageFeature.AllowObjectExpressionWithoutOverrides, previewVersion + LanguageFeature.DeprecatePlacesWhereSeqCanBeOmitted, previewVersion ] static let defaultLanguageVersion = LanguageVersion("default") @@ -375,6 +377,7 @@ type LanguageVersion(versionText) = | LanguageFeature.ParsedHashDirectiveArgumentNonQuotes -> FSComp.SR.featureParsedHashDirectiveArgumentNonString () | LanguageFeature.EmptyBodiedComputationExpressions -> FSComp.SR.featureEmptyBodiedComputationExpressions () | LanguageFeature.AllowObjectExpressionWithoutOverrides -> FSComp.SR.featureAllowObjectExpressionWithoutOverrides () + | LanguageFeature.DeprecatePlacesWhereSeqCanBeOmitted -> FSComp.SR.featureDeprecatePlacesWhereSeqCanBeOmitted () /// Get a version string associated with the given feature. static member GetFeatureVersionString feature = diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index 7408300b943..6396f7b72c0 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -85,6 +85,7 @@ type LanguageFeature = | ParsedHashDirectiveArgumentNonQuotes | EmptyBodiedComputationExpressions | AllowObjectExpressionWithoutOverrides + | DeprecatePlacesWhereSeqCanBeOmitted /// LanguageVersion management type LanguageVersion = 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/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/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 6a550c3b1a8..2cd42701e70 100644 --- a/src/Compiler/SyntaxTree/SyntaxTrivia.fs +++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fs @@ -420,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 f16294b0a1d..ab6525bc010 100644 --- a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi @@ -522,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/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/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 958a1357ac9..4a6bbf58d2f 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -52,6 +52,11 @@ Tento výraz je anonymní záznam, použijte {{|...|}} místo {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Duplicitní parametr Parametr {0} byl v této metodě použit vícekrát. @@ -322,6 +327,11 @@ opravit překlad názvů typů delegátů, viz https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding vzor discard ve vazbě použití @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Neplatný výraz záznamu, pořadí nebo výpočtu. Výrazy pořadí by měly mít notaci seq {{ ... }}. + Neplatný výraz záznamu, pořadí nebo výpočtu. Výrazy pořadí by měly mít notaci seq {{ ... }}. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index d7233a5d2fc..1546541aee7 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -52,6 +52,11 @@ Dieser Ausdruck ist ein anonymer Datensatz. Verwenden Sie {{|...|}} anstelle von {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Doppelter Parameter. Der Parameter „{0}“ wurde in dieser Methode mehrmals verwendet. @@ -322,6 +327,11 @@ Informationen zur Problembehebung bezüglich der Auflösung von Delegattypnamen finden Sie unter https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding Das Verwerfen des verwendeten Musters ist verbindlich. @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Ungültiger Datensatz-, Sequenz- oder Berechnungsausdruck. Sequenzausdrücke müssen das Format "seq {{ ... }}" besitzen. + Ungültiger Datensatz-, Sequenz- oder Berechnungsausdruck. Sequenzausdrücke müssen das Format "seq {{ ... }}" besitzen. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 1b3205ffa53..db357235565 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -52,6 +52,11 @@ Esta expresión es un registro anónimo; use {{|...|}} en lugar de {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Parámetro duplicado. El parámetro '{0}' se ha usado más una vez en este método. @@ -322,6 +327,11 @@ corrección para la resolución de nombres de tipo de delegado, consulte https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding descartar enlace de patrón en uso @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Expresión de registro, secuencia o cómputo no válida. Las expresiones de secuencia deben tener el formato 'seq {{ ... }}'. + Expresión de registro, secuencia o cómputo no válida. Las expresiones de secuencia deben tener el formato 'seq {{ ... }}'. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 018180a8fb6..dca6fe2b78d 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -52,6 +52,11 @@ Cette expression est un enregistrement anonyme, utilisez {{|...|}} au lieu de {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Paramètre dupliqué. Le paramètre « {0} » a été utilisé une fois de plus dans cette méthode. @@ -322,6 +327,11 @@ corriger pour résoudre les noms de types délégués, voir https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding annuler le modèle dans la liaison d’utilisation @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Expression d'enregistrement, de séquence ou de calcul non valide. Les expressions de séquence doivent avoir le format 'seq {{ ... }}' + Expression d'enregistrement, de séquence ou de calcul non valide. Les expressions de séquence doivent avoir le format 'seq {{ ... }}' diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 7cc3f46259b..0d2815aa9b2 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -52,6 +52,11 @@ Questa espressione è un record anonimo. Usa {{|...|}} invece di {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Parametro duplicato. Il parametro '{0}' è stato utilizzato più volte in questo metodo. @@ -322,6 +327,11 @@ correggere la risoluzione dei nomi dei tipi delegati, vedere https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding rimuovi criterio nell'utilizzo dell'associazione @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Espressione di calcolo, sequenza o record non valida. Il formato delle espressioni sequenza deve essere 'seq {{ ... }}' + Espressione di calcolo, sequenza o record non valida. Il formato delle espressioni sequenza deve essere 'seq {{ ... }}' diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 10c5f06f4ff..d660cf6768b 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -52,6 +52,11 @@ この式は匿名レコードであり、{{...}} の代わりに {{|...|}} を使用してください。 + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. パラメーターが重複しています。パラメーター '{0}' は、このメソッドで 1 回以上使用されています。 @@ -322,6 +327,11 @@ デリゲート型名の解決を修正するには、https://github.com/dotnet/fsharp/issues/10228 を参照してください + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding 使用バインドでパターンを破棄する @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - 無効なレコード、シーケンス式、またはコンピュテーション式です。シーケンス式は 'seq {{ ... }}' という形式にしてください。 + 無効なレコード、シーケンス式、またはコンピュテーション式です。シーケンス式は 'seq {{ ... }}' という形式にしてください。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 94cd344f052..a0f3d1411b4 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -52,6 +52,11 @@ 이 식은 익명 레코드입니다. {{...}} 대신 {{|...|}}을 사용하세요. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. 매개 변수가 중복되었습니다. 이 메소드에서 매개 변수 '{0}'이(가) 두 번 이상 사용되었습니다. @@ -322,6 +327,11 @@ 대리자 형식 이름의 해결 방법을 수정합니다. https://github.com/dotnet/fsharp/issues/10228 참조하세요. + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding 사용 중인 패턴 바인딩 무시 @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - 레코드, 시퀀스 또는 계산 식이 잘못되었습니다. 시퀀스 식의 형식은 'seq {{ ... }}'여야 합니다. + 레코드, 시퀀스 또는 계산 식이 잘못되었습니다. 시퀀스 식의 형식은 'seq {{ ... }}'여야 합니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 01f2ff1d5e3..fcb2638d5a2 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -52,6 +52,11 @@ To wyrażenie jest rekordem anonimowym. Użyj {{|...|}} zamiast {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Zduplikowany parametr. Parametr „{0}” został użyty więcej niż raz w tej metodzie. @@ -322,6 +327,11 @@ naprawa rozpoznawania nazw typów delegatów, sprawdź stronę https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding odrzuć wzorzec w powiązaniu użycia @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Nieprawidłowe wyrażenie rekordu, sekwencji lub obliczenia. Wyrażenia sekwencji powinny mieć postać „seq {{ ... }}” + Nieprawidłowe wyrażenie rekordu, sekwencji lub obliczenia. Wyrażenia sekwencji powinny mieć postać „seq {{ ... }}” diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 63da6a667b1..a27487e1c20 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -52,6 +52,11 @@ Esta expressão é um registro anônimo, use {{|...|}} em vez de {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Parâmetro duplicado. O parâmetro '{0}' foi usado mais de uma vez neste método. @@ -322,6 +327,11 @@ corrigir para resolução de nomes de tipos delegados, consulte https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding descartar o padrão em uso de associação @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Expressão de registro, sequência ou computação inválida. Expressões de sequência devem estar na forma 'seq {{ ... }}' + Expressão de registro, sequência ou computação inválida. Expressões de sequência devem estar na forma 'seq {{ ... }}' diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 231bc83103b..18c6c501759 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -52,6 +52,11 @@ Это выражение является анонимной записью. Используйте {{|...|}} вместо {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Повторяющийся параметр. Параметр "{0}" использовался в этом методе несколько раз. @@ -322,6 +327,11 @@ исправить разрешение имен типов делегатов, см. https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding шаблон отмены в привязке использования @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Недопустимая запись, выражение последовательности или вычислительное выражение. Выражения последовательностей должны иметь форму "seq {{ ... }}' + Недопустимая запись, выражение последовательности или вычислительное выражение. Выражения последовательностей должны иметь форму "seq {{ ... }}' diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index a3bab7e5a92..94a7a284470 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -52,6 +52,11 @@ Bu ifade, anonim bir kayıt, {{...}} yerine {{|...|}} kullanın. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Yinelenen parametre. '{0}' parametresi bu metotta bir kereden fazla kullanıldı. @@ -322,6 +327,11 @@ temsilci türü adlarının çözümlenmesiyle ilgili sorunun çözümü için bkz. https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding kullanım bağlamasında deseni at @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Geçersiz kayıt, dizi veya hesaplama ifadesi. Dizi ifadeleri 'seq {{ ... }}' biçiminde olmalıdır + Geçersiz kayıt, dizi veya hesaplama ifadesi. Dizi ifadeleri 'seq {{ ... }}' biçiminde olmalıdır diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 579ac9b79c3..ba5826eb686 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -52,6 +52,11 @@ 此表达式是匿名记录,请使用 {{|...|}} 而不是 {{...}}。 + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. 参数重复。此方法中多次使用了参数“{0}”。 @@ -322,6 +327,11 @@ 修复了委托类型名称的解析,请参阅 https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding 放弃使用绑定模式 @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - 记录、序列或计算表达式无效。序列表达式的格式应为“seq {{ ... }}” + 记录、序列或计算表达式无效。序列表达式的格式应为“seq {{ ... }}” diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 09818a7487b..b039caf9e93 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -52,6 +52,11 @@ 此運算式是匿名記錄,請使用 {{|...|}} 而不是 {{...}}。 + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. 重複的參數。參數 '{0}' 在此方法中使用多次。 @@ -322,6 +327,11 @@ 修正委派類型名稱的解析,請參閱 https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding 捨棄使用繫結中的模式 @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - 無效的記錄、循序項或計算運算式。循序項運算式應該是 'seq {{ ... }}' 形式。 + 無效的記錄、循序項或計算運算式。循序項運算式應該是 'seq {{ ... }}' 形式。 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/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/StructTypes/E_Inheritance.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/E_Inheritance.fs new file mode 100644 index 00000000000..4407d0dafed --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/E_Inheritance.fs @@ -0,0 +1,7 @@ +type TK_I_005 = + abstract M : unit -> unit + +[] +type TK_I_006b = + inherit TK_I_005 + diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/StructTypes.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/StructTypes.fs index 95f228de96a..95e1cb2e4a6 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/StructTypes.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/StructTypes.fs @@ -38,3 +38,15 @@ module StructTypes = |> shouldSucceed |> ignore + [] + let ``StructTypes - E_Inheritance.fs`` compilation = + compilation + |> asFsx + |> withOptions ["--warnaserror+"; "--nowarn:988"] + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 931, Line 6, Col 12, Line 6, Col 20, "Structs, interfaces, enums and delegates cannot inherit from other types"); + (Error 946, Line 6, Col 12, Line 6, Col 20, "Cannot inherit from interface type. Use interface ... with instead.") + ] + 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/ErrorMessages/ClassesTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs index 55f4d1cbf1b..f902fa14369 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs @@ -815,4 +815,38 @@ 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.") + ] + + [] + let ``The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class.`` () = + Fsx """ +type C1 = class inherit System.ValueType override x.ToString() = "" end +type C2 = class inherit System.Array override x.ToString() = "" end +type C3 = class inherit System.Enum override x.ToString() = "" end +type C4 = class inherit System.Delegate override x.ToString() = "" end +type C5 = class inherit System.MulticastDelegate override x.ToString() = "" end + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 771, Line 2, Col 25, Line 2, Col 41, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class"); + (Error 771, Line 3, Col 25, Line 3, Col 37, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class"); + (Error 771, Line 4, Col 25, Line 4, Col 36, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class") + (Error 771, Line 5, Col 25, Line 5, Col 40, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class"); + (Error 771, Line 6, Col 25, Line 6, Col 49, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class") + ] \ 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 029ec14b0b4..af431847400 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -223,6 +223,7 @@ + @@ -237,7 +238,6 @@ - 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/Language/SequenceExpressions/E_SequenceExpressions01.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/E_SequenceExpressions01.fs new file mode 100644 index 00000000000..37ca58c3db6 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/E_SequenceExpressions01.fs @@ -0,0 +1,76 @@ +{ 1..10 } + +{ 1..5..10 } + +[| { 1..10 } |] + +[| { 1..5..10 } |] + +let a = { 1..10 } + +let a3 = { 1..10..20 } + +let b = [| { 1..10 } |] + +let b3 = [| { 1..10..20 } |] + +let c = [ { 1..10 } ] + +[| { 1..10 } |] + +[| yield { 1..10 } |] + +[ { 1..10 } ] + +[ { 1..10..10 } ] + +[ yield { 1..10 } ] + +[ yield { 1..10..20 } ] + +ResizeArray({ 1..10 }) + +ResizeArray({ 1..10..20 }) + +let fw start finish = [ for x in { start..finish } -> x ] + +let fe start finish = [| for x in { start..finish } -> x |] + +for x in { 1..10 } do () + +for x in { 1..5..10 } do () + +let f = Seq.head + +let a2 = f { 1..6 } + +let a23 = f { 1..6..10 } + +let b2 = set { 1..6 } + +let f10 start finish = for x in { start..finish } do ignore (float x ** float x) + +let (..) _ _ = "lol" + +let lol1 = { 1..10 } + +{ 1..5..10 } + +let resultInt = Seq.length {1..8} + +let resultInt2 funcInt = Seq.map3 funcInt { 1..8 } { 2..9 } { 3..10 } + +let verify c = failwith "not implemented" + +Seq.splitInto 4 {1..5} |> verify { 1.. 10 } + +seq [ {1..4}; {5..7}; {8..10} ] + +Seq.allPairs { 1..7 } Seq.empty + +Seq.allPairs Seq.empty { 1..7 } + +let intArr1 = [| yield! {1..100} + yield! {1..100} |] + +Array.ofSeq {1..10} \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressionTests.fs similarity index 59% rename from tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressionTests.fs rename to tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressionTests.fs index 8247eaf60e3..263f305f7a5 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressionTests.fs @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -module Language.SequenceExpressionTests +module Language.SequenceExpression.SequenceExpressionTests +open FSharp.Test open Xunit open FSharp.Test.Compiler open FSharp.Test.ScriptHelpers @@ -467,4 +468,125 @@ let f2 = return! [ 3; 4 ] |> withDiagnostics [ (Error 748, Line 2, Col 10, Line 2, Col 16, "This construct may only be used within computation expressions. To return a value from an ordinary function simply write the expression without 'return'."); (Error 748, Line 3, Col 10, Line 3, Col 17, "This construct may only be used within computation expressions. To return a value from an ordinary function simply write the expression without 'return'.") - ] \ No newline at end of file + ] + +[] +let ``Sequence(SynExpr.Sequential) expressions should be of the form 'seq { ... } lang version 9``() = + Fsx """ +{ 1;10 } +[| { 1;10 } |] +let a = { 1;10 } +let b = [| { 1;10 } |] +let c = [ { 1;10 } ] + """ + |> withOptions [ "--nowarn:0020" ] + |> withLangVersion90 + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 740, Line 2, Col 1, Line 2, Col 9, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 3, Col 4, Line 3, Col 12, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 4, Col 9, Line 4, Col 17, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 5, Col 12, Line 5, Col 20, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 6, Col 11, Line 6, Col 19, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + ] + +[] +let ``Sequence(SynExpr.Sequential) expressions should be of the form 'seq { ... } lang version preview``() = + Fsx """ +{ 1;10 } +[| { 1;10 } |] +let a = { 1;10 } +let b = [| { 1;10 } |] +let c = [ { 1;10 } ] + """ + |> withOptions [ "--nowarn:0020" ] + |> withLangVersionPreview + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 740, Line 2, Col 1, Line 2, Col 9, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 3, Col 4, Line 3, Col 12, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 4, Col 9, Line 4, Col 17, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 5, Col 12, Line 5, Col 20, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 6, Col 11, Line 6, Col 19, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + ] + +// SOURCE=E_SequenceExpressions01.fs # E_SequenceExpressions01.fs +[] +let ``E_SequenceExpressions01 lang version 9`` compilation = + compilation + |> withOptions [ "--nowarn:0020" ] + |> withLangVersion90 + |> typecheck + |> shouldSucceed + +// SOURCE=E_SequenceExpressions01.fs # E_SequenceExpressions01.fs +[] +let ``E_SequenceExpressions01 lang version preview`` compilation = + compilation + |> withOptions [ "--nowarn:0020" ] + |> withLangVersionPreview + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Warning 3873, Line 1, Col 1, Line 1, Col 10, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 3, Col 1, Line 3, Col 13, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 5, Col 4, Line 5, Col 13, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 7, Col 4, Line 7, Col 16, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 9, Col 9, Line 9, Col 18, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 11, Col 10, Line 11, Col 23, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 13, Col 12, Line 13, Col 21, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 15, Col 13, Line 15, Col 26, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 17, Col 11, Line 17, Col 20, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 19, Col 4, Line 19, Col 13, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 21, Col 10, Line 21, Col 19, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 23, Col 3, Line 23, Col 12, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 25, Col 3, Line 25, Col 16, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 27, Col 9, Line 27, Col 18, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 29, Col 9, Line 29, Col 22, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 31, Col 13, Line 31, Col 22, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 33, Col 13, Line 33, Col 26, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 35, Col 34, Line 35, Col 51, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 37, Col 35, Line 37, Col 52, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 39, Col 10, Line 39, Col 19, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 41, Col 10, Line 41, Col 22, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 45, Col 12, Line 45, Col 20, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 47, Col 13, Line 47, Col 25, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 49, Col 14, Line 49, Col 22, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 51, Col 33, Line 51, Col 50, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 55, Col 12, Line 55, Col 21, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 57, Col 1, Line 57, Col 13, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 59, Col 28, Line 59, Col 34, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 61, Col 44, Line 61, Col 52, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 61, Col 53, Line 61, Col 61, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 61, Col 62, Line 61, Col 71, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 65, Col 17, Line 65, Col 23, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 65, Col 34, Line 65, Col 44, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 67, Col 7, Line 67, Col 13, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 67, Col 15, Line 67, Col 21, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 67, Col 23, Line 67, Col 30, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 69, Col 14, Line 69, Col 22, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 71, Col 24, Line 71, Col 32, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 73, Col 25, Line 73, Col 33, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 74, Col 25, Line 74, Col 33, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 76, Col 13, Line 76, Col 20, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + ] + +// SOURCE=SequenceExpressions01.fs # SequenceExpressions01.fs +[] +let ``SequenceExpressions01 lang version 9`` compilation = + compilation + |> withOptions [ "--nowarn:0020" ] + |> withLangVersion90 + |> typecheck + |> shouldSucceed + +// SOURCE=SequenceExpressions01.fs # SequenceExpressions01.fs +[] +let ``SequenceExpressions01 lang version preview`` compilation = + compilation + |> withOptions [ "--nowarn:0020" ] + |> withLangVersionPreview + |> typecheck + |> shouldSucceed \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions01.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions01.fs new file mode 100644 index 00000000000..ea1ab603eef --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions01.fs @@ -0,0 +1,76 @@ +seq { 1..10 } + +seq { 1..5..10 } + +[| seq { 1..10 } |] + +[| seq { 1..5..10 } |] + +let a = seq { 1..10 } + +let a3 = seq { 1..10..20 } + +let b = [| seq { 1..10 } |] + +let b3 = [| seq { 1..10..20 } |] + +let c = [ seq { 1..10 } ] + +[| seq { 1..10 } |] + +[| yield seq { 1..10 } |] + +[ seq { 1..10 } ] + +[ seq { 1..10..10 } ] + +[ yield seq { 1..10 } ] + +[ yield seq { 1..10..20 } ] + +ResizeArray(seq { 1..10 }) + +ResizeArray(seq { 1..10..20 }) + +let fw start finish = [ for x in seq { start..finish } -> x ] + +let fe start finish = [| for x in seq { start..finish } -> x |] + +for x in seq { 1..10 } do () + +for x in seq { 1..5..10 } do () + +let f = Seq.head + +let a2 = f (seq { 1..6 }) + +let a23 = f (seq { 1..6..10 }) + +let b2 = set (seq { 1..6 }) + +let f10 start finish = for x in seq { start..finish } do ignore (float x ** float x) + +let (..) _ _ = "lol" + +let lol1 = seq { 1..10 } + +seq { 1..5..10 } + +let resultInt = Seq.length (seq {1..8}) + +let resultInt2 funcInt = Seq.map3 funcInt (seq { 1..8 }) (seq { 2..9 }) (seq { 3..10 }) + +let verify c = failwith "not implemented" + +Seq.splitInto 4 (seq {1..5}) |> verify (seq { 1.. 10 }) + +seq [ seq {1..4}; seq {5..7}; seq {8..10} ] + +Seq.allPairs (seq { 1..7 }) Seq.empty + +Seq.allPairs Seq.empty (seq { 1..7 }) + +let intArr1 = [| yield! seq {1..100} + yield! seq {1..100} |] + +Array.ofSeq (seq {1..10}) \ No newline at end of file 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 15e1dd848e6..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 @@ -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) 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 15e1dd848e6..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 @@ -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) diff --git a/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs b/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs index 4ae43434099..e22c58e8a3a 100644 --- a/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs @@ -455,7 +455,7 @@ let r as _ = 10 let s as Id0 = 11 let t as (u) = 12 let v as struct(w, x) = 13, 14 -let y as z : int = 15{set { 'a'..'x' } - set [ 'p'; 'v' ] |> Set.map (sprintf " + %c") |> System.String.Concat} +let y as z : int = 15{set (seq { 'a'..'x' }) - set [ 'p'; 'v' ] |> Set.map (sprintf " + %c") |> System.String.Concat} Some p |> eq Some v |> eq () @@ -590,7 +590,7 @@ let _ as r = 10 let Id0 as s = 11 let (t) as u = 12 let struct(w, v) as x = 13, 14 -let (y : int) as z = 15{set { 'a'..'v' } - set [ 'h'; 'q' ] |> Set.map (sprintf " + %c") |> System.String.Concat} +let (y : int) as z = 15{set (seq { 'a'..'v' }) - set [ 'h'; 'q' ] |> Set.map (sprintf " + %c") |> System.String.Concat} Some h |> eq Some q |> eq Some x |> eq @@ -917,7 +917,7 @@ let :? z as [] let ``As 16 - syntactical precedence matrix testing left with type tests - total patterns`` () = - let validSet = set { 'a'..'x' } - set [ 'p'; 'q' ] |> Set.map string + let validSet = set (seq { 'a'..'x' }) - set [ 'p'; 'q' ] |> Set.map string let _, checkResults = getParseAndCheckResults70 $""" let eq<'T> (x:'T option) = () // FS-1093-safe type assert function let (|Id0|) = ignore 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.Collections/ArrayModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs index c2b0d240372..662a729e28f 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs @@ -259,8 +259,8 @@ type ArrayModule() = [] member _.Except() = // integer array - let intArr1 = [| yield! {1..100} - yield! {1..100} |] + let intArr1 = [| yield! seq {1..100} + yield! seq {1..100} |] let intArr2 = [| 1 .. 10 |] let expectedIntArr = [| 11 .. 100 |] diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs index ec30e724bbb..5c5afc3c234 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs @@ -372,7 +372,7 @@ type ArrayModule2() = [] member this.Of_Seq() = // integer array - let resultInt = Array.ofSeq {1..10} + let resultInt = Array.ofSeq (seq {1..10}) if resultInt <> [|1..10|] then Assert.Fail() // string array diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule.fs index 9f3ae062d02..8b0fcf507e5 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule.fs @@ -346,8 +346,8 @@ type ListModule() = [] member _.Except() = // integer list - let intList1 = [ yield! {1..100} - yield! {1..100} ] + let intList1 = [ yield! seq {1..100} + yield! seq {1..100} ] let intList2 = [1..10] let expectedIntList = [11..100] diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule2.fs index 328574bdac0..3a27d4e7d2a 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule2.fs @@ -367,7 +367,7 @@ type ListModule02() = [] member this.Of_Seq() = // integer List - let resultInt = List.ofSeq {1..10} + let resultInt = List.ofSeq (seq {1..10}) Assert.AreEqual([1..10], resultInt) // string List diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ObsoleteSeqFunctions.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ObsoleteSeqFunctions.fs index 3b8727fc538..67c5aeba747 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ObsoleteSeqFunctions.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ObsoleteSeqFunctions.fs @@ -15,14 +15,14 @@ type ObsoleteSeqFunctions() = // Negative index for i = -1 downto -10 do - CheckThrowsArgumentException (fun () -> Seq.nth i { 10 .. 20 } |> ignore) + CheckThrowsArgumentException (fun () -> Seq.nth i (seq { 10 .. 20 }) |> ignore) // Out of range for i = 11 to 20 do - CheckThrowsArgumentException (fun () -> Seq.nth i { 10 .. 20 } |> ignore) + CheckThrowsArgumentException (fun () -> Seq.nth i (seq { 10 .. 20 }) |> ignore) // integer Seq - let resultInt = Seq.nth 3 { 10..20 } + let resultInt = Seq.nth 3 (seq { 10..20 }) Assert.AreEqual(13, resultInt) // string Seq diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs index de6f66dd7ec..f2f88933506 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs @@ -39,8 +39,8 @@ type SeqModule() = // empty Seq VerifySeqsEqual Seq.empty <| Seq.allPairs Seq.empty Seq.empty - VerifySeqsEqual Seq.empty <| Seq.allPairs { 1..7 } Seq.empty - VerifySeqsEqual Seq.empty <| Seq.allPairs Seq.empty { 1..7 } + VerifySeqsEqual Seq.empty <| Seq.allPairs (seq { 1..7 }) Seq.empty + VerifySeqsEqual Seq.empty <| Seq.allPairs Seq.empty (seq { 1..7 }) // null Seq CheckThrowsArgumentNullException(fun() -> Seq.allPairs null null |> ignore) @@ -349,9 +349,9 @@ type SeqModule() = |> Seq.iter ((<||) VerifySeqsEqual) // int Seq - verify [[1..4];[5..8]] <| Seq.chunkBySize 4 {1..8} - verify [[1..4];[5..8];[9..10]] <| Seq.chunkBySize 4 {1..10} - verify [[1]; [2]; [3]; [4]] <| Seq.chunkBySize 1 {1..4} + verify [[1..4];[5..8]] <| Seq.chunkBySize 4 (seq {1..8}) + verify [[1..4];[5..8];[9..10]] <| Seq.chunkBySize 4 (seq {1..10}) + verify [[1]; [2]; [3]; [4]] <| Seq.chunkBySize 1 (seq {1..4}) Seq.chunkBySize 2 (Seq.initInfinite id) |> Seq.take 3 @@ -372,8 +372,8 @@ type SeqModule() = CheckThrowsArgumentNullException (fun () -> Seq.chunkBySize 3 nullSeq |> ignore) // invalidArg - CheckThrowsArgumentException (fun () -> Seq.chunkBySize 0 {1..10} |> ignore) - CheckThrowsArgumentException (fun () -> Seq.chunkBySize -1 {1..10} |> ignore) + CheckThrowsArgumentException (fun () -> Seq.chunkBySize 0 (seq {1..10}) |> ignore) + CheckThrowsArgumentException (fun () -> Seq.chunkBySize -1 (seq {1..10}) |> ignore) () @@ -385,12 +385,12 @@ type SeqModule() = |> Seq.iter ((<||) VerifySeqsEqual) // int Seq - Seq.splitInto 3 {1..10} |> verify (seq [ {1..4}; {5..7}; {8..10} ]) - Seq.splitInto 3 {1..11} |> verify (seq [ {1..4}; {5..8}; {9..11} ]) - Seq.splitInto 3 {1..12} |> verify (seq [ {1..4}; {5..8}; {9..12} ]) + Seq.splitInto 3 (seq {1..10}) |> verify (seq [ seq {1..4}; seq {5..7}; seq {8..10} ]) + Seq.splitInto 3 (seq {1..11}) |> verify (seq [ seq {1..4}; seq {5..8}; seq {9..11} ]) + Seq.splitInto 3 (seq {1..12}) |> verify (seq [ seq {1..4}; seq {5..8}; seq {9..12} ]) - Seq.splitInto 4 {1..5} |> verify (seq [ [1..2]; [3]; [4]; [5] ]) - Seq.splitInto 20 {1..4} |> verify (seq [ [1]; [2]; [3]; [4] ]) + Seq.splitInto 4 (seq {1..5}) |> verify (seq [ [1..2]; [3]; [4]; [5] ]) + Seq.splitInto 20 (seq {1..4}) |> verify (seq [ [1]; [2]; [3]; [4] ]) // string Seq Seq.splitInto 3 ["a";"b";"c";"d";"e"] |> verify ([ ["a"; "b"]; ["c";"d"]; ["e"] ]) @@ -586,10 +586,10 @@ type SeqModule() = [] member _.Except() = // integer Seq - let intSeq1 = seq { yield! {1..100} - yield! {1..100} } - let intSeq2 = {1..10} - let expectedIntSeq = {11..100} + let intSeq1 = seq { yield! seq {1..100} + yield! seq {1..100} } + let intSeq2 = seq {1..10} + let expectedIntSeq = seq {11..100} VerifySeqsEqual expectedIntSeq <| Seq.except intSeq2 intSeq1 @@ -609,7 +609,7 @@ type SeqModule() = // empty Seq let emptyIntSeq = Seq.empty - VerifySeqsEqual {1..100} <| Seq.except emptyIntSeq intSeq1 + VerifySeqsEqual (seq {1..100}) <| Seq.except emptyIntSeq intSeq1 VerifySeqsEqual emptyIntSeq <| Seq.except intSeq1 emptyIntSeq VerifySeqsEqual emptyIntSeq <| Seq.except emptyIntSeq emptyIntSeq VerifySeqsEqual emptyIntSeq <| Seq.except intSeq1 intSeq1 diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs index 8412b999b5d..db3b8a3adcc 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs @@ -479,7 +479,7 @@ type SeqModule2() = member _.Length() = // integer seq - let resultInt = Seq.length {1..8} + let resultInt = Seq.length (seq {1..8}) if resultInt <> 8 then Assert.Fail() // string Seq @@ -505,7 +505,7 @@ type SeqModule2() = | _ when x % 2 = 0 -> 10*x | _ -> x - let resultInt = Seq.map funcInt { 1..10 } + let resultInt = Seq.map funcInt (seq { 1..10 }) let expectedint = seq [1;20;3;40;5;60;7;80;9;100] VerifySeqsEqual expectedint resultInt @@ -531,7 +531,7 @@ type SeqModule2() = member _.Map2() = // integer Seq let funcInt x y = x+y - let resultInt = Seq.map2 funcInt { 1..10 } {2..2..20} + let resultInt = Seq.map2 funcInt (seq { 1..10 }) (seq {2..2..20}) let expectedint = seq [3;6;9;12;15;18;21;24;27;30] VerifySeqsEqual expectedint resultInt @@ -558,16 +558,16 @@ type SeqModule2() = member _.Map3() = // Integer seq let funcInt a b c = (a + b) * c - let resultInt = Seq.map3 funcInt { 1..8 } { 2..9 } { 3..10 } + let resultInt = Seq.map3 funcInt (seq { 1..8 }) (seq { 2..9 }) (seq { 3..10 }) let expectedInt = seq [9; 20; 35; 54; 77; 104; 135; 170] VerifySeqsEqual expectedInt resultInt // First seq is shorter - VerifySeqsEqual (seq [9; 20]) (Seq.map3 funcInt { 1..2 } { 2..9 } { 3..10 }) + VerifySeqsEqual (seq [9; 20]) (Seq.map3 funcInt (seq { 1..2 }) (seq { 2..9 }) (seq { 3..10 })) // Second seq is shorter - VerifySeqsEqual (seq [9; 20; 35]) (Seq.map3 funcInt { 1..8 } { 2..4 } { 3..10 }) + VerifySeqsEqual (seq [9; 20; 35]) (Seq.map3 funcInt (seq { 1..8 }) (seq { 2..4 }) (seq { 3..10 })) // Third seq is shorter - VerifySeqsEqual (seq [9; 20; 35; 54]) (Seq.map3 funcInt { 1..8 } { 2..6 } { 3..6 }) + VerifySeqsEqual (seq [9; 20; 35; 54]) (Seq.map3 funcInt (seq { 1..8 }) (seq { 2..6 }) (seq { 3..6 })) // String seq let funcStr a b c = a + b + c @@ -812,7 +812,7 @@ type SeqModule2() = member _.Collect() = // integer Seq let funcInt x = seq [x+1] - let resultInt = Seq.collect funcInt { 1..10 } + let resultInt = Seq.collect funcInt (seq { 1..10 }) let expectedint = seq {2..11} @@ -843,7 +843,7 @@ type SeqModule2() = // integer Seq let funcInt x y = x+y - let resultInt = Seq.mapi funcInt { 10..2..20 } + let resultInt = Seq.mapi funcInt (seq { 10..2..20 }) let expectedint = seq [10;13;16;19;22;25] VerifySeqsEqual expectedint resultInt @@ -871,7 +871,7 @@ type SeqModule2() = member _.Mapi2() = // integer Seq let funcInt x y z = x+y+z - let resultInt = Seq.mapi2 funcInt { 1..10 } {2..2..20} + let resultInt = Seq.mapi2 funcInt (seq { 1..10 }) (seq {2..2..20}) let expectedint = seq [3;7;11;15;19;23;27;31;35;39] VerifySeqsEqual expectedint resultInt @@ -907,7 +907,7 @@ type SeqModule2() = member _.Indexed() = // integer Seq - let resultInt = Seq.indexed { 10..2..20 } + let resultInt = Seq.indexed (seq { 10..2..20 }) let expectedint = seq [(0,10);(1,12);(2,14);(3,16);(4,18);(5,20)] VerifySeqsEqual expectedint resultInt @@ -931,7 +931,7 @@ type SeqModule2() = [] member _.Max() = // integer Seq - let resultInt = Seq.max { 10..20 } + let resultInt = Seq.max (seq { 10..20 }) Assert.AreEqual(20,resultInt) @@ -954,7 +954,7 @@ type SeqModule2() = // integer Seq let funcInt x = x % 8 - let resultInt = Seq.maxBy funcInt { 2..2..20 } + let resultInt = Seq.maxBy funcInt (seq { 2..2..20 }) Assert.AreEqual(6,resultInt) // string Seq @@ -976,7 +976,7 @@ type SeqModule2() = // integer Seq let funcInt x = x % 8 - let resultInt = Seq.minBy funcInt { 2..2..20 } + let resultInt = Seq.minBy funcInt (seq { 2..2..20 }) Assert.AreEqual(8,resultInt) // string Seq @@ -998,7 +998,7 @@ type SeqModule2() = member _.Min() = // integer Seq - let resultInt = Seq.min { 10..20 } + let resultInt = Seq.min (seq { 10..20 }) Assert.AreEqual(10,resultInt) // string Seq @@ -1017,7 +1017,7 @@ type SeqModule2() = [] member _.Item() = // integer Seq - let resultInt = Seq.item 3 { 10..20 } + let resultInt = Seq.item 3 (seq { 10..20 }) Assert.AreEqual(13, resultInt) // string Seq @@ -1033,11 +1033,11 @@ type SeqModule2() = // Negative index for i = -1 downto -10 do - CheckThrowsArgumentException (fun () -> Seq.item i { 10 .. 20 } |> ignore) + CheckThrowsArgumentException (fun () -> Seq.item i (seq { 10 .. 20 }) |> ignore) // Out of range for i = 11 to 20 do - CheckThrowsArgumentException (fun () -> Seq.item i { 10 .. 20 } |> ignore) + CheckThrowsArgumentException (fun () -> Seq.item i (seq { 10 .. 20 }) |> ignore) [] member _.``item should fail with correct number of missing elements``() = @@ -1057,7 +1057,7 @@ type SeqModule2() = member _.Of_Array() = // integer Seq let resultInt = Seq.ofArray [|1..10|] - let expectedInt = {1..10} + let expectedInt = seq {1..10} VerifySeqsEqual expectedInt resultInt @@ -1076,7 +1076,7 @@ type SeqModule2() = member _.Of_List() = // integer Seq let resultInt = Seq.ofList [1..10] - let expectedInt = {1..10} + let expectedInt = seq {1..10} VerifySeqsEqual expectedInt resultInt @@ -1095,7 +1095,7 @@ type SeqModule2() = [] member _.Pairwise() = // integer Seq - let resultInt = Seq.pairwise {1..3} + let resultInt = Seq.pairwise (seq {1..3}) let expectedInt = seq [1,2;2,3] @@ -1182,7 +1182,7 @@ type SeqModule2() = member _.Scan() = // integer Seq let funcInt x y = x+y - let resultInt = Seq.scan funcInt 9 {1..10} + let resultInt = Seq.scan funcInt 9 (seq {1..10}) let expectedInt = seq [9;10;12;15;19;24;30;37;45;54;64] VerifySeqsEqual expectedInt resultInt @@ -1207,7 +1207,7 @@ type SeqModule2() = member _.ScanBack() = // integer Seq let funcInt x y = x+y - let resultInt = Seq.scanBack funcInt { 1..10 } 9 + let resultInt = Seq.scanBack funcInt (seq { 1..10 }) 9 let expectedInt = seq [64;63;61;58;54;49;43;36;28;19;9] VerifySeqsEqual expectedInt resultInt @@ -1313,7 +1313,7 @@ type SeqModule2() = // integer Seq let resultInt = Seq.sort (seq [1;3;2;4;6;5;7]) - let expectedInt = {1..7} + let expectedInt = seq {1..7} VerifySeqsEqual expectedInt resultInt // string Seq @@ -1960,7 +1960,7 @@ type SeqModule2() = [] member _.tryItem() = // integer Seq - let resultInt = Seq.tryItem 3 { 10..20 } + let resultInt = Seq.tryItem 3 (seq { 10..20 }) Assert.AreEqual(Some(13), resultInt) // string Seq @@ -1976,11 +1976,11 @@ type SeqModule2() = CheckThrowsArgumentNullException (fun () -> Seq.tryItem 3 nullSeq |> ignore) // Negative index - let resultNegativeIndex = Seq.tryItem -1 { 10..20 } + let resultNegativeIndex = Seq.tryItem -1 (seq { 10..20 }) Assert.AreEqual(None, resultNegativeIndex) // Index greater than length - let resultIndexGreater = Seq.tryItem 31 { 10..20 } + let resultIndexGreater = Seq.tryItem 31 (seq { 10..20 }) Assert.AreEqual(None, resultIndexGreater) [] 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.Core.UnitTests/FSharp.Core/PrimTypes.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs index 8e24be62850..68692f65c67 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs @@ -821,7 +821,7 @@ module internal RangeTestsHelpers = enumerator.Current |> ignore let inline exceptions zero one two = - Assert.Throws (typeof, (fun () -> {one .. zero .. two} |> Seq.length |> ignore)) |> ignore + Assert.Throws (typeof, (fun () -> seq {one .. zero .. two} |> Seq.length |> ignore)) |> ignore Assert.Throws (typeof, (fun () -> [one .. zero .. two] |> List.length |> ignore)) |> ignore Assert.Throws (typeof, (fun () -> [|one .. zero .. two|] |> Array.length |> ignore)) |> ignore @@ -831,10 +831,10 @@ module internal RangeTestsHelpers = Assert.Throws (typeof, (fun () -> regressionExceptionAfterEndVariableStepIntegralRange zero two)) |> ignore let inline common (min0, min1, min2, min3) (max0, max1, max2, max3) (zero, one, two, three) = - Assert.AreEqual (seq {yield min0; yield min1; yield min2; yield min3}, {min0 .. min3}) - Assert.AreEqual (seq {min0; min1; min2; min3}, {min0 .. one .. min3}) - Assert.AreEqual (seq {min0; min2}, {min0 .. two .. min3}) - Assert.AreEqual (seq {min0; min3}, {min0 .. three .. min3}) + Assert.AreEqual (seq {yield min0; yield min1; yield min2; yield min3}, seq {min0 .. min3}) + Assert.AreEqual (seq {min0; min1; min2; min3}, seq {min0 .. one .. min3}) + Assert.AreEqual (seq {min0; min2}, seq {min0 .. two .. min3}) + Assert.AreEqual (seq {min0; min3}, seq {min0 .. three .. min3}) Assert.AreEqual ([min0; min1; min2; min3], [min0 .. min3]) Assert.AreEqual ([min0; min1; min2; min3], [min0 .. one .. min3]) @@ -846,10 +846,10 @@ module internal RangeTestsHelpers = Assert.AreEqual ([|min0; min2|], [|min0 .. two .. min3|]) Assert.AreEqual ([|min0; min3|], [|min0 .. three .. min3|]) - Assert.AreEqual (seq {yield max3; yield max2; yield max1; yield max0}, {max3 .. max0}) - Assert.AreEqual (seq {max3; max2; max1; max0}, {max3 .. one .. max0}) - Assert.AreEqual (seq {max3; max1}, {max3 .. two .. max0}) - Assert.AreEqual (seq {max3; max0}, {max3 .. three .. max0}) + Assert.AreEqual (seq {yield max3; yield max2; yield max1; yield max0}, seq {max3 .. max0}) + Assert.AreEqual (seq {max3; max2; max1; max0}, seq {max3 .. one .. max0}) + Assert.AreEqual (seq {max3; max1}, seq {max3 .. two .. max0}) + Assert.AreEqual (seq {max3; max0}, seq {max3 .. three .. max0}) Assert.AreEqual ([max3; max2; max1; max0], [max3 .. max0]) Assert.AreEqual ([max3; max2; max1; max0], [max3 .. one .. max0]) @@ -861,10 +861,10 @@ module internal RangeTestsHelpers = Assert.AreEqual ([|max3; max1|], [|max3 .. two .. max0|]) Assert.AreEqual ([|max3; max0|], [|max3 .. three .. max0|]) - Assert.AreEqual (Seq.empty, {max0 .. min0}) - Assert.AreEqual (Seq.empty, {max0 .. one .. min0}) - Assert.AreEqual (Seq.empty, {max0 .. two .. min0}) - Assert.AreEqual (Seq.empty, {max0 .. three .. min0}) + Assert.AreEqual (Seq.empty, seq {max0 .. min0}) + Assert.AreEqual (Seq.empty, seq {max0 .. one .. min0}) + Assert.AreEqual (Seq.empty, seq {max0 .. two .. min0}) + Assert.AreEqual (Seq.empty, seq {max0 .. three .. min0}) Assert.AreEqual ([], [max0 .. min0]) Assert.AreEqual ([], [max0 .. one .. min0]) @@ -880,8 +880,8 @@ module internal RangeTestsHelpers = // tests for singleStepRangeEnumerator, as it only is used if start and/or end are not the // minimum or maximum of the number range and it is counting by 1s - Assert.AreEqual (seq {min1; min2; min3}, {min1 .. min3}) - Assert.AreEqual (seq {max3; max2; max1}, {max3 .. max1}) + Assert.AreEqual (seq {min1; min2; min3}, seq {min1 .. min3}) + Assert.AreEqual (seq {max3; max2; max1}, seq {max3 .. max1}) Assert.AreEqual ([min1; min2; min3], [min1 .. min3]) Assert.AreEqual ([max3; max2; max1], [max3 .. max1]) @@ -903,10 +903,10 @@ module internal RangeTestsHelpers = common (min0, min1, min2, min3) (max0, max1, max2, max3) (zero, one, two, three) - Assert.AreEqual (seq { min0; min0 + max0; min0 + max0 + max0 }, {min0 .. max0 .. max0}) - Assert.AreEqual (seq { min0; min0 + max1; min0 + max1 + max1 }, {min0 .. max1 .. max0}) - Assert.AreEqual (seq { min0; min0 + max2; min0 + max2 + max2 }, {min0 .. max2 .. max0}) - Assert.AreEqual (seq { min0; min0 + max3; min0 + max3 + max3 }, {min0 .. max3 .. max0}) + Assert.AreEqual (seq { min0; min0 + max0; min0 + max0 + max0 }, seq {min0 .. max0 .. max0}) + Assert.AreEqual (seq { min0; min0 + max1; min0 + max1 + max1 }, seq {min0 .. max1 .. max0}) + Assert.AreEqual (seq { min0; min0 + max2; min0 + max2 + max2 }, seq {min0 .. max2 .. max0}) + Assert.AreEqual (seq { min0; min0 + max3; min0 + max3 + max3 }, seq {min0 .. max3 .. max0}) Assert.AreEqual ([ min0; min0 + max0; min0 + max0 + max0 ], [min0 .. max0 .. max0]) Assert.AreEqual ([ min0; min0 + max1; min0 + max1 + max1 ], [min0 .. max1 .. max0]) @@ -918,9 +918,9 @@ module internal RangeTestsHelpers = Assert.AreEqual ([| min0; min0 + max2; min0 + max2 + max2 |], [|min0 .. max2 .. max0|]) Assert.AreEqual ([| min0; min0 + max3; min0 + max3 + max3 |], [|min0 .. max3 .. max0|]) - Assert.AreEqual (seq {min3; min2; min1; min0}, {min3 .. -one .. min0}) - Assert.AreEqual (seq {min3; min1}, {min3 .. -two .. min0}) - Assert.AreEqual (seq {min3; min0}, {min3 .. -three .. min0}) + Assert.AreEqual (seq {min3; min2; min1; min0}, seq {min3 .. -one .. min0}) + Assert.AreEqual (seq {min3; min1}, seq {min3 .. -two .. min0}) + Assert.AreEqual (seq {min3; min0}, seq {min3 .. -three .. min0}) Assert.AreEqual ([min3; min2; min1; min0], [min3 .. -one .. min0]) Assert.AreEqual ([min3; min1], [min3 .. -two .. min0]) @@ -930,9 +930,9 @@ module internal RangeTestsHelpers = Assert.AreEqual ([|min3; min1|], [|min3 .. -two .. min0|]) Assert.AreEqual ([|min3; min0|], [|min3 .. -three .. min0|]) - Assert.AreEqual (seq {max0; max1; max2; max3}, {max0 .. -one .. max3}) - Assert.AreEqual (seq {max0; max2}, {max0 .. -two .. max3}) - Assert.AreEqual (seq {max0; max3}, {max0 .. -three .. max3}) + Assert.AreEqual (seq {max0; max1; max2; max3}, seq {max0 .. -one .. max3}) + Assert.AreEqual (seq {max0; max2}, seq {max0 .. -two .. max3}) + Assert.AreEqual (seq {max0; max3}, seq {max0 .. -three .. max3}) Assert.AreEqual ([max0; max1; max2; max3], [max0 .. -one .. max3]) Assert.AreEqual ([max0; max2], [max0 .. -two .. max3]) @@ -942,9 +942,9 @@ module internal RangeTestsHelpers = Assert.AreEqual ([|max0; max2|], [|max0 .. -two .. max3|]) Assert.AreEqual ([|max0; max3|], [|max0 .. -three .. max3|]) - Assert.AreEqual (Seq.empty, {min0 .. -one .. max0}) - Assert.AreEqual (Seq.empty, {min0 .. -two .. max0}) - Assert.AreEqual (Seq.empty, {min0 .. -three .. max0}) + Assert.AreEqual (Seq.empty, seq {min0 .. -one .. max0}) + Assert.AreEqual (Seq.empty, seq {min0 .. -two .. max0}) + Assert.AreEqual (Seq.empty, seq {min0 .. -three .. max0}) Assert.AreEqual ([], [min0 .. -one .. max0]) Assert.AreEqual ([], [min0 .. -two .. max0]) @@ -954,10 +954,10 @@ module internal RangeTestsHelpers = Assert.AreEqual ([||], [|min0 .. -two .. max0|]) Assert.AreEqual ([||], [|min0 .. -three .. max0|]) - Assert.AreEqual (seq {max0; max0 + min0}, {max0 .. min0 .. min0}) - Assert.AreEqual (seq {max0; max0 + min1; max0 + min1 + min1 }, {max0 .. min1 .. min0}) - Assert.AreEqual (seq {max0; max0 + min2; max0 + min2 + min2 }, {max0 .. min2 .. min0}) - Assert.AreEqual (seq {max0; max0 + min3; max0 + min3 + min3 }, {max0 .. min3 .. min0}) + Assert.AreEqual (seq {max0; max0 + min0}, seq {max0 .. min0 .. min0}) + Assert.AreEqual (seq {max0; max0 + min1; max0 + min1 + min1 }, seq {max0 .. min1 .. min0}) + Assert.AreEqual (seq {max0; max0 + min2; max0 + min2 + min2 }, seq {max0 .. min2 .. min0}) + Assert.AreEqual (seq {max0; max0 + min3; max0 + min3 + min3 }, seq {max0 .. min3 .. min0}) Assert.AreEqual ([max0; max0 + min0], [max0 .. min0 .. min0]) Assert.AreEqual ([max0; max0 + min1; max0 + min1 + min1 ], [max0 .. min1 .. min0]) @@ -983,10 +983,10 @@ module internal RangeTestsHelpers = common (min0, min1, min2, min3) (max0, max1, max2, max3) (zero, one, two, three) - Assert.AreEqual (seq {yield min0; yield min0 + max0}, {min0 .. max0 .. max0}) - Assert.AreEqual (seq {min0; min0 + max1}, {min0 .. max1 .. max0}) - Assert.AreEqual (seq {min0; min0 + max2}, {min0 .. max2 .. max0}) - Assert.AreEqual (seq {min0; min0 + max3}, {min0 .. max3 .. max0}) + Assert.AreEqual (seq {yield min0; yield min0 + max0}, seq {min0 .. max0 .. max0}) + Assert.AreEqual (seq {min0; min0 + max1}, seq {min0 .. max1 .. max0}) + Assert.AreEqual (seq {min0; min0 + max2}, seq {min0 .. max2 .. max0}) + Assert.AreEqual (seq {min0; min0 + max3}, seq {min0 .. max3 .. max0}) Assert.AreEqual ([min0; min0 + max0], [min0 .. max0 .. max0]) Assert.AreEqual ([min0; min0 + max1], [min0 .. max1 .. max0]) @@ -1064,15 +1064,15 @@ module RangeTests = Assert.AreEqual(256, let mutable c = 0 in for _ in System.SByte.MinValue..1y..System.SByte.MaxValue do c <- c + 1 done; c) Assert.AreEqual(256, let mutable c = 0 in for _ in System.SByte.MaxValue .. -1y .. System.SByte.MinValue do c <- c + 1 done; c) - Assert.AreEqual(allSBytesSeq, {System.SByte.MinValue..System.SByte.MaxValue}) + Assert.AreEqual(allSBytesSeq, seq {System.SByte.MinValue..System.SByte.MaxValue}) Assert.AreEqual(allSBytesList, [System.SByte.MinValue..System.SByte.MaxValue]) Assert.AreEqual(allSBytesArray, [|System.SByte.MinValue..System.SByte.MaxValue|]) - Assert.AreEqual(allSBytesSeq, {System.SByte.MinValue..1y..System.SByte.MaxValue}) + Assert.AreEqual(allSBytesSeq, seq {System.SByte.MinValue..1y..System.SByte.MaxValue}) Assert.AreEqual(allSBytesList, [System.SByte.MinValue..1y..System.SByte.MaxValue]) Assert.AreEqual(allSBytesArray, [|System.SByte.MinValue..1y..System.SByte.MaxValue|]) - Assert.AreEqual(Seq.rev allSBytesSeq, {System.SByte.MaxValue .. -1y .. System.SByte.MinValue}) + Assert.AreEqual(Seq.rev allSBytesSeq, seq {System.SByte.MaxValue .. -1y .. System.SByte.MinValue}) Assert.AreEqual(List.rev allSBytesList, [System.SByte.MaxValue .. -1y .. System.SByte.MinValue]) Assert.AreEqual(Array.rev allSBytesArray, [|System.SByte.MaxValue .. -1y .. System.SByte.MinValue|]) @@ -1083,11 +1083,11 @@ module RangeTests = Assert.AreEqual(256, let mutable c = 0 in for _ in System.Byte.MinValue..System.Byte.MaxValue do c <- c + 1 done; c) Assert.AreEqual(256, let mutable c = 0 in for _ in System.Byte.MinValue..1uy..System.Byte.MaxValue do c <- c + 1 done; c) - Assert.AreEqual(allBytesSeq, {System.Byte.MinValue..System.Byte.MaxValue}) + Assert.AreEqual(allBytesSeq, seq {System.Byte.MinValue..System.Byte.MaxValue}) Assert.AreEqual(allBytesList, [System.Byte.MinValue..System.Byte.MaxValue]) Assert.AreEqual(allBytesArray, [|System.Byte.MinValue..System.Byte.MaxValue|]) - Assert.AreEqual(allBytesSeq, {System.Byte.MinValue..1uy..System.Byte.MaxValue}) + Assert.AreEqual(allBytesSeq, seq {System.Byte.MinValue..1uy..System.Byte.MaxValue}) Assert.AreEqual(allBytesList, [System.Byte.MinValue..1uy..System.Byte.MaxValue]) Assert.AreEqual(allBytesArray, [|System.Byte.MinValue..1uy..System.Byte.MaxValue|]) @@ -1141,15 +1141,15 @@ module RangeTests = Assert.AreEqual(256, let mutable c = 0 in for _ in min0..one..max0 do c <- c + 1 done; c) Assert.AreEqual(256, let mutable c = 0 in for _ in max0 .. -one .. min0 do c <- c + 1 done; c) - Assert.AreEqual(allSBytesSeq, {min0..max0}) + Assert.AreEqual(allSBytesSeq, seq {min0..max0}) Assert.AreEqual(allSBytesList, [min0..max0]) Assert.AreEqual(allSBytesArray, [|min0..max0|]) - Assert.AreEqual(allSBytesSeq, {min0..one..max0}) + Assert.AreEqual(allSBytesSeq, seq {min0..one..max0}) Assert.AreEqual(allSBytesList, [min0..one..max0]) Assert.AreEqual(allSBytesArray, [|min0..one..max0|]) - Assert.AreEqual(Seq.rev allSBytesSeq, {max0 .. -one .. min0}) + Assert.AreEqual(Seq.rev allSBytesSeq, seq {max0 .. -one .. min0}) Assert.AreEqual(List.rev allSBytesList, [max0 .. -one .. min0]) Assert.AreEqual(Array.rev allSBytesArray, [|max0 .. -one .. min0|]) @@ -1160,11 +1160,11 @@ module RangeTests = Assert.AreEqual(256, let mutable c = 0 in for _ in min0..max0 do c <- c + 1 done; c) Assert.AreEqual(256, let mutable c = 0 in for _ in min0..one..max0 do c <- c + 1 done; c) - Assert.AreEqual(allBytesSeq, {min0..max0}) + Assert.AreEqual(allBytesSeq, seq {min0..max0}) Assert.AreEqual(allBytesList, [min0..max0]) Assert.AreEqual(allBytesArray, [|min0..max0|]) - Assert.AreEqual(allBytesSeq, {min0..one..max0}) + Assert.AreEqual(allBytesSeq, seq {min0..one..max0}) Assert.AreEqual(allBytesList, [min0..one..max0]) Assert.AreEqual(allBytesArray, [|min0..one..max0|]) diff --git a/tests/FSharp.Core.UnitTests/TestFrameworkHelpers.fs b/tests/FSharp.Core.UnitTests/TestFrameworkHelpers.fs index d5fe22cc3b3..31a699ae586 100644 --- a/tests/FSharp.Core.UnitTests/TestFrameworkHelpers.fs +++ b/tests/FSharp.Core.UnitTests/TestFrameworkHelpers.fs @@ -72,7 +72,7 @@ module private Impl = let ub = a1.GetUpperBound(0) if lb <> a2.GetLowerBound(0) || ub <> a2.GetUpperBound(0) then false else - {lb..ub} |> Seq.forall(fun i -> equals (a1.GetValue(i)) (a2.GetValue(i))) + seq {lb..ub} |> Seq.forall(fun i -> equals (a1.GetValue(i)) (a2.GetValue(i))) | _ -> Object.Equals(expected, actual) 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/typeProviders/negTests/neg4.bsl b/tests/fsharp/typeProviders/negTests/neg4.bsl index 7f2259377c8..a1ed652c2cc 100644 --- a/tests/fsharp/typeProviders/negTests/neg4.bsl +++ b/tests/fsharp/typeProviders/negTests/neg4.bsl @@ -17,12 +17,12 @@ neg4.fsx(30,5,30,22): typecheck error FS3062: This type test with a provided typ neg4.fsx(36,5,36,28): typecheck error FS3060: This type test or downcast will erase the provided type 'HelloWorldType' to the type 'System.Object' -neg4.fsx(42,8,42,33): typecheck error FS3063: Cannot inherit from erased provided type +neg4.fsx(42,16,42,33): typecheck error FS3063: Cannot inherit from erased provided type -neg4.fsx(42,8,42,33): typecheck error FS3063: Cannot inherit from erased provided type +neg4.fsx(42,16,42,33): typecheck error FS3063: Cannot inherit from erased provided type -neg4.fsx(47,8,47,35): typecheck error FS3063: Cannot inherit from erased provided type +neg4.fsx(47,16,47,33): typecheck error FS3063: Cannot inherit from erased provided type -neg4.fsx(47,8,47,35): typecheck error FS3063: Cannot inherit from erased provided type +neg4.fsx(47,16,47,33): typecheck error FS3063: Cannot inherit from erased provided type neg4.fsx(52,25,52,42): typecheck error FS3063: Cannot inherit from erased provided type diff --git a/tests/fsharp/typeProviders/negTests/neg6.bsl b/tests/fsharp/typeProviders/negTests/neg6.bsl index 985dd483213..08c6c3166fa 100644 --- a/tests/fsharp/typeProviders/negTests/neg6.bsl +++ b/tests/fsharp/typeProviders/negTests/neg6.bsl @@ -1,12 +1,12 @@ -neg6.fsx(8,3,8,27): typecheck error FS3063: Cannot inherit from erased provided type +neg6.fsx(8,11,8,25): typecheck error FS3063: Cannot inherit from erased provided type -neg6.fsx(8,3,8,27): typecheck error FS3063: Cannot inherit from erased provided type +neg6.fsx(8,11,8,25): typecheck error FS3063: Cannot inherit from erased provided type -neg6.fsx(11,3,11,30): typecheck error FS3063: Cannot inherit from erased provided type +neg6.fsx(11,11,11,28): typecheck error FS3063: Cannot inherit from erased provided type -neg6.fsx(11,3,11,30): typecheck error FS3063: Cannot inherit from erased provided type +neg6.fsx(11,11,11,28): typecheck error FS3063: Cannot inherit from erased provided type -neg6.fsx(14,3,14,35): typecheck error FS3063: Cannot inherit from erased provided type +neg6.fsx(14,11,14,33): typecheck error FS3063: Cannot inherit from erased provided type -neg6.fsx(14,3,14,35): typecheck error FS3063: Cannot inherit from erased provided type +neg6.fsx(14,11,14,33): typecheck error FS3063: Cannot inherit from erased provided type 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/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_RestrictedSuperTypes.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_RestrictedSuperTypes.fs index 4019069641d..c973c282410 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_RestrictedSuperTypes.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_RestrictedSuperTypes.fs @@ -5,16 +5,16 @@ //The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class //The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class //The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class #light let o1 = { new System.ValueType with member x.ToString() = "" } 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..05074e12def 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs @@ -1,11 +1,11 @@ // #Regression #Conformance #ObjectOrientedTypes #TypeInference // 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 +//Structs, interfaces, enums and delegates cannot inherit from other types +//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 +//Structs, interfaces, enums and delegates cannot inherit from other types +//Cannot inherit from interface type\. Use interface \.\.\. with instead // An interface type TK_I_003 = interface 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/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingSeq.fs b/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingSeq.fs new file mode 100644 index 00000000000..e9a5783bbb2 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingSeq.fs @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor + +open System.Collections.Immutable +open System.Composition +open FSharp.Compiler.Syntax +open FSharp.Compiler.Text +open Microsoft.CodeAnalysis.CodeFixes +open Microsoft.CodeAnalysis.Text +open CancellableTasks + +[] +[] +type internal AddMissingSeqCodeFixProvider() = + inherit CodeFixProvider() + + static let title = SR.AddMissingSeq() + static let fixableDiagnosticIds = ImmutableArray.Create("FS3873", "FS0740") + + override _.FixableDiagnosticIds = fixableDiagnosticIds + override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix this + override this.GetFixAllProvider() = this.RegisterFsharpFixAll() + + interface IFSharpCodeFixProvider with + member _.GetCodeFixIfAppliesAsync context = + cancellableTask { + let! sourceText = context.GetSourceTextAsync() + let! parseFileResults = context.Document.GetFSharpParseResultsAsync(nameof AddMissingSeqCodeFixProvider) + + let getSourceLineStr line = + sourceText.Lines[Line.toZ line].ToString() + + let range = + RoslynHelpers.TextSpanToFSharpRange(context.Document.FilePath, context.Span, sourceText) + + let needsParens = + (range.Start, parseFileResults.ParseTree) + ||> ParsedInput.exists (fun path node -> + match path, node with + | SyntaxNode.SynExpr outer :: _, SyntaxNode.SynExpr(expr & SynExpr.ComputationExpr _) when + expr.Range |> Range.equals range + -> + let seqRange = + range + |> Range.withEnd (Position.mkPos range.Start.Line (range.Start.Column + 3)) + + let inner = + SynExpr.App( + ExprAtomicFlag.NonAtomic, + false, + SynExpr.Ident(Ident(nameof seq, seqRange)), + expr, + Range.unionRanges seqRange expr.Range + ) + + let outer = + match outer with + | SynExpr.App(flag, isInfix, funcExpr, _, outerAppRange) -> + SynExpr.App(flag, isInfix, funcExpr, inner, outerAppRange) + | outer -> outer + + inner + |> SynExpr.shouldBeParenthesizedInContext getSourceLineStr (SyntaxNode.SynExpr outer :: path) + | _ -> false) + + let text = sourceText.ToString(TextSpan(context.Span.Start, context.Span.Length)) + let newText = if needsParens then $"(seq {text})" else $"seq {text}" + + return + ValueSome + { + Name = CodeFix.AddMissingSeq + Message = title + Changes = [ TextChange(context.Span, newText) ] + } + } diff --git a/vsintegration/src/FSharp.Editor/Common/Constants.fs b/vsintegration/src/FSharp.Editor/Common/Constants.fs index 822af01d16a..24ee22eb433 100644 --- a/vsintegration/src/FSharp.Editor/Common/Constants.fs +++ b/vsintegration/src/FSharp.Editor/Common/Constants.fs @@ -208,3 +208,6 @@ module internal CodeFix = [] let RemoveUnnecessaryParentheses = "RemoveUnnecessaryParentheses" + + [] + let AddMissingSeq = "AddMissingSeq" diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 37bb02d43d2..2ec608dda20 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -141,6 +141,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index 26b96dcc405..fac57e8b469 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -359,6 +359,9 @@ Use live (unsaved) buffers for analysis Remove unnecessary parentheses + + Add missing 'seq' + Remarks: diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index 421cc037111..7f7c1064aad 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -17,6 +17,11 @@ Přidat chybějící parametr člena instance + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Přidejte klíčové slovo new. diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index ff2a415b3a0..4117ecceddc 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -17,6 +17,11 @@ Fehlenden Instanzmemberparameter hinzufügen + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Schlüsselwort "new" hinzufügen diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index 5df84b54acc..729a252061a 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -17,6 +17,11 @@ Agregar parámetro de miembro de instancia que falta + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Agregar "nueva" palabra clave diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index efe15d65037..a49ba5d1a13 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -17,6 +17,11 @@ Ajouter un paramètre de membre d’instance manquant + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Ajouter le mot clé 'new' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index ca32c029946..0f82d483df8 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -17,6 +17,11 @@ Aggiungi parametro membro di istanza mancante + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Aggiungi la parola chiave 'new' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index 44ca609e1cd..71c981ec17c 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -17,6 +17,11 @@ 見つからないインスタンス メンバー パラメーターを追加する + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword 'new' キーワードを追加する diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index 66cfbeed575..776efa37ca0 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -17,6 +17,11 @@ 누락된 인스턴스 멤버 매개 변수 추가 + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword 'new' 키워드 추가 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index 1675887bd6d..d4b1c40cd09 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -17,6 +17,11 @@ Dodaj brakujący parametr składowej wystąpienia + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Dodaj słowo kluczowe „new” diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index f6770d970de..d743e4f549d 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -17,6 +17,11 @@ Adicionar parâmetro de membro de instância ausente + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Adicionar a palavra-chave 'new' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index bc8554237a8..623dbc446f3 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -17,6 +17,11 @@ Добавить отсутствующий параметр экземплярного элемента + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Добавить ключевое слово "new" diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index cf2198ba7d3..d652ca45127 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -17,6 +17,11 @@ Eksik örnek üye parametresini ekleyin + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword 'new' anahtar sözcüğünü ekleme diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index 16a89acc021..e0d31417ab4 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -17,6 +17,11 @@ 添加缺少的实例成员参数 + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword 添加“新”关键字 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index 932d4de3e61..89f6de50bcd 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -17,6 +17,11 @@ 新增缺少的執行個體成員參數 + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword 新增 'new' 關鍵字 diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddMissingSeqTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddMissingSeqTests.fs new file mode 100644 index 00000000000..8a51be6a8fc --- /dev/null +++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddMissingSeqTests.fs @@ -0,0 +1,239 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +module FSharp.Editor.Tests.CodeFixes.AddMissingSeqTests + +open Microsoft.VisualStudio.FSharp.Editor +open Xunit +open CodeFixTestFramework + +let private codeFix = AddMissingSeqCodeFixProvider() + +// This can be changed to Auto when featureDeprecatePlacesWhereSeqCanBeOmitted is out of preview. +let mode = WithOption "--langversion:preview" + +[] +let ``FS3873 — Adds missing seq before { start..finish }`` () = + let code = "let xs = { 1..10 }" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = seq { 1..10 }" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds missing seq before { start..step..finish }`` () = + let code = "let xs = { 1..5..10 }" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = seq { 1..5..10 }" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS0740 — Adds missing seq before { x; y }`` () = + let code = "let xs = { 1; 10 }" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = seq { 1; 10 }" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds missing seq before yield { start..finish }`` () = + let code = "let xs = [| yield { 1..100 } |]" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = [| yield seq { 1..100 } |]" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds missing seq before yield { start..finish } multiline`` () = + let code = + """ +let xs = [| yield seq { 1..100 } + yield { 1..100 } |] +""" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = + """ +let xs = [| yield seq { 1..100 } + yield seq { 1..100 } |] +""" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds parens when needed — app`` () = + let code = "let xs = id { 1..10 }" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = id (seq { 1..10 })" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds parens when needed — app parens`` () = + let code = "let xs = ResizeArray({ 1..10 })" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = ResizeArray(seq { 1..10 })" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds parens when needed — foreach`` () = + let code = "[ for x in { 1..10 } -> x ]" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "[ for x in seq { 1..10 } -> x ]" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds parens when needed — dot`` () = + let code = "let s = { 1..10 }.ToString ()" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let s = (seq { 1..10 }).ToString ()" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS0740 — Adds parens when needed — app`` () = + let code = "let xs = id { 1; 10 }" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = id (seq { 1; 10 })" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS0740 — Adds parens when needed — dot`` () = + let code = "let s = { 1; 10 }.ToString ()" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let s = (seq { 1; 10 }).ToString ()" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds parens when needed — multiline`` () = + let code = + """ +let xs = + id { + 1..10 + } +""" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = + """ +let xs = + id (seq { + 1..10 + }) +""" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS0740 — Adds parens when needed — multiline`` () = + let code = + """ +let xs = + id { + 1; 10 + } +""" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = + """ +let xs = + id (seq { + 1; 10 + }) +""" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj index a180accc43f..738a3e1323c 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj +++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj @@ -72,6 +72,7 @@ +