diff --git a/src/Compiler/Service/FSharpParseFileResults.fs b/src/Compiler/Service/FSharpParseFileResults.fs index 3589c79f0d8..62cd5b5319d 100644 --- a/src/Compiler/Service/FSharpParseFileResults.fs +++ b/src/Compiler/Service/FSharpParseFileResults.fs @@ -412,7 +412,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput, | SynBinding(expr = SynExpr.Lambda _) when skipLambdas -> defaultTraverse binding // Skip manually type-annotated bindings - | SynBinding(returnInfo = Some (SynBindingReturnInfo(typeName = SynType.LongIdent _))) -> defaultTraverse binding + | SynBinding(returnInfo = Some (SynBindingReturnInfo _)) -> defaultTraverse binding // Let binding | SynBinding (trivia = { EqualsRange = Some equalsRange }; range = range) when range.Start = symbolUseStart -> diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 01350198cdd..111f914dd72 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -662,11 +662,13 @@ moduleSpfn: if isRec then raiseParseErrorAt (rhs parseState 3) (FSComp.SR.parsInvalidUseOfRec()) let info = SynComponentInfo($1 @ attribs2, None, [], path, xmlDoc, false, vis, rhs parseState 3) if Option.isSome $2 then errorR(Error(FSComp.SR.parsVisibilityDeclarationsShouldComePriorToIdentifier(), rhs parseState 2)) - let m = (rhs2 parseState 1 4, $5) + let decls, mOptEnd = $5 + let m = (rhs2 parseState 1 4, decls) ||> unionRangeWithListBy (fun (d: SynModuleSigDecl) -> d.Range) |> unionRangeWithXmlDoc xmlDoc + let m = match mOptEnd with | None -> m | Some mEnd -> unionRanges m mEnd let trivia: SynModuleSigDeclNestedModuleTrivia = { ModuleKeyword = Some mModule; EqualsRange = $4 } - SynModuleSigDecl.NestedModule(info, isRec, $5, m, trivia) } + SynModuleSigDecl.NestedModule(info, isRec, decls, m, trivia) } | opt_attributes opt_access moduleIntro error { let mModule, isRec, path, vis, attribs2 = $3 @@ -743,15 +745,17 @@ moduleSpecBlock: /* #light-syntax, with no sig/end or begin/end */ | OBLOCKBEGIN moduleSpfns oblockend - { $2 } + { $2, None } /* #light-syntax, with sig/end or begin/end */ | OBLOCKBEGIN sigOrBegin moduleSpfnsPossiblyEmpty END oblockend - { $3 } + { let mEnd = rhs parseState 4 + $3, Some mEnd } /* non-#light-syntax, with sig/end or begin/end */ | sigOrBegin moduleSpfnsPossiblyEmpty END - { $2 } + { let mEnd = rhs parseState 3 + $2, Some mEnd } tyconSpfnList: diff --git a/src/FSharp.Core/array.fs b/src/FSharp.Core/array.fs index 3d4ffa4474f..21fee099a9e 100644 --- a/src/FSharp.Core/array.fs +++ b/src/FSharp.Core/array.fs @@ -2081,7 +2081,7 @@ module Array = let private maxPartitions = Environment.ProcessorCount // The maximum number of partitions to use let private minChunkSize = 256 // The minimum size of a chunk to be sorted in parallel - let private createPartitionsUpTo maxIdxExclusive (array: 'T[]) = + let private createPartitionsUpToWithMinChunkSize maxIdxExclusive minChunkSize (array: 'T[]) = [| let chunkSize = match maxIdxExclusive with @@ -2098,6 +2098,98 @@ module Array = yield new ArraySegment<'T>(array, offset, maxIdxExclusive - offset) |] + let private createPartitionsUpTo maxIdxExclusive (array: 'T[]) = + createPartitionsUpToWithMinChunkSize maxIdxExclusive minChunkSize array + + (* This function is there also as a support vehicle for other aggregations. + It is public in order to be called from inlined functions, the benefit of inlining call into it is significant *) + [] + let reduceBy (projection: 'T -> 'U) (reduction: 'U -> 'U -> 'U) (array: 'T[]) = + checkNonNull "array" array + + if array.Length = 0 then + invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString + + let chunks = createPartitionsUpToWithMinChunkSize array.Length 2 array // We need at least 2 elements/chunk for 'reduction' + + let chunkResults = + Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked chunks.Length + + Parallel.For( + 0, + chunks.Length, + fun chunkIdx -> + let chunk = chunks[chunkIdx] + let mutable res = projection array[chunk.Offset] + let lastIdx = chunk.Offset + chunk.Count - 1 + + for i = chunk.Offset + 1 to lastIdx do + let projected = projection array[i] + res <- reduction res projected + + chunkResults[chunkIdx] <- res + ) + |> ignore + + let mutable finalResult = chunkResults[0] + + for i = 1 to chunkResults.Length - 1 do + finalResult <- reduction finalResult chunkResults[i] + + finalResult + + [] + let inline reduce ([] reduction) (array: _[]) = + array |> reduceBy id reduction + + let inline vFst struct (a, _) = + a + + let inline vSnd struct (_, b) = + b + + [] + let inline minBy ([] projection) (array: _[]) = + + array + |> reduceBy (fun x -> struct (projection x, x)) (fun a b -> if vFst a < vFst b then a else b) + |> vSnd + + [] + let inline min (array: _[]) = + array |> reduce (fun a b -> if a < b then a else b) + + [] + let inline sumBy ([] projection: 'T -> ^U) (array: 'T[]) : ^U = + if array.Length = 0 then + LanguagePrimitives.GenericZero + else + array |> reduceBy projection Operators.Checked.(+) + + [] + let inline sum (array: ^T[]) : ^T = + array |> sumBy id + + [] + let inline maxBy projection (array: _[]) = + + array + |> reduceBy (fun x -> struct (projection x, x)) (fun a b -> if vFst a > vFst b then a else b) + |> vSnd + + [] + let inline max (array: _[]) = + array |> reduce (fun a b -> if a > b then a else b) + + [] + let inline averageBy ([] projection: 'T -> ^U) (array: 'T[]) : ^U = + let sum = array |> reduceBy projection Operators.Checked.(+) + LanguagePrimitives.DivideByInt sum (array.Length) + + [] + let inline average (array: 'T[]) = + array |> averageBy id + [] let zip (array1: _[]) (array2: _[]) = checkNonNull "array1" array1 diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index ec0d228a365..3cd6996b132 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -3252,6 +3252,301 @@ module Array = [] val tryPick: chooser: ('T -> 'U option) -> array: 'T[] -> 'U option + /// Applies a function to each element of the array in parallel, threading an accumulator argument + /// through the computation for each thread involved in the computation. After processing entire input, results from all threads are reduced together. + /// Raises ArgumentException if the array is empty. + /// The order of processing is not guaranteed. For that reason, the 'reduce' function argument should be commutative. + /// (That is, changing the order of execution must not affect the result) + /// Also, compared to the non-parallel version of Array.reduce, the 'reduce' function may be invoked more times due to the resulting reduction from participating threads. + /// + /// The function to reduce a pair of elements to a single element. + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// Result of the reductions. + /// + /// + /// + /// let inputs = [| 1; 3; 4; 2 |] + /// + /// inputs |> Array.Parallel.reduce (fun a b -> a + b) + /// + /// Evaluates to 1 + 3 + 4 + 2. However, the system could have decided to compute (1+3) and (4+2) first, and then put them together. + /// + + [] + [] + val inline reduce: reduction: ('T -> 'T -> 'T) -> array: 'T[] -> 'T + + /// Applies a projection function to each element of the array in parallel, reducing elements in each thread with a dedicated 'reduction' function. + /// After processing entire input, results from all threads are reduced together. + /// Raises ArgumentException if the array is empty. + /// The order of processing is not guaranteed. For that reason, the 'reduction' function argument should be commutative. + /// (That is, changing the order of execution must not affect the result) + /// + /// The function to project from elements of the input array + /// The function to reduce a pair of projected elements to a single element. + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// The final result of the reductions. + /// + /// + /// + /// let inputs = [| "1"; "3"; "4"; "2" |] + /// + /// inputs |> Array.Parallel.reduceBy (fun x -> int x) (+) + /// + /// Evaluates to 1 + 3 + 4 + 2. However, the system could have decided to compute (1+3) and (4+2) first, and then put them together. + /// + + [] + [] + val reduceBy: projection: ('T -> 'U) -> reduction: ('U -> 'U -> 'U) -> array: 'T[] -> 'U + + /// Returns the greatest of all elements of the array, compared via Operators.max. + /// + /// Throws ArgumentException for empty arrays. + /// + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// The maximum element. + /// + /// + /// + /// let inputs = [| 10; 12; 11 |] + /// + /// inputs |> Array.Parallel.max + /// + /// Evaluates to 12 + /// + /// + /// + /// + /// let inputs: int[]= [| |] + /// + /// inputs |> Array.Parallel.max + /// + /// Throws System.ArgumentException. + /// + [] + [] + val inline max: array: 'T[] -> 'T when 'T: comparison + + /// Returns the greatest of all elements of the array, compared via Operators.max on the function result. + /// + /// Throws ArgumentException for empty arrays. + /// + /// The function to transform the elements into a type supporting comparison. + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// The maximum element. + /// + /// + /// + /// let inputs = [| "aaa"; "b"; "cccc" |] + /// + /// inputs |> Array.Parallel.maxBy (fun s -> s.Length) + /// + /// Evaluates to "cccc" + /// + /// + /// + /// + /// let inputs: string[]= [| |] + /// + /// inputs |> Array.Parallel.maxBy (fun s -> s.Length) + /// + /// Throws System.ArgumentException. + /// + [] + [] + val inline maxBy: projection: ('T -> 'U) -> array: 'T[] -> 'T when 'U: comparison + + /// Returns the smallest of all elements of the array, compared via Operators.min. + /// + /// Throws ArgumentException for empty arrays + /// + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// The minimum element. + /// + /// + /// + /// let inputs = [| 10; 12; 11 |] + /// + /// inputs |> Array.Parallel.min + /// + /// Evaluates to 10 + /// + /// + /// + /// + /// let inputs: int[]= [| |] + /// + /// inputs |> Array.Parallel.min + /// + /// Throws System.ArgumentException. + /// + [] + [] + val inline min: array: 'T[] -> 'T when 'T: comparison + + /// Returns the lowest of all elements of the array, compared via Operators.min on the function result. + /// + /// Throws ArgumentException for empty arrays. + /// + /// The function to transform the elements into a type supporting comparison. + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// The minimum element. + /// + /// + /// + /// let inputs = [| "aaa"; "b"; "cccc" |] + /// + /// inputs |> Array.Parallel.minBy (fun s -> s.Length) + /// + /// Evaluates to "b" + /// + /// + /// + /// + /// let inputs: string[]= [| |] + /// + /// inputs |> Array.Parallel.minBy (fun s -> s.Length) + /// + /// Throws System.ArgumentException. + /// + [] + [] + val inline minBy: projection: ('T -> 'U) -> array: 'T[] -> 'T when 'U: comparison + + /// Returns the sum of the elements in the array. + /// + /// The input array. + /// + /// The resulting sum. + /// + /// Thrown when the input array is null. + /// + /// + /// + /// let input = [| 1; 5; 3; 2 |] + /// + /// input |> Array.Parallel.sum + /// + /// Evaluates to 11. + /// + [] + [] + val inline sum: array: ^T[] -> ^T when ^T: (static member (+): ^T * ^T -> ^T) and ^T: (static member Zero: ^T) + + /// Returns the sum of the results generated by applying the function to each element of the array. + /// + /// The function to transform the array elements into the type to be summed. + /// The input array. + /// + /// The resulting sum. + /// + /// Thrown when the input array is null. + /// + /// + /// + /// let input = [| "aa"; "bbb"; "cc" |] + /// + /// input |> Array.Parallel.sumBy (fun s -> s.Length) + /// + /// Evaluates to 7. + /// + [] + [] + val inline sumBy: + projection: ('T -> ^U) -> array: 'T[] -> ^U + when ^U: (static member (+): ^U * ^U -> ^U) and ^U: (static member Zero: ^U) + + /// Returns the average of the elements in the array. + /// + /// The input array. + /// + /// Thrown when array is empty. + /// Thrown when the input array is null. + /// + /// The average of the elements in the array. + /// + /// + /// + /// [| 1.0; 2.0; 6.0 |] |> Array.Parallel.average + /// + /// Evaluates to 3.0 + /// + /// + /// + /// + /// [| |] |> Array.Parallel.average + /// + /// Throws ArgumentException + /// + [] + [] + val inline average: + array: ^T[] -> ^T + when ^T: (static member (+): ^T * ^T -> ^T) and ^T: (static member DivideByInt: ^T * int -> ^T) + + /// Returns the average of the elements generated by applying the function to each element of the array. + /// + /// The function to transform the array elements before averaging. + /// The input array. + /// + /// Thrown when array is empty. + /// + /// The computed average. + /// + /// Thrown when the input array is null. + /// + /// + /// + /// type Foo = { Bar: float } + /// + /// let input = [| {Bar = 2.0}; {Bar = 4.0} |] + /// + /// input |> Array.Parallel.averageBy (fun foo -> foo.Bar) + /// + /// Evaluates to 3.0 + /// + /// + /// + /// + /// type Foo = { Bar: float } + /// + /// let input : Foo[] = [| |] + /// + /// input |> Array.Parallel.averageBy (fun foo -> foo.Bar) + /// + /// Throws ArgumentException + /// + [] + [] + val inline averageBy: + projection: ('T -> ^U) -> array: 'T[] -> ^U + when ^U: (static member (+): ^U * ^U -> ^U) and ^U: (static member DivideByInt: ^U * int -> ^U) + /// Apply the given function to each element of the array. Return /// the array comprised of the results x for each element where /// the function returns Some(x). diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl index 8d196f405f3..e373ae3440b 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl @@ -48,6 +48,20 @@ Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpO Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T1,T2][] Zip[T1,T2](T1[], T2[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[TKey,T[]][] GroupBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average$W[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MaxBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Max[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Min[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult ReduceBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] MapIndexed[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]], T[]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl index 8e493cc60ad..e314c7263a2 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl @@ -48,6 +48,20 @@ Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpO Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T1,T2][] Zip[T1,T2](T1[], T2[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[TKey,T[]][] GroupBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average$W[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MaxBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Max[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Min[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult ReduceBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] MapIndexed[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]], T[]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl index 2577f674bad..29f826a24ba 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl @@ -48,6 +48,20 @@ Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpO Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T1,T2][] Zip[T1,T2](T1[], T2[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[TKey,T[]][] GroupBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average$W[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MaxBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Max[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Min[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult ReduceBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] MapIndexed[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]], T[]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl index 55ebd5ff7bb..5114bd40b1d 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl @@ -48,6 +48,20 @@ Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpO Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T1,T2][] Zip[T1,T2](T1[], T2[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[TKey,T[]][] GroupBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average$W[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MaxBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Max[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Min[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult ReduceBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] MapIndexed[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]], T[]) 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 a402c396765..ec30e724bbb 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 @@ -443,9 +443,30 @@ type ArrayModule2() = // null array let nullArr = null:string[] CheckThrowsArgumentNullException (fun () -> Array.reduce (fun (x:string) (y:string) -> x.Remove(0,y.Length)) nullArr |> ignore) - - () + [] + member this.ParallelReduce() = + let assertSameBehavior reduction arr = + Assert.AreEqual(Array.reduce reduction arr, Array.Parallel.reduce reduction arr) + + [|5;4;3;2;1|] |> assertSameBehavior (fun x y -> x+y) + [|"A"; "B"; "C" ; "D" |] |> assertSameBehavior (fun x y -> if x < y then x else y) + + CheckThrowsArgumentException (fun () -> Array.Parallel.reduce (fun x y -> x/y) [||] |> ignore) + let nullArr = null:string[] + CheckThrowsArgumentNullException (fun () -> Array.Parallel.reduce (fun (x:string) (y:string) -> x.Remove(0,y.Length)) nullArr |> ignore) + + [] + member this.ParallelReduceBy() = + let assertSameBehavior projection reduction arr = + Assert.AreEqual(arr |> Array.map projection |> Array.reduce reduction, Array.Parallel.reduceBy projection reduction arr) + + [|5;4;3;2;1|] |> assertSameBehavior (fun x -> x * 2)(fun x y -> x+y) + [|"ABCD"; "B"; "C" ; "D" |] |> assertSameBehavior (fun x -> x.Length) (Operators.Checked.(+)) + + CheckThrowsArgumentException (fun () -> Array.Parallel.reduceBy id (fun x y -> x/y) [||] |> ignore) + let nullArr = null:string[] + CheckThrowsArgumentNullException (fun () -> Array.Parallel.reduceBy id (fun (x:string) (y:string) -> x.Remove(0,y.Length)) nullArr |> ignore) [] member this.ReduceBack() = @@ -1014,6 +1035,76 @@ type ArrayModule2() = CheckThrowsArgumentNullException (fun () -> Array.sumBy float32 nullArr |> ignore) () + member private _.TestOperation opName (actual:'T) (expected:'T) = + Assert.AreEqual(expected, actual, sprintf "%s: should be %A but is %A" opName expected actual) + + [] + member this.ParallelSum() = + this.TestOperation "sum empty" (Array.Parallel.sum [||]) (0) + this.TestOperation "sum single" (Array.Parallel.sum [|42|]) (42) + this.TestOperation "sum two" (Array.Parallel.sum [|42;-21|]) (21) + this.TestOperation "sum many" (Array.Parallel.sum [|1..1000|]) ((1000*1001) / 2) + this.TestOperation "sum floats" (Array.Parallel.sum [|1.;2.;3.|]) (6.) + this.TestOperation "sum infinity" (Array.Parallel.sum [|1.;2.;infinity;3.|]) (infinity) + this.TestOperation "sum nan" (Array.Parallel.sum [|infinity;nan|] |> Double.IsNaN) (true) + + [] + member this.ParallelSumBy() = + this.TestOperation "sum_by empty" (Array.Parallel.sumBy int [||]) (0) + this.TestOperation "sum_by single" (Array.Parallel.sumBy int [|42|]) (42) + this.TestOperation "sum_by two" (Array.Parallel.sumBy int [|42;-21|]) (21) + this.TestOperation "sum_by many" (Array.Parallel.sumBy int [|1..1000|]) ((1000*1001) / 2) + this.TestOperation "sum_by floats" (Array.Parallel.sumBy float [|1.;2.;3.|]) (6.) + this.TestOperation "sum_by infinity" (Array.Parallel.sumBy float [|1.;2.;infinity;3.|]) (infinity) + this.TestOperation "sum_by abs" (Array.Parallel.sumBy abs [|1; -2; 3; -4|]) (10) + this.TestOperation "sum_by string.Length" (Array.Parallel.sumBy String.length [|"abcd";"efg";"hi";"j";""|]) (10) + + [] + member this.ParallelAverage() = + CheckThrowsArgumentException (fun () -> Array.Parallel.average [||] |> ignore) + this.TestOperation "average of 0" (Array.Parallel.average [|0.|]) (0.) + this.TestOperation "average of single" (Array.Parallel.average [|4.|]) (4.) + this.TestOperation "average of two" (Array.Parallel.average [|4.;6.|]) (5.) + + [] + member this.ParallelAverageBy() = + CheckThrowsArgumentException (fun () -> Array.Parallel.averageBy float [||] |> ignore) + this.TestOperation "average_by of 0" (Array.Parallel.averageBy id [|0.|]) (0.) + this.TestOperation "average_by of single" (Array.Parallel.averageBy id [|4.|]) (4.) + this.TestOperation "average_by of two" (Array.Parallel.averageBy id [|4.;6.|]) (5.) + this.TestOperation "average_by int>float" (Array.Parallel.averageBy float [|0..1000|]) (500.) + this.TestOperation "average_by string.Length" (Array.Parallel.averageBy (String.length >> float) [|"ab";"cdef"|]) (3.) + + [] + member this.ParallelMin() = + CheckThrowsArgumentException (fun () -> Array.Parallel.min [||] |> ignore) + this.TestOperation "min single" (Array.Parallel.min [|42|]) (42) + this.TestOperation "min many" (Array.Parallel.min [|1..100|]) (1) + this.TestOperation "min floats" (Array.Parallel.min [|1.0;-1.0;nan;infinity;-infinity|]) (-infinity) + + [] + member this.ParallelMax() = + CheckThrowsArgumentException (fun () -> Array.Parallel.max [||] |> ignore) + this.TestOperation "max single" (Array.Parallel.max [|42|]) (42) + this.TestOperation "max many" (Array.Parallel.max [|1..100|]) (100) + this.TestOperation "max floats" (Array.Parallel.max [|1.0;-1.0;nan;infinity;-infinity|]) (infinity) + + [] + member this.ParallelMinBy() = + CheckThrowsArgumentException (fun () -> Array.Parallel.minBy string [||] |> ignore) + this.TestOperation "minBy single" (Array.Parallel.minBy string [|42|]) (42) + this.TestOperation "minBy int->string" (Array.Parallel.minBy string [|5..25|]) (10) + this.TestOperation "minBy many" (Array.Parallel.minBy (fun x -> -x) [|1..100|]) (100) + this.TestOperation "minBy floats" (Array.Parallel.minBy (fun x -> 1./float x) [|1..100|]) (100) + + [] + member this.ParallelMaxBy() = + CheckThrowsArgumentException (fun () -> Array.Parallel.maxBy int [||] |> ignore) + this.TestOperation "maxBy single" (Array.Parallel.maxBy string [|42|]) (42) + this.TestOperation "maxBy many" (Array.Parallel.maxBy (fun x -> -x) [|1..100|]) (1) + this.TestOperation "maxBy floats" (Array.Parallel.maxBy (fun x -> 1./float x) [|1..100|]) (1) + + [] member this.Tl() = // integer array diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs index e22e3d019ba..7b0ac00e5db 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs @@ -44,12 +44,15 @@ let ``append is consistent`` () = smallerSizeCheck append smallerSizeCheck append +let inline roundResult res = res |> Result.map (fun (x:float) -> Math.Round(x,8)) + let averageFloat (xs : NormalFloat []) = let xs = xs |> Array.map float - let s = runAndCheckErrorType (fun () -> xs |> Seq.average) - let l = runAndCheckErrorType (fun () -> xs |> List.ofArray |> List.average) - let a = runAndCheckErrorType (fun () -> xs |> Array.average) - consistency "average" s l a + let s = runAndCheckErrorType (fun () -> xs |> Seq.average) |> roundResult + let l = runAndCheckErrorType (fun () -> xs |> List.ofArray |> List.average) |> roundResult + let a = runAndCheckErrorType (fun () -> xs |> Array.average) |> roundResult + let pa = runAndCheckErrorType (fun () -> xs |> Array.Parallel.average) |> roundResult + consistencyIncludingParallel "average" s l a pa [] let ``average is consistent`` () = @@ -58,10 +61,11 @@ let ``average is consistent`` () = let averageBy (xs : float []) f = let xs = xs |> Array.map float let f x = (f x : NormalFloat) |> float - let s = runAndCheckErrorType (fun () -> xs |> Seq.averageBy f) - let l = runAndCheckErrorType (fun () -> xs |> List.ofArray |> List.averageBy f) - let a = runAndCheckErrorType (fun () -> xs |> Array.averageBy f) - consistency "averageBy" s l a + let s = runAndCheckErrorType (fun () -> xs |> Seq.averageBy f) |> roundResult + let l = runAndCheckErrorType (fun () -> xs |> List.ofArray |> List.averageBy f) |> roundResult + let a = runAndCheckErrorType (fun () -> xs |> Array.averageBy f) |> roundResult + let pa = runAndCheckErrorType (fun () -> xs |> Array.Parallel.averageBy f) |> roundResult + consistencyIncludingParallel "averageBy" s l a pa [] @@ -85,7 +89,9 @@ let choose<'a when 'a : equality> (xs : 'a []) f = let s = xs |> Seq.choose f |> Seq.toArray let l = xs |> List.ofArray |> List.choose f |> List.toArray let a = xs |> Array.choose f - consistency "contains" s l a + let pa = xs |> Array.Parallel.choose f + + consistencyIncludingParallel "contains" s l a pa [] let ``choose is consistent`` () = @@ -116,7 +122,8 @@ let collect<'a> (xs : 'a []) f = let s = xs |> Seq.collect f |> Seq.toArray let l = xs |> List.ofArray |> List.collect (fun x -> f x |> List.ofArray) |> List.toArray let a = xs |> Array.collect f - consistency "collect" s l a + let pa = xs |> Array.Parallel.collect f + consistencyIncludingParallel "collect" s l a pa @@ -705,7 +712,8 @@ let max<'a when 'a : comparison> (xs : 'a []) = let s = runAndCheckIfAnyError (fun () -> xs |> Seq.max) let l = runAndCheckIfAnyError (fun () -> xs |> List.ofArray |> List.max) let a = runAndCheckIfAnyError (fun () -> xs |> Array.max) - consistency "max" s l a + let pa = runAndCheckIfAnyError (fun () -> xs |> Array.Parallel.max) + consistencyIncludingParallel "max" s l a pa [] let ``max is consistent`` () = @@ -717,7 +725,8 @@ let maxBy<'a when 'a : comparison> (xs : 'a []) f = let s = runAndCheckIfAnyError (fun () -> xs |> Seq.maxBy f) let l = runAndCheckIfAnyError (fun () -> xs |> List.ofArray |> List.maxBy f) let a = runAndCheckIfAnyError (fun () -> xs |> Array.maxBy f) - consistency "maxBy" s l a + let pa = runAndCheckIfAnyError (fun () -> xs |> Array.Parallel.maxBy f) + consistencyIncludingParallel "maxBy" s l a pa [] let ``maxBy is consistent`` () = @@ -729,7 +738,8 @@ let min<'a when 'a : comparison> (xs : 'a []) = let s = runAndCheckIfAnyError (fun () -> xs |> Seq.min) let l = runAndCheckIfAnyError (fun () -> xs |> List.ofArray |> List.min) let a = runAndCheckIfAnyError (fun () -> xs |> Array.min) - consistency "min" s l a + let pa = runAndCheckIfAnyError (fun () -> xs |> Array.Parallel.min) + consistencyIncludingParallel "min" s l a pa [] let ``min is consistent`` () = @@ -741,7 +751,8 @@ let minBy<'a when 'a : comparison> (xs : 'a []) f = let s = runAndCheckIfAnyError (fun () -> xs |> Seq.minBy f) let l = runAndCheckIfAnyError (fun () -> xs |> List.ofArray |> List.minBy f) let a = runAndCheckIfAnyError (fun () -> xs |> Array.minBy f) - consistency "minBy" s l a + let pa = runAndCheckIfAnyError (fun () -> xs |> Array.Parallel.minBy f) + consistencyIncludingParallel "minBy" s l a pa [] let ``minBy is consistent`` () = @@ -813,8 +824,8 @@ let ``pick is consistent`` () = let reduce<'a when 'a : equality> (xs : 'a []) f = let s = runAndCheckErrorType (fun () -> xs |> Seq.reduce f) let l = runAndCheckErrorType (fun () -> xs |> List.ofArray |> List.reduce f) - let a = runAndCheckErrorType (fun () -> xs |> Array.reduce f) - consistency "reduce" s l a + let a = runAndCheckErrorType (fun () -> xs |> Array.reduce f) + consistency "reduce" s l a [] let ``reduce is consistent`` () = @@ -1004,7 +1015,8 @@ let sum (xs : int []) = let s = run (fun () -> xs |> Seq.sum) let l = run (fun () -> xs |> Array.toList |> List.sum) let a = run (fun () -> xs |> Array.sum) - consistency "sum" s l a + let pa = run (fun () -> xs |> Array.Parallel.sum) + consistencyIncludingParallel "sum" s l a pa [] let ``sum is consistent`` () = @@ -1014,7 +1026,8 @@ let sumBy<'a> (xs : 'a []) (f:'a -> int) = let s = run (fun () -> xs |> Seq.sumBy f) let l = run (fun () -> xs |> Array.toList |> List.sumBy f) let a = run (fun () -> xs |> Array.sumBy f) - consistency "sumBy" s l a + let pa = run (fun () -> xs |> Array.Parallel.sumBy f) + consistencyIncludingParallel "sumBy" s l a pa [] let ``sumBy is consistent`` () = diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListProperties.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListProperties.fs index 53623f11548..00ae357fac6 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListProperties.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListProperties.fs @@ -377,7 +377,7 @@ type ListProperties () = let b = List.tryItem pos xs match a with - | Success a -> b.Value = a + | Ok a -> b.Value = a | _ -> b = None [] @@ -391,7 +391,7 @@ type ListProperties () = let b = List.tryPick f xs match a with - | Success a -> b.Value = a + | Ok a -> b.Value = a | _ -> b = None [] @@ -405,7 +405,7 @@ type ListProperties () = let b = List.tryLast xs match a with - | Success a -> b.Value = a + | Ok a -> b.Value = a | _ -> b = None [] @@ -503,7 +503,7 @@ type ListProperties () = match run (fun () -> xs |> List.indexed |> List.permute permutation) with - | Success s -> + | Ok s -> let originals = s |> List.map fst let rs = s |> List.map snd for o in originals do @@ -718,7 +718,7 @@ type ListProperties () = let a = run (fun () -> xs |> List.findIndex predicate) let b = run (fun () -> xs |> List.rev |> List.findIndexBack predicate) match a,b with - | Success a, Success b -> a = (xs.Length - b - 1) + | Ok a, Ok b -> a = (xs.Length - b - 1) | _ -> a = b [] diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/Utils.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/Utils.fs index 7d55fdcb142..ce2a299a3f1 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/Utils.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/Utils.fs @@ -4,29 +4,24 @@ module FSharp.Core.UnitTests.Collections.Utils open Xunit -type Result<'a> = -| Success of 'a -| Error of string - let run f = try - Success(f()) + Ok(f()) with | exn -> Error(exn.Message) let runAndCheckErrorType f = try - Success(f()) + Ok(f()) with | exn -> Error(exn.GetType().ToString()) let runAndCheckIfAnyError f = try - Success(f()) + Ok(f()) with | exn -> Error("") - let isStable sorted = sorted |> Seq.pairwise |> Seq.forall (fun ((ia, a),(ib, b)) -> if a = b then ia < ib else true) let isSorted sorted = sorted |> Seq.pairwise |> Seq.forall (fun (a,b) -> a <= b) diff --git a/tests/fsharp/core/libtest/test.fsx b/tests/fsharp/core/libtest/test.fsx index e4aa2382cec..27ff143f922 100644 --- a/tests/fsharp/core/libtest/test.fsx +++ b/tests/fsharp/core/libtest/test.fsx @@ -20,7 +20,6 @@ let test s b = else (stderr.WriteLine ("failure: " + s); reportFailure s) - let format_uint64 outc formatc width left_justify add_zeros num_prefix_if_pos (n:uint64) = let _ = match formatc with 'd' | 'i' | 'u' -> 10UL | 'o' -> 8UL | 'x' | 'X'-> 16UL | _ -> failwith "invalid value" in failwith "hello" diff --git a/tests/projects/SelfContained_Trimming_Test/Program.fs b/tests/projects/SelfContained_Trimming_Test/Program.fs index a6005136e07..22de634e776 100644 --- a/tests/projects/SelfContained_Trimming_Test/Program.fs +++ b/tests/projects/SelfContained_Trimming_Test/Program.fs @@ -1,7 +1,8 @@ module Core_printf -open Printf open Microsoft.FSharp.Reflection +open Printf +open System.Collections.Generic let failures = ref [] @@ -11,6 +12,10 @@ let report_failure (s : string) = failures := !failures @ [s] () +let check s e r = + if r <> e then + (stderr.WriteLine ($"\n***** {s}: Expected: '{e}' Results: '{r}' = FAIL\n"); report_failure s) + let test t (s1:Lazy) s2 = let s1 = s1.Force() @@ -9094,10 +9099,39 @@ module PercentAPublicTests = test "test8902" (lazy (sprintf "%A" (IntNumber 10 )).Replace("\n", ";")) """IntNumber 10""" test "test8903" (lazy (sprintf "%A" (DoubleNumber 12.0)).Replace("\n", ";")) """DoubleNumber 12.0""" + let testPercentAOptionChoiceTypes () = + test "test8920" (lazy (sprintf "%A" None).Replace("\n", ";")) "None" + test "test8921" (lazy (sprintf "%A" (Some 1.030m)).Replace("\n", ";")) "Some 1.030M" + test "test8922" (lazy (sprintf "%A" ValueNone).Replace("\n", ";")) "ValueNone" + test "test8923" (lazy (sprintf "%A" (ValueSome 1.030m)).Replace("\n", ";")) "ValueSome 1.030M" + test "test8924" (lazy (sprintf "%A" (Choice1Of2 "Hello")).Replace("\n", ";")) "Choice1Of2 \"Hello\"" + test "test8924" (lazy (sprintf "%A" (Choice1Of2 1.032m)).Replace("\n", ";")) "Choice1Of2 1.032M" + + let testUnit () = + test "test8925" (lazy (sprintf "%A" ()).Replace("\n", ";")) "()" + + let testTupleTypes () = + test "test8930" (lazy (sprintf "%A" (1, 1.020m, "Hello, World!!!!")).Replace("\n", ";")) """(1, 1.020M, "Hello, World!!!!")""" + test "test8931" (lazy (sprintf "%A" struct ( 1, 1.020m, "Hello, World!!!!" )).Replace("\n", ";")) """struct (1, 1.020M, "Hello, World!!!!")""" + + let testCollectionsTypes () = + test "test8940" (lazy (sprintf "%A" [|1;2;3;4;5;6;7;8;9|]).Replace("\n", ";")) "[|1; 2; 3; 4; 5; 6; 7; 8; 9|]" + test "test8941" (lazy (sprintf "%A" [1;2;3;4;5;6;7;8;9]).Replace("\n", ";")) "[1; 2; 3; 4; 5; 6; 7; 8; 9]" + test "test8942" (lazy (sprintf "%A" (seq {1;2;3;4;5;6;7;8;9})).Replace("\n", ";")) "seq [1; 2; 3; 4; ...]" + test "test8943" (lazy (sprintf "%A" [|[|1,2|],[|3,4|]|]).Replace("\n", ";")) "[|([|(1, 2)|], [|(3, 4)|])|]" + test "test8944" (lazy (sprintf "%A" [|[|1;2|];[|3;4|]|]).Replace("\n", ";")) "[|[|1; 2|]; [|3; 4|]|]" + test "test8945" (lazy (sprintf "%A" (dict [(1, "a"); (2, "b"); (3, "c")])).Replace("\n", ";")) "seq [[1, a]; [2, b]; [3, c]]" + test "test8946" (lazy (sprintf "%A" (set [1; 2; 3; 4; 5])).Replace("\n", ";")) "set [1; 2; 3; 4; 5]" + test "test8947" (lazy (sprintf "%A" ([ ("One", 1); ("Two", 2) ] |> Map.ofSeq))) """map [("One", 1); ("Two", 2)]""" + let tests () = testPercentAMyRecord () testPercentAMyAnnonymousRecord () testDiscriminatedUnion () + testPercentAOptionChoiceTypes () + testUnit () + testTupleTypes () + testCollectionsTypes () module PercentAInternalTests = type internal MyInternalRecord = @@ -9123,9 +9157,220 @@ module PercentAInternalTests = testPercentA () testPercentPlusA () +module ClassWithEvents = + + type EventClass () = + let event = new Event () + + [] + member _.Event = event.Publish + + member _.TriggerEvent (arg) = event.Trigger (arg) + + let testWithEventClass () = + test "test9200" ( + lazy ( + let mutable eventstring = "" + let evt = EventClass() + evt.Event.Add(fun arg -> eventstring <- eventstring + $"Event handler: {arg}") + evt.TriggerEvent("Hello World!") + eventstring + )) + """Event handler: Hello World!""" + test "test9201" ( + lazy ( + let mutable eventstring = "" + let evt = EventClass(); + evt.Event.Add(fun arg -> eventstring <- eventstring + $"First handler: {arg}") + evt.Event.Add(fun arg -> eventstring <- eventstring + $" Second handler: {arg}") + evt.TriggerEvent("Hello World!") + eventstring + )) + """First handler: Hello World! Second handler: Hello World!""" + let tests () = + testWithEventClass () + +module SameTestsUsingNonStructuralComparison2 = + open NonStructuralComparison + + do check "test9200" (3 > 1) true + do check "test9201" (3y > 1y) true + do check "test9202" (3uy > 1uy) true + do check "test9203" (3s > 1s) true + do check "test9204" (3us > 1us) true + do check "test9205" (3 > 1) true + do check "test9206" (3u > 1u) true + do check "test9207" (3L > 1L) true + do check "test9208" (3UL > 1UL) true + do check "test9209" (3.14 > 3.1) true + do check "test9210" (3.14f > 3.1f) true + do check "test9211" ("bbb" > "aaa") true + do check "test9212" ("bbb" > "bbb") false + do check "test9213" ("aaa" > "bbb") false + do check "test9214" ('b' > 'a') true + do check "test9215" ('a' > 'b') false + do check "test9216" ('b' > 'b') false + + do check "test9217" (3 >= 3) true + do check "test9218" (3y >= 3y) true + do check "test9219" (3uy >= 3uy) true + do check "test9220" (3s >= 3s) true + do check "test9221" (3us >= 3us) true + do check "test9222" (3 >= 3) true + do check "test9223" (3u >= 3u) true + do check "test9224" (3L >= 3L) true + do check "test9225" (3UL >= 3UL) true + do check "test9226" (3.14 >= 3.1) true + do check "test9227" (3.14f >= 3.1f) true + do check "test9228" (3.14M >= 3.1M) true + do check "test9229" ("bbb" >= "aaa") true + do check "test9230" ("bbb" >= "bbb") true + do check "test9231" ("aaa" >= "bbb") false + do check "test9232" ('b' >= 'a') true + do check "test9233" ('a' >= 'b') false + do check "test9234" ('b' >= 'b') true + + do check "test9235" (3 < 1) false + do check "test9236" (3y < 1y) false + do check "test9237" (3uy < 1uy) false + do check "test9238" (3s < 1s) false + do check "test9239" (3us < 1us) false + do check "test9240" (3 < 1) false + do check "test9241" (3u < 1u) false + do check "test9242" (3L < 1L) false + do check "test9243" (3UL < 1UL) false + do check "test9244" (3.14 < 1.0) false + do check "test9245" (3.14f < 1.0f) false + do check "test9246" (3.14M < 1.0M) false + do check "test9247" ("bbb" < "aaa") false + do check "test9248" ("bbb" < "bbb") false + do check "test9249" ("aaa" < "bbb") true + do check "test9250" ('b' < 'a') false + do check "test9251" ('a' < 'b') true + do check "test9252" ('b' < 'b') false + + do check "test9253" (3 <= 1) false + do check "test9254" (3y <= 1y) false + do check "test9255" (3uy <= 1uy) false + do check "test9256" (3s <= 1s) false + do check "test9257" (3us <= 1us) false + do check "test9258" (3 <= 1) false + do check "test9259" (3u <= 1u) false + do check "test9260" (3L <= 1L) false + do check "test9261" (3UL <= 1UL) false + do check "test9262" (3.14 <= 1.0) false + do check "test9263" (3.14f <= 1.0f) false + do check "test9264" (3.14M <= 1.0M) false + do check "test9265" ("bbb" <= "aaa") false + do check "test9266" ("bbb" <= "bbb") true + do check "test9267" ("aaa" <= "bbb") true + do check "test9268" ('b' <= 'a') false + do check "test9269" ('a' <= 'b') true + do check "test9270" ('b' <= 'b') true + do check "test9271" (3 <= 3) true + do check "test9272" (3y <= 3y) true + do check "test9273" (3uy <= 3uy) true + do check "test9274" (3s <= 3s) true + do check "test9275" (3us <= 3us) true + do check "test9276" (3 <= 3) true + do check "test9277" (3u <= 3u) true + do check "test9278" (3L <= 3L) true + do check "test9279" (3UL <= 3UL) true + do check "test9280" (3.14 <= 3.14) true + do check "test9281" (3.14f <= 3.14f) true + do check "test9282" (3.14M <= 3.14M) true + +module NonStructuralComparisonOverDateTime = + open NonStructuralComparison + let now = System.DateTime.Now + let tom = now.AddDays 1.0 + + do check "test9283" (now = tom) false + do check "test9284" (now <> tom) true + do check "test9285" (now < tom) true + do check "test9286" (now <= now) true + do check "test9287" (now <= tom) true + do check "test9288" (tom > now) true + do check "test9289" (now >= now) true + do check "test9290" (tom >= now) true + do check "test9291" (compare now now) 0 + do check "test9292" (compare now tom) -1 + do check "test9293" (compare tom now) 1 + do check "test9294" (max tom tom) tom + do check "test9295" (max tom now) tom + do check "test9296" (max now tom) tom + do check "test9297" (min tom tom) tom + do check "test9298" (min tom now) now + do check "test9299" (min now tom) now + + do check "test9301" (ComparisonIdentity.NonStructural.Compare (1, 1)) 0 + do check "test9302" (ComparisonIdentity.NonStructural.Compare (0, 1)) -1 + do check "test9303" (ComparisonIdentity.NonStructural.Compare (1, 0)) 1 + do check "test9304" (ComparisonIdentity.NonStructural.Compare (now, now)) 0 + do check "test9305" (ComparisonIdentity.NonStructural.Compare (now, tom)) -1 + do check "test9306" (ComparisonIdentity.NonStructural.Compare (tom, now)) 1 + do check "test9307" (HashIdentity.NonStructural.Equals (now, now)) true + do check "test9308" (HashIdentity.NonStructural.Equals (now, tom)) false + do check "test9309" (HashIdentity.NonStructural.Equals (tom, now)) false + do check "test9310" (HashIdentity.NonStructural.GetHashCode now) (hash now) + do check "test9311" (HashIdentity.NonStructural.GetHashCode tom) (hash tom) + do check "test9312" (HashIdentity.NonStructural.GetHashCode 11) (hash 11) + do check "test9313" (HashIdentity.NonStructural.GetHashCode 11L) (hash 11L) + do check "test9314" (HashIdentity.NonStructural.GetHashCode 11UL) (hash 11UL) + do check "test9315" (HashIdentity.NonStructural.Equals (1, 1)) true + do check "test9316" (HashIdentity.NonStructural.Equals (1, 0)) false + do check "test9317" (HashIdentity.NonStructural.Equals (0, 1)) false + +module NonStructuralComparisonOverTimeSpan = + open NonStructuralComparison + let now = System.TimeSpan.Zero + let tom = System.TimeSpan.FromDays 1.0 + + do check "test9318" (now = tom) false + do check "test9319" (now <> tom) true + do check "test9320" (now < tom) true + do check "test9381" (now <= now) true + do check "test9382" (now <= tom) true + do check "test9383" (tom > now) true + do check "test9384" (now >= now) true + do check "test9385" (tom >= now) true + do check "test9386" (compare now now) 0 + do check "test9387" (compare now tom) -1 + do check "test9388" (compare tom now) 1 + do check "test9389" (max tom tom) tom + do check "test9390" (max tom now) tom + do check "test9391" (max now tom) tom + do check "test9392" (min tom tom) tom + do check "test9393" (min tom now) now + do check "test9394" (min now tom) now + +// Check you can use the operators without opening the module by naming them +module NonStructuralComparisonOverTimeSpanDirect = + let now = System.TimeSpan.Zero + let tom = System.TimeSpan.FromDays 1.0 + + do check "test9395" (NonStructuralComparison.(=) now tom) false + do check "test9396" (NonStructuralComparison.(<>) now tom) true + do check "test9397" (NonStructuralComparison.(<) now tom) true + do check "test9398" (NonStructuralComparison.(<=) now now) true + do check "test9399" (NonStructuralComparison.(>) tom now) true + do check "test9400" (NonStructuralComparison.(>=) now now) true + do check "test9401" (NonStructuralComparison.compare now now) 0 + do check "test9402" (NonStructuralComparison.max tom now) tom + do check "test9403" (NonStructuralComparison.min tom now) now + + do check "test9404" (NonStructuralComparison.hash now) (Operators.hash now) + do check "test9405" (NonStructuralComparison.hash tom) (Operators.hash tom) + do check "test9406" (NonStructuralComparison.hash 11) (Operators.hash 11) + do check "test9407" (NonStructuralComparison.hash 11L) (Operators.hash 11L) + do check "test9408" (NonStructuralComparison.hash 11UL) (Operators.hash 11UL) + + [] let main _ = + testing1() + func0() func1000() func2000() @@ -9135,9 +9380,11 @@ let main _ = func6000() func7000() func8000() + PresenceOfReflectionApi.tests () PercentAPublicTests.tests () PercentAInternalTests.tests () + ClassWithEvents.testWithEventClass () match !failures with | [] -> diff --git a/tests/projects/SelfContained_Trimming_Test/check.ps1 b/tests/projects/SelfContained_Trimming_Test/check.ps1 index c1505120df8..0c959cb1715 100644 --- a/tests/projects/SelfContained_Trimming_Test/check.ps1 +++ b/tests/projects/SelfContained_Trimming_Test/check.ps1 @@ -14,7 +14,7 @@ if (-not ($output -eq $expected)) } # Checking that FSharp.Core binary is of expected size (needs adjustments if test is updated). -$expected_len = 265216 # In bytes +$expected_len = 287744 # In bytes $file = Get-Item .\bin\Release\net7.0\win-x64\publish\FSharp.Core.dll $file_len = $file.Length if (-not ($file_len -eq $expected_len)) diff --git a/tests/service/data/SyntaxTree/NestedModule/NestedModuleWithBeginEndAndDecls.fsi b/tests/service/data/SyntaxTree/NestedModule/NestedModuleWithBeginEndAndDecls.fsi new file mode 100644 index 00000000000..0a647263162 --- /dev/null +++ b/tests/service/data/SyntaxTree/NestedModule/NestedModuleWithBeginEndAndDecls.fsi @@ -0,0 +1,7 @@ +namespace X + +module Y = + begin + val a: int + type B = string + end diff --git a/tests/service/data/SyntaxTree/NestedModule/NestedModuleWithBeginEndAndDecls.fsi.bsl b/tests/service/data/SyntaxTree/NestedModule/NestedModuleWithBeginEndAndDecls.fsi.bsl new file mode 100644 index 00000000000..63876c52c8d --- /dev/null +++ b/tests/service/data/SyntaxTree/NestedModule/NestedModuleWithBeginEndAndDecls.fsi.bsl @@ -0,0 +1,40 @@ +SigFile + (ParsedSigFileInput + ("/root/NestedModule/NestedModuleWithBeginEndAndDecls.fsi", + QualifiedNameOfFile NestedModuleWithBeginEndAndDecls, [], [], + [SynModuleOrNamespaceSig + ([X], false, DeclaredNamespace, + [NestedModule + (SynComponentInfo + ([], None, [], [Y], + PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false, + None, (3,0--3,8)), false, + [Val + (SynValSig + ([], SynIdent (a, None), SynValTyparDecls (None, true), + LongIdent (SynLongIdent ([int], [], [None])), + SynValInfo ([], SynArgInfo ([], false, None)), false, false, + PreXmlDoc ((5,8), FSharp.Compiler.Xml.XmlDocCollector), + None, None, (5,8--5,18), { LeadingKeyword = Val (5,8--5,11) + InlineKeyword = None + WithKeyword = None + EqualsRange = None }), + (5,8--5,18)); + Types + ([SynTypeDefnSig + (SynComponentInfo + ([], None, [], [B], + PreXmlDoc ((6,8), FSharp.Compiler.Xml.XmlDocCollector), + false, None, (6,13--6,14)), + Simple + (TypeAbbrev + (Ok, LongIdent (SynLongIdent ([string], [], [None])), + (6,17--6,23)), (6,17--6,23)), [], (6,13--6,23), + { LeadingKeyword = Type (6,8--6,12) + EqualsRange = Some (6,15--6,16) + WithKeyword = None })], (6,8--6,23))], (3,0--7,7), + { ModuleKeyword = Some (3,0--3,6) + EqualsRange = Some (3,9--3,10) })], PreXmlDocEmpty, [], None, + (1,0--7,7), { LeadingKeyword = Namespace (1,0--1,9) })], + { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/NestedModule/RangeOfBeginEnd.fsi b/tests/service/data/SyntaxTree/NestedModule/RangeOfBeginEnd.fsi new file mode 100644 index 00000000000..ce52cae2fb6 --- /dev/null +++ b/tests/service/data/SyntaxTree/NestedModule/RangeOfBeginEnd.fsi @@ -0,0 +1,4 @@ +namespace X + +module Y = + begin end diff --git a/tests/service/data/SyntaxTree/NestedModule/RangeOfBeginEnd.fsi.bsl b/tests/service/data/SyntaxTree/NestedModule/RangeOfBeginEnd.fsi.bsl new file mode 100644 index 00000000000..33815671eb9 --- /dev/null +++ b/tests/service/data/SyntaxTree/NestedModule/RangeOfBeginEnd.fsi.bsl @@ -0,0 +1,16 @@ +SigFile + (ParsedSigFileInput + ("/root/NestedModule/RangeOfBeginEnd.fsi", + QualifiedNameOfFile RangeOfBeginEnd, [], [], + [SynModuleOrNamespaceSig + ([X], false, DeclaredNamespace, + [NestedModule + (SynComponentInfo + ([], None, [], [Y], + PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false, + None, (3,0--3,8)), false, [], (3,0--4,13), + { ModuleKeyword = Some (3,0--3,6) + EqualsRange = Some (3,9--3,10) })], PreXmlDocEmpty, [], None, + (1,0--4,13), { LeadingKeyword = Namespace (1,0--1,9) })], + { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/vsintegration/src/FSharp.Editor/Hints/InlineParameterNameHints.fs b/vsintegration/src/FSharp.Editor/Hints/InlineParameterNameHints.fs index c4da0889448..35601c2799b 100644 --- a/vsintegration/src/FSharp.Editor/Hints/InlineParameterNameHints.fs +++ b/vsintegration/src/FSharp.Editor/Hints/InlineParameterNameHints.fs @@ -54,6 +54,9 @@ type InlineParameterNameHints(parseResults: FSharpParseFileResults) = >> Seq.map (fun location -> location.ArgumentRange) >> Seq.contains range + let isCustomOperation (symbol: FSharpMemberOrFunctionOrValue) = + symbol.HasAttribute() + let getSourceTextAtRange (sourceText: SourceText) (range: range) = (RoslynHelpers.FSharpRangeToTextSpan(sourceText, range) |> sourceText.GetSubText) .ToString() @@ -65,11 +68,9 @@ type InlineParameterNameHints(parseResults: FSharpParseFileResults) = symbol.DeclaringEntity |> Option.exists (fun entity -> entity.CompiledName <> "Operators") - let isNotCustomOperation = not <| symbol.HasAttribute() - (symbol.IsFunction && isNotBuiltInOperator) // arguably, hints for those would be rather useless || symbol.IsConstructor - || (symbol.IsMethod && isNotCustomOperation) + || symbol.IsMethod else false @@ -100,8 +101,10 @@ type InlineParameterNameHints(parseResults: FSharpParseFileResults) = |> Seq.filter (fun range -> argumentLocations |> (not << isNamedArgument range)) let argumentNames = Seq.map (getSourceTextAtRange sourceText) ranges + let skipped = if symbol |> isCustomOperation then 1 else 0 parameters + |> Seq.skip skipped |> Seq.zip ranges // Seq.zip is important as List.zip requires equal lengths |> Seq.where (snd >> parameterNameExists) |> Seq.zip argumentNames diff --git a/vsintegration/src/FSharp.UIResources/LanguageServicePerformanceOptionControl.xaml b/vsintegration/src/FSharp.UIResources/LanguageServicePerformanceOptionControl.xaml index 4642e2f9c10..eb3573f9879 100644 --- a/vsintegration/src/FSharp.UIResources/LanguageServicePerformanceOptionControl.xaml +++ b/vsintegration/src/FSharp.UIResources/LanguageServicePerformanceOptionControl.xaml @@ -58,9 +58,6 @@ - diff --git a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs index 1708adc1c27..05c26ae57a3 100644 --- a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs +++ b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs @@ -141,15 +141,6 @@ public static string Enable_Live_Buffers { } } - /// - /// Looks up a localized string similar to Enable parallel type checking with signature files. - /// - public static string Enable_Parallel_Checking_With_Signature_Files { - get { - return ResourceManager.GetString("Enable_Parallel_Checking_With_Signature_Files", resourceCulture); - } - } - /// /// Looks up a localized string similar to Enable parallel reference resolution. /// diff --git a/vsintegration/src/FSharp.UIResources/Strings.resx b/vsintegration/src/FSharp.UIResources/Strings.resx index f7f87534ac6..98d089b053b 100644 --- a/vsintegration/src/FSharp.UIResources/Strings.resx +++ b/vsintegration/src/FSharp.UIResources/Strings.resx @@ -219,9 +219,6 @@ Parallelization (requires restart) - - Enable parallel type checking with signature files - Enable parallel reference resolution diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf index 5035800a03b..8d56d2adbdd 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf @@ -52,11 +52,6 @@ Diagnostika - - Enable parallel type checking with signature files - Povolit paralelní kontrolu typů pomocí souborů podpisu - - Enable parallel reference resolution Povolit paralelní referenční rozlišení diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf index 06456adc3b0..8c59250dc20 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf @@ -52,11 +52,6 @@ Diagnose - - Enable parallel type checking with signature files - Parallele Typüberprüfung mit Signaturdateien aktivieren - - Enable parallel reference resolution Parallele Verweisauflösung aktivieren diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf index dea7e11508b..d58237d68ba 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf @@ -52,11 +52,6 @@ Diagnóstico - - Enable parallel type checking with signature files - Habilitar la comprobación de tipos paralelos con archivos de firma - - Enable parallel reference resolution Habilitar resolución de referencias paralelas diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf index e05f8cafa33..b6a62f29963 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf @@ -52,11 +52,6 @@ Diagnostics - - Enable parallel type checking with signature files - Activer la vérification de type parallèle avec les fichiers de signature - - Enable parallel reference resolution Activer la résolution de référence parallèle diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf index 8b44f752de2..68e72796bf1 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf @@ -52,11 +52,6 @@ Diagnostica - - Enable parallel type checking with signature files - Abilitare il controllo dei tipi paralleli con i file di firma - - Enable parallel reference resolution Abilitare risoluzione riferimenti paralleli diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf index c2997864851..074852e1f72 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf @@ -52,11 +52,6 @@ 診断 - - Enable parallel type checking with signature files - 署名ファイルを使用して並列型チェックを有効にする - - Enable parallel reference resolution 並列参照解決を有効にする diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf index 454f8bccd30..0d595fc1801 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf @@ -52,11 +52,6 @@ 진단 - - Enable parallel type checking with signature files - 서명 파일로 병렬 유형 검사 사용 - - Enable parallel reference resolution 병렬 참조 해상도 사용 diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf index 2b3b17e4b62..73b1fb9158c 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf @@ -52,11 +52,6 @@ Diagnostyka - - Enable parallel type checking with signature files - Włącz równoległe sprawdzanie typów za pomocą plików podpisu - - Enable parallel reference resolution Włącz równoległe rozpoznawanie odwołań diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf index 1a70eb3c62f..257b0f3f57a 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf @@ -52,11 +52,6 @@ Diagnóstico - - Enable parallel type checking with signature files - Habilitar a verificação de tipo paralelo com arquivos de assinatura - - Enable parallel reference resolution Habilitar a resolução de referência paralela diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf index bfbddfc12e5..ed978ec293a 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf @@ -52,11 +52,6 @@ Диагностика - - Enable parallel type checking with signature files - Включить параллельную проверку типа с файлами подписей - - Enable parallel reference resolution Включить параллельное разрешение ссылок diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf index 9d099287ea2..c3bc0800f2e 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf @@ -52,11 +52,6 @@ Tanılama - - Enable parallel type checking with signature files - İmza dosyalarıyla paralel tür denetlemeyi etkinleştir - - Enable parallel reference resolution Paralel başvuru çözümlemeyi etkinleştir diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf index 13caff6cc04..4fc3ff63c93 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf @@ -52,11 +52,6 @@ 诊断 - - Enable parallel type checking with signature files - 使用签名文件启用并行类型检查 - - Enable parallel reference resolution 启用并行引用解析 diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf index a14b2c99ee8..c3a520bc23c 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf @@ -52,11 +52,6 @@ 診斷 - - Enable parallel type checking with signature files - 啟用簽章檔案的平行類型檢查 - - Enable parallel reference resolution 啟用平行參考解析 diff --git a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineParameterNameHintTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineParameterNameHintTests.fs index 46805aea480..7d58b05bd81 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineParameterNameHintTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineParameterNameHintTests.fs @@ -481,7 +481,7 @@ let test sequences = Assert.Equal(expected, actual) [] - let ``Hints are not shown when CustomOperation attribute is detected`` () = + let ``Hints are shown correctly for custom operations`` () = let code = """ let q = query { for x in { 1 .. 10 } do select x } @@ -489,9 +489,30 @@ let q = query { for x in { 1 .. 10 } do select x } let document = getFsDocument code + let expected = + [ + { + Content = "projection = " + Location = (1, 48) + } + ] + + let actual = getParameterNameHints document + + Assert.Equal(expected, actual) + + [] + let ``Hints are not shown for custom operations with only 1 parameter`` () = + let code = + """ +let q = query { for _ in { 1 .. 10 } do count } +""" + + let document = getFsDocument code + let actual = getParameterNameHints document - Assert.Empty actual + Assert.Empty(actual) [] let ``Hints are not shown when parameter names coincide with variable names`` () = diff --git a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineReturnTypeHintTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineReturnTypeHintTests.fs index 48f838f9e8a..2f419d749be 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineReturnTypeHintTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Hints/InlineReturnTypeHintTests.fs @@ -109,9 +109,11 @@ let ``Hints are not shown for lambda bindings`` () = Assert.Empty result -[] -let ``Hints are not shown when there's type annotation`` () = - let code = "let func x : int = x" +[] +[] +[] +[ = [a]")>] +let ``Hints are not shown when there's type annotation`` code = let document = getFsDocument code