From b9659f41454d32d2ce548938dd9ce80f69f50779 Mon Sep 17 00:00:00 2001 From: Diego Esmerio Date: Sat, 12 May 2018 14:53:17 -0300 Subject: [PATCH 01/17] Remove limitations on custom operation overloads - Check 1:1 by operation/method names instead of count - Remove arg count check (cherry picked from commit 854f080c1fb486e53892894c95cc9351bb04be96) --- src/fsharp/TypeChecker.fs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 27c731b8710..3f433ceee79 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -7667,14 +7667,22 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder let customOperationMethodsIndexedByKeyword = customOperationMethods |> Seq.groupBy (fun (nm, _, _, _, _, _, _, _, _) -> nm) - |> Seq.map (fun (nm, g) -> (nm, Seq.toList g)) + |> Seq.map (fun (nm, g) -> + (nm, + g + |> Seq.distinctBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName) + |> Seq.toList)) |> dict // Check for duplicates by method name (keywords and method names must be 1:1) let customOperationMethodsIndexedByMethodName = customOperationMethods |> Seq.groupBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName) - |> Seq.map (fun (nm, g) -> (nm, Seq.toList g)) + |> Seq.map (fun (nm, g) -> + (nm, + g + |> Seq.distinctBy (fun (nm, _, _, _, _, _, _, _, _) -> nm) + |> Seq.toList)) |> dict @@ -8658,21 +8666,15 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder let maintainsVarSpace = customOperationMaintainsVarSpace nm let maintainsVarSpaceUsingBind = customOperationMaintainsVarSpaceUsingBind nm - let expectedArgCount = expectedArgCountForCustomOperator nm - let dataCompAfterOp = match opExpr with - | StripApps(SingleIdent nm, args) -> - if args.Length = expectedArgCount then - // Check for the [] attribute on each argument position - let args = args |> List.mapi (fun i arg -> - if isCustomOperationProjectionParameter (i+1) nm then - SynExpr.Lambda (false, false, varSpaceSimplePat, arg, arg.Range.MakeSynthetic()) - else arg) - mkSynCall methInfo.DisplayName mClause (dataCompPrior :: args) - else - errorR(Error(FSComp.SR.tcCustomOperationHasIncorrectArgCount(nm.idText, expectedArgCount, args.Length), nm.idRange)) - mkSynCall methInfo.DisplayName mClause ([ dataCompPrior ] @ List.init expectedArgCount (fun i -> arbExpr("_arg" + string i, mClause))) + | StripApps(SingleIdent nm, args) -> + // Check for the [] attribute on each argument position + let args = args |> List.mapi (fun i arg -> + if isCustomOperationProjectionParameter (i+1) nm then + SynExpr.Lambda (false, false, varSpaceSimplePat, arg, arg.Range.MakeSynthetic()) + else arg) + mkSynCall methInfo.DisplayName mClause (dataCompPrior :: args) | _ -> failwith "unreachable" match optionalCont with From 83ca57f999d67d2a003d5fae51b4f1fa02ca506c Mon Sep 17 00:00:00 2001 From: Diego Esmerio Date: Mon, 14 May 2018 23:16:37 -0300 Subject: [PATCH 02/17] Updated baselines (cherry picked from commit 527eb54fc47802ed742c5fd5aa69a9b6a3d22f25) --- tests/fsharp/typecheck/sigs/neg60.bsl | 2 -- tests/fsharp/typecheck/sigs/neg61.bsl | 10 ++++++++-- tests/fsharp/typecheck/sigs/neg87.bsl | 2 -- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/fsharp/typecheck/sigs/neg60.bsl b/tests/fsharp/typecheck/sigs/neg60.bsl index 9e05fc389f2..21e5c3951b0 100644 --- a/tests/fsharp/typecheck/sigs/neg60.bsl +++ b/tests/fsharp/typecheck/sigs/neg60.bsl @@ -55,8 +55,6 @@ neg60.fs(65,19,65,24): typecheck error FS3087: The custom operation 'where' refe neg60.fs(65,19,65,24): typecheck error FS3087: The custom operation 'where' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. -neg60.fs(65,19,65,24): typecheck error FS3087: The custom operation 'where' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. - neg60.fs(65,19,65,38): typecheck error FS0001: This expression was expected to have type 'bool' but here has type diff --git a/tests/fsharp/typecheck/sigs/neg61.bsl b/tests/fsharp/typecheck/sigs/neg61.bsl index 2811c3198e5..accf054328e 100644 --- a/tests/fsharp/typecheck/sigs/neg61.bsl +++ b/tests/fsharp/typecheck/sigs/neg61.bsl @@ -9,7 +9,10 @@ neg61.fs(22,13,22,16): typecheck error FS3145: This is not a known query operato neg61.fs(22,13,22,16): typecheck error FS0039: The value or constructor 'zip' is not defined. -neg61.fs(26,13,26,19): typecheck error FS3099: 'select' is used with an incorrect number of arguments. This is a custom operation in this query or computation expression. Expected 1 argument(s), but given 0. +neg61.fs(25,13,25,28): typecheck error FS0001: This expression was expected to have type + 'Linq.QuerySource<'a,'b> * ('a -> 'c)' +but here has type + 'Linq.QuerySource' neg61.fs(30,13,30,16): typecheck error FS3145: This is not a known query operator. Query operators are identifiers such as 'select', 'where', 'sortBy', 'thenBy', 'groupBy', 'groupValBy', 'join', 'groupJoin', 'sumBy' and 'averageBy', defined using corresponding methods on the 'QueryBuilder' type. @@ -81,7 +84,10 @@ neg61.fs(148,20,148,23): typecheck error FS3147: This 'let' definition may not b neg61.fs(156,21,156,22): typecheck error FS3147: This 'let' definition may not be used in a query. Only simple value definitions may be used in queries. -neg61.fs(171,13,171,18): typecheck error FS3099: 'sumBy' is used with an incorrect number of arguments. This is a custom operation in this query or computation expression. Expected 1 argument(s), but given 0. +neg61.fs(170,13,170,32): typecheck error FS0001: This expression was expected to have type + 'Linq.QuerySource<'a,'b> * ('a -> 'c)' +but here has type + 'Linq.QuerySource' neg61.fs(174,22,174,23): typecheck error FS0041: No overloads match for method 'Source'. diff --git a/tests/fsharp/typecheck/sigs/neg87.bsl b/tests/fsharp/typecheck/sigs/neg87.bsl index 5359647ec21..20e2b49f345 100644 --- a/tests/fsharp/typecheck/sigs/neg87.bsl +++ b/tests/fsharp/typecheck/sigs/neg87.bsl @@ -36,5 +36,3 @@ neg87.fsx(14,5,14,10): typecheck error FS3087: The custom operation 'test2' refe neg87.fsx(14,5,14,10): typecheck error FS3087: The custom operation 'test2' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. neg87.fsx(14,5,14,10): typecheck error FS3087: The custom operation 'test2' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. - -neg87.fsx(14,5,14,10): typecheck error FS3087: The custom operation 'test2' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. From 3ee5a492ecd886793c88236217e5a21f4f1e7b65 Mon Sep 17 00:00:00 2001 From: Diego Esmerio Date: Tue, 22 May 2018 15:37:56 -0300 Subject: [PATCH 03/17] New error messages (cherry picked from commit cdc765d231fa4b3f39681d0d43cdfeba033009b7) --- .../DataExpressions/QueryExpressions/E_BadGroupValBy01.fs | 4 ++-- .../DataExpressions/QueryExpressions/E_BadGroupValBy02.fs | 2 +- .../DataExpressions/QueryExpressions/E_WhitespaceErrors01.fs | 2 +- .../Expressions/DataExpressions/QueryExpressions/env.lst | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy01.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy01.fs index 9e338f91218..9ed2865a7ea 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy01.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy01.fs @@ -1,7 +1,7 @@ // #Conformance #DataExpressions #Query // DevDiv:179889, groupValBy was hard to use with poor diagnostics -//'groupValBy' is used with an incorrect number of arguments\. This is a custom operation in this query or computation expression\. Expected 2 argument\(s\), but given 0\.$ -//'groupValBy' is used with an incorrect number of arguments\. This is a custom operation in this query or computation expression\. Expected 2 argument\(s\), but given 1\.$ +//This expression was expected to have type. 'Linq\.QuerySource\<'a,'b\> \* \('a \-\> 'c\) \* \('a \-\> 'd\)' .but here has type. 'Linq\.QuerySource\' +//The member or object constructor 'GroupValBy' takes 3 argument\(s\) but is here given 2\. The required signature is 'member Linq\.QueryBuilder\.GroupValBy \: source\:Linq\.QuerySource\<'T,'Q\> \* resultSelector\:\('T \-\> 'Value\) \* keySelector\:\('T \-\> 'Key\) \-\> Linq\.QuerySource\,'Q\> when 'Key \: equality'\.$ let q1 = query { diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy02.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy02.fs index bc604c6f5ac..434230874b4 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy02.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy02.fs @@ -1,6 +1,6 @@ // #Conformance #DataExpressions #Query // DevDiv:210830, groupValBy with poor diagnostics -//This expression was expected to have type.+'System\.Linq\.IGrouping<'a,'b>'.+but here has type.+'unit' +//The member or object constructor 'GroupValBy' takes 3 argument\(s\) but is here given 4\. The required signature is 'member Linq\.QueryBuilder\.GroupValBy \: source\:Linq\.QuerySource\<'T,'Q\> \* resultSelector\:\('T \-\> 'Value\) \* keySelector\:\('T \-\> 'Key\) \-\> Linq\.QuerySource\,'Q\> when 'Key \: equality'\. let words = ["blueberry"; "chimpanzee"; ] let wordGroups = diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_WhitespaceErrors01.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_WhitespaceErrors01.fs index efc3d64dbba..a9dd25f5173 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_WhitespaceErrors01.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_WhitespaceErrors01.fs @@ -1,6 +1,6 @@ // #Conformance #DataExpressions #Query // DevDiv:188241, just baselines errors around spacing -//'where' is used with an incorrect number of arguments\. This is a custom operation in this query or computation expression\. Expected 1 argument\(s\), but given 3\.$ +//The member or object constructor 'Where' takes 2 argument\(s\) but is here given 4\. The required signature is 'member Linq\.QueryBuilder\.Where : source:Linq\.QuerySource<'T,'Q> \* predicate:\('T \-> bool\) \-> Linq\.QuerySource<'T,'Q>'\.$ let q1 = // no errors query { diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/env.lst b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/env.lst index 58c79d96417..63cfbf8bd7b 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/env.lst +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/env.lst @@ -13,7 +13,7 @@ NoMT SOURCE=ForWhereJoin01.fs SCFLAGS="--test:ErrorRange NoMT SOURCE=E_WhitespaceErrors01.fs SCFLAGS="--test:ErrorRanges" # E_WhitespaceErrors01.fs NoMT SOURCE=E_WhitespaceErrors02.fs SCFLAGS="--test:ErrorRanges" # E_WhitespaceErrors02.fs NoMT SOURCE=E_WhitespaceErrors03.fs SCFLAGS="--test:ErrorRanges" # E_WhitespaceErrors03.fs -NoMT SOURCE=E_BadGroupValBy01.fs SCFLAGS="--test:ErrorRanges" # E_BadGroupValBy01.fs +NoMT SOURCE=E_BadGroupValBy01.fs SCFLAGS="--test:ErrorRanges --flaterrors" # E_BadGroupValBy01.fs NoMT SOURCE=E_BadGroupValBy02.fs SCFLAGS="--test:ErrorRanges --flaterrors" # E_BadGroupValBy02.fs NoMT SOURCE=E_FirstOrDefaultWithNulls01.fs SCFLAGS="--test:ErrorRanges -r:Utils.dll" # E_FirstOrDefaultWithNulls01.fs From 7f7b4f7c40f996eeb7fdb052ebccff9be8742553 Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Sat, 6 Jun 2020 22:50:48 -0500 Subject: [PATCH 04/17] Add failing tests based on RFC --- tests/fsharp/typecheck/sigs/neg60.fs | 111 +++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/tests/fsharp/typecheck/sigs/neg60.fs b/tests/fsharp/typecheck/sigs/neg60.fs index 15475f55884..57b338bc3c8 100644 --- a/tests/fsharp/typecheck/sigs/neg60.fs +++ b/tests/fsharp/typecheck/sigs/neg60.fs @@ -85,3 +85,114 @@ module NullableOperators3 = let a = new System.Nullable(0) let b = new System.Nullable(1) if a ?=? b then printfn "Same" else printfn "Differerent" + +module QuerySyntaxWithValidOverloading = + + open System + + type Content = ArraySegment list + + type ContentBuilder() = + member this.Run(c: Content) = + let crlf = "\r\n"B + [|for part in c do + yield! part.Array.[part.Offset..part.Count] + yield! crlf |] + + member this.Yield(_) = [] + + [] + member this.Body(c, segment) = + segment::c + + [] + member this.Body(c, bytes, offset, count) = + this.Body(c, ArraySegment(bytes, offset, count)) + + [] + member this.Body(c, bytes: byte[]) = + this.Body(c, bytes, 0, bytes.Length) + + [] + member this.Body(c, text:string) = + let bytes = Text.Encoding.ASCII.GetBytes(text) + this.Body(c, bytes) + + let content = ContentBuilder() + + //--------------------------------------------------------------- + + let values = + content { + body "Name" + body "Email"B + body "Password"B 2 4 + body (ArraySegment("Description"B, 0, 4)) + } + +module QuerySyntaxWithOptionalParamAndParamsArray = + + open System + + type InputKind = + | Text of placeholder:string option + | Password of placeholder: string option + + type InputOptions = + { Label: string option + Kind : InputKind + Validators : (string -> bool) array } + + type InputBuilder() = + + member t.Yield(_) = + { Label = None + Kind = Text None + Validators = [||] } + + [] + member this.Text(io,?placeholder) = + { io with Kind = Text placeholder } + + [] + member this.Password(io,?placeholder) = + { io with Kind = Password placeholder } + + [] + member this.Label(io,label) = + { io with Label = Some label } + + [] + member this.Validators(io, [] validators) = + { io with Validators = validators } + + let input = InputBuilder() + + //--------------------------------------------------------------- + + let name = + input { + label "Name" + text + with_validators + (String.IsNullOrWhiteSpace >> not) + } + + let email = + input { + label "Email" + text "Your email" + with_validators + (String.IsNullOrWhiteSpace >> not) + (fun s -> s.Contains "@") + } + + let password = + input { + label "Password" + password "Must contains at least 6 characters, one number and one uppercase" + with_validators + (String.exists Char.IsUpper) + (String.exists Char.IsDigit) + (fun s -> s.Length >= 6) + } From c6f4e47ca671bccee5f49e006f7447cc339e9f48 Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Sun, 7 Jun 2020 12:29:49 -0500 Subject: [PATCH 05/17] Expand test cases for overloaded CE members --- .../DataExpressions/ComputationExpressions.fs | 102 ++++++++++++++++++ tests/fsharp/typecheck/sigs/neg60.fs | 31 +++--- 2 files changed, 118 insertions(+), 15 deletions(-) diff --git a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs index 9b596c4e9e2..b2fb15188b3 100644 --- a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs +++ b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs @@ -710,3 +710,105 @@ let ceResult = check "grwerjkrwejgk42" ceResult.Value 2 """ + let overloadLib includeInternalExtensions includeExternalExtensions = + """ +open System + +type Content = ArraySegment list + +type ContentBuilder() = + member this.Run(c: Content) = + let crlf = "\r\n"B + [|for part in List.rev c do + yield! part.Array.[part.Offset..(part.Count+part.Offset-1)] + yield! crlf |] + + member this.Yield(_) = [] + + [] + member this.Body(c: Content, segment) = + segment::c + """ + (if includeInternalExtensions then """ + +type ContentBuilder with + [] + member this.Body(c: Content, bytes: byte[], offset, count) = + ArraySegment(bytes, offset, count)::c + """ else """ + + [] + member this.Body(c: Content, bytes: byte[], offset, count) = + ArraySegment(bytes, offset, count)::c + """) + (if includeExternalExtensions then """ + +module Extensions = + type ContentBuilder with + [] + member this.Body(c: Content, [] contents: string[]) = + let rec loop acc (contents: string list) = + match contents with + | [] -> acc + | content::rest -> + let bytes = Text.Encoding.ASCII.GetBytes(content) + loop (this.Body(c, bytes, 0, bytes.Length)) rest + loop c (List.ofArray contents) + """ else """ + + [] + member this.Body(c: Content, [] contents: string[]) = + let rec loop acc (contents: string list) = + match contents with + | [] -> acc + | content::rest -> + let bytes = Text.Encoding.ASCII.GetBytes(content) + loop (this.Body(c, bytes, 0, bytes.Length)) rest + loop c (List.ofArray contents) + """) + """ + +let check msg actual expected = if actual <> expected then failwithf "FAILED %s, expected %A, got %A" msg expected actual + """ + + let OverloadLibTest inclInternalExt inclExternalExt source = + CompilerAssert.CompileExeAndRunWithOptions [| "/langversion:preview" |] (overloadLib inclInternalExt inclExternalExt + source) + + [] + let ``OverloadLib accepts overloaded methods`` () = + OverloadLibTest false false """ +let content = ContentBuilder() +let ceResult = + content { + body "Name" + body (ArraySegment<_>("Email"B, 0, 5)) + body "Password"B 2 4 + body "Description" "of" "content" + } +check "TmFtZVxyXG5FbWF1" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B + """ + + [] + let ``OverloadLib accepts overloaded internal extension methods`` () = + OverloadLibTest true false """ +let content = ContentBuilder() +let ceResult = + content { + body "Name" + body (ArraySegment<_>("Email"B, 0, 5)) + body "Password"B 2 4 + body "Description" "of" "content" + } +check "TmFtZVxyXG5FbWF2" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B + """ + + [] + let ``OverloadLib accepts overloaded internal and external extensions`` () = + OverloadLibTest true true """ +let content = ContentBuilder() +let ceResult = + content { + body "Name" + body (ArraySegment<_>("Email"B, 0, 5)) + body "Password"B 2 4 + body "Description" "of" "content" + } +check "TmFtZVxyXG5FbWF3" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B + """ diff --git a/tests/fsharp/typecheck/sigs/neg60.fs b/tests/fsharp/typecheck/sigs/neg60.fs index 57b338bc3c8..70026402204 100644 --- a/tests/fsharp/typecheck/sigs/neg60.fs +++ b/tests/fsharp/typecheck/sigs/neg60.fs @@ -95,29 +95,30 @@ module QuerySyntaxWithValidOverloading = type ContentBuilder() = member this.Run(c: Content) = let crlf = "\r\n"B - [|for part in c do - yield! part.Array.[part.Offset..part.Count] + [|for part in List.rev c do + yield! part.Array.[part.Offset..(part.Count+part.Offset-1)] yield! crlf |] member this.Yield(_) = [] - + [] - member this.Body(c, segment) = + member this.Body(c: Content, segment: ArraySegment) = segment::c [] - member this.Body(c, bytes, offset, count) = - this.Body(c, ArraySegment(bytes, offset, count)) + member this.Body(c: Content, bytes: byte[], offset, count) = + ArraySegment(bytes, offset, count)::c [] - member this.Body(c, bytes: byte[]) = - this.Body(c, bytes, 0, bytes.Length) + member this.Body(c: Content, [] contents: string[]) = + let rec loop acc (contents: string list) = + match contents with + | [] -> acc + | content::rest -> + let bytes = Text.Encoding.ASCII.GetBytes(content) + loop (this.Body(c, bytes, 0, bytes.Length)) rest + loop c (List.ofArray contents) - [] - member this.Body(c, text:string) = - let bytes = Text.Encoding.ASCII.GetBytes(text) - this.Body(c, bytes) - let content = ContentBuilder() //--------------------------------------------------------------- @@ -125,9 +126,9 @@ module QuerySyntaxWithValidOverloading = let values = content { body "Name" - body "Email"B + body (ArraySegment<_>("Email"B, 0, 5)) body "Password"B 2 4 - body (ArraySegment("Description"B, 0, 4)) + body "Description" "of" "content" } module QuerySyntaxWithOptionalParamAndParamsArray = From 8bda72b3f3bbd4194766a754f01bb63fd46f9398 Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Sun, 26 Jul 2020 22:45:56 -0500 Subject: [PATCH 06/17] open Extensions to fix tests --- .../Conformance/DataExpressions/ComputationExpressions.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs index 6bd5a4e4c84..55bf053fa42 100644 --- a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs +++ b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs @@ -764,6 +764,7 @@ module Extensions = loop (this.Body(c, bytes, 0, bytes.Length)) rest loop c (List.ofArray contents) """) + """ +open Extensions let check msg actual expected = if actual <> expected then failwithf "FAILED %s, expected %A, got %A" msg expected actual """ From 8d31f0f33ff3972cbfdfbfc919b2524f77e3168f Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Sun, 2 Aug 2020 13:58:02 -0500 Subject: [PATCH 07/17] Fix error with opening missing Extensions module --- .../DataExpressions/ComputationExpressions.fs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs index 55bf053fa42..73aa714376f 100644 --- a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs +++ b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs @@ -729,19 +729,19 @@ type ContentBuilder() = member this.Body(c: Content, segment) = segment::c """ + (if includeInternalExtensions then """ - type ContentBuilder with + // internal type extension [] member this.Body(c: Content, bytes: byte[], offset, count) = ArraySegment(bytes, offset, count)::c """ else """ - + // type member [] member this.Body(c: Content, bytes: byte[], offset, count) = ArraySegment(bytes, offset, count)::c """) + (if includeExternalExtensions then """ - module Extensions = + // external type extension type ContentBuilder with [] member this.Body(c: Content, [] contents: string[]) = @@ -752,8 +752,9 @@ module Extensions = let bytes = Text.Encoding.ASCII.GetBytes(content) loop (this.Body(c, bytes, 0, bytes.Length)) rest loop c (List.ofArray contents) +open Extensions """ else """ - + // type member [] member this.Body(c: Content, [] contents: string[]) = let rec loop acc (contents: string list) = @@ -764,7 +765,6 @@ module Extensions = loop (this.Body(c, bytes, 0, bytes.Length)) rest loop c (List.ofArray contents) """) + """ -open Extensions let check msg actual expected = if actual <> expected then failwithf "FAILED %s, expected %A, got %A" msg expected actual """ From 20d9e98aa95d6a98dfff95f89f913b8f9118233f Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Sun, 2 Aug 2020 14:52:52 -0500 Subject: [PATCH 08/17] Fix unit tests --- .../DataExpressions/ComputationExpressions.fs | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs index 73aa714376f..b08db5a401c 100644 --- a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs +++ b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs @@ -745,25 +745,13 @@ module Extensions = type ContentBuilder with [] member this.Body(c: Content, [] contents: string[]) = - let rec loop acc (contents: string list) = - match contents with - | [] -> acc - | content::rest -> - let bytes = Text.Encoding.ASCII.GetBytes(content) - loop (this.Body(c, bytes, 0, bytes.Length)) rest - loop c (List.ofArray contents) + List.rev [for c in contents -> let b = Text.Encoding.ASCII.GetBytes c in ArraySegment<_>(b,0,b.Length)] @ c open Extensions """ else """ // type member [] member this.Body(c: Content, [] contents: string[]) = - let rec loop acc (contents: string list) = - match contents with - | [] -> acc - | content::rest -> - let bytes = Text.Encoding.ASCII.GetBytes(content) - loop (this.Body(c, bytes, 0, bytes.Length)) rest - loop c (List.ofArray contents) + List.rev [for c in contents -> let b = Text.Encoding.ASCII.GetBytes c in ArraySegment<_>(b,0,b.Length)] @ c """) + """ let check msg actual expected = if actual <> expected then failwithf "FAILED %s, expected %A, got %A" msg expected actual @@ -797,7 +785,7 @@ let ceResult = body "Password"B 2 4 body "Description" "of" "content" } -check "TmFtZVxyXG5FbWF2" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B +check "TmFtZVxyXG5FbWF1" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B """ [] @@ -811,5 +799,5 @@ let ceResult = body "Password"B 2 4 body "Description" "of" "content" } -check "TmFtZVxyXG5FbWF3" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B +check "TmFtZVxyXG5FbWF1" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B """ From 87c5de47cca2186daec4405337d7435ba3ca9d0a Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Sun, 2 Aug 2020 20:30:42 -0500 Subject: [PATCH 09/17] Give unique values for each check in CE overload tests --- .../Conformance/DataExpressions/ComputationExpressions.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs index b08db5a401c..13d1667a215 100644 --- a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs +++ b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs @@ -785,7 +785,7 @@ let ceResult = body "Password"B 2 4 body "Description" "of" "content" } -check "TmFtZVxyXG5FbWF1" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B +check "TmFtZVxyXG5FbWF2" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B """ [] @@ -799,5 +799,5 @@ let ceResult = body "Password"B 2 4 body "Description" "of" "content" } -check "TmFtZVxyXG5FbWF1" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B +check "TmFtZVxyXG5FbWF3" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B """ From 67b79e8f6e2a9a2e7dc4485c8dd57564124a5b73 Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Mon, 3 Aug 2020 21:05:18 -0500 Subject: [PATCH 10/17] Add regression scenarios to ensure current functionality does not break for computation expression overloads [FS-1056] --- .../DataExpressions/ComputationExpressions.fs | 51 ++++++++++++++++--- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs index 13d1667a215..5b2c6159b09 100644 --- a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs +++ b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs @@ -726,29 +726,55 @@ type ContentBuilder() = member this.Yield(_) = [] [] - member this.Body(c: Content, segment) = + member this.Body(c: Content, segment: ArraySegment) = segment::c """ + (if includeInternalExtensions then """ + type ContentBuilder with - // internal type extension + // unattributed internal type extension with same arity + member this.Body(c: Content, bytes: byte[]) = + ArraySegment(bytes, 0, bytes.Length)::c + + // internal type extension with different arity [] member this.Body(c: Content, bytes: byte[], offset, count) = ArraySegment(bytes, offset, count)::c """ else """ - // type member + + // unattributed type member with same arity + member this.Body(c: Content, bytes: byte[]) = + ArraySegment(bytes, 0, bytes.Length)::c + + // type member with different arity [] member this.Body(c: Content, bytes: byte[], offset, count) = ArraySegment(bytes, offset, count)::c """) + (if includeExternalExtensions then """ + module Extensions = - // external type extension type ContentBuilder with + // unattributed external type extension with same arity + member this.Body(c: Content, content: System.IO.Stream) = + let mem = new System.IO.MemoryStream() + content.CopyTo(mem) + let bytes = mem.ToArray() + ArraySegment(bytes, 0, bytes.Length)::c + + // external type extensions as ParamArray [] member this.Body(c: Content, [] contents: string[]) = List.rev [for c in contents -> let b = Text.Encoding.ASCII.GetBytes c in ArraySegment<_>(b,0,b.Length)] @ c open Extensions """ else """ - // type member + + // unattributed type member with same arity + member this.Body(c: Content, content: System.IO.Stream) = + let mem = new System.IO.MemoryStream() + content.CopyTo(mem) + let bytes = mem.ToArray() + ArraySegment(bytes, 0, bytes.Length)::c + + // type members [] member this.Body(c: Content, [] contents: string[]) = List.rev [for c in contents -> let b = Text.Encoding.ASCII.GetBytes c in ArraySegment<_>(b,0,b.Length)] @ c @@ -763,41 +789,50 @@ let check msg actual expected = if actual <> expected then failwithf "FAILED %s, [] let ``OverloadLib accepts overloaded methods`` () = OverloadLibTest false false """ +let mem = new System.IO.MemoryStream("Stream"B) let content = ContentBuilder() let ceResult = content { body "Name" body (ArraySegment<_>("Email"B, 0, 5)) body "Password"B 2 4 + body "BYTES"B + body mem body "Description" "of" "content" } -check "TmFtZVxyXG5FbWF1" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B +check "TmFtZVxyXG5FbWF1" ceResult "Name\r\nEmail\r\nsswo\r\nBYTES\r\nStream\r\nDescription\r\nof\r\ncontent\r\n"B """ [] let ``OverloadLib accepts overloaded internal extension methods`` () = OverloadLibTest true false """ +let mem = new System.IO.MemoryStream("Stream"B) let content = ContentBuilder() let ceResult = content { body "Name" body (ArraySegment<_>("Email"B, 0, 5)) body "Password"B 2 4 + body "BYTES"B + body mem body "Description" "of" "content" } -check "TmFtZVxyXG5FbWF2" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B +check "TmFtZVxyXG5FbWF2" ceResult "Name\r\nEmail\r\nsswo\r\nBYTES\r\nStream\r\nDescription\r\nof\r\ncontent\r\n"B """ [] let ``OverloadLib accepts overloaded internal and external extensions`` () = OverloadLibTest true true """ +let mem = new System.IO.MemoryStream("Stream"B) let content = ContentBuilder() let ceResult = content { body "Name" body (ArraySegment<_>("Email"B, 0, 5)) body "Password"B 2 4 + body "BYTES"B + body mem body "Description" "of" "content" } -check "TmFtZVxyXG5FbWF3" ceResult "Name\r\nEmail\r\nsswo\r\nDescription\r\nof\r\ncontent\r\n"B +check "TmFtZVxyXG5FbWF3" ceResult "Name\r\nEmail\r\nsswo\r\nBYTES\r\nStream\r\nDescription\r\nof\r\ncontent\r\n"B """ From 1f48cfd2deab82dbc1a490cde1f7d35e1cdb79b5 Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Tue, 4 Aug 2020 06:45:06 -0500 Subject: [PATCH 11/17] Rename g to group per code review [FS-1056] --- src/fsharp/TypeChecker.fs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 149e008d5e0..6eaee28e862 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -7684,9 +7684,9 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder let customOperationMethodsIndexedByKeyword = customOperationMethods |> Seq.groupBy (fun (nm, _, _, _, _, _, _, _, _) -> nm) - |> Seq.map (fun (nm, g) -> + |> Seq.map (fun (nm, group) -> (nm, - g + group |> Seq.distinctBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName) |> Seq.toList)) |> dict @@ -7695,9 +7695,9 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder let customOperationMethodsIndexedByMethodName = customOperationMethods |> Seq.groupBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName) - |> Seq.map (fun (nm, g) -> + |> Seq.map (fun (nm, group) -> (nm, - g + group |> Seq.distinctBy (fun (nm, _, _, _, _, _, _, _, _) -> nm) |> Seq.toList)) |> dict From 319818c5442bc469b2d5e7e62016db889cec1bec Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Fri, 7 Aug 2020 19:34:50 -0500 Subject: [PATCH 12/17] Hide overloads for custom operations behind feature flag [FS-1056] --- src/fsharp/LanguageFeatures.fs | 2 ++ src/fsharp/LanguageFeatures.fsi | 1 + src/fsharp/TypeChecker.fs | 57 +++++++++++++++++++++------------ 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/fsharp/LanguageFeatures.fs b/src/fsharp/LanguageFeatures.fs index 8c8330ea4d1..6a955350a13 100644 --- a/src/fsharp/LanguageFeatures.fs +++ b/src/fsharp/LanguageFeatures.fs @@ -34,6 +34,7 @@ type LanguageFeature = | WitnessPassing | InterfacesWithMultipleGenericInstantiation | StringInterpolation + | OverloadsForCustomOperations /// LanguageVersion management type LanguageVersion (specifiedVersionAsString) = @@ -73,6 +74,7 @@ type LanguageVersion (specifiedVersionAsString) = LanguageFeature.InterfacesWithMultipleGenericInstantiation, previewVersion LanguageFeature.NameOf, previewVersion LanguageFeature.StringInterpolation, previewVersion + LanguageFeature.OverloadsForCustomOperations, previewVersion ] let specified = diff --git a/src/fsharp/LanguageFeatures.fsi b/src/fsharp/LanguageFeatures.fsi index 95ad370a5e7..2ab1d118074 100644 --- a/src/fsharp/LanguageFeatures.fsi +++ b/src/fsharp/LanguageFeatures.fsi @@ -22,6 +22,7 @@ type LanguageFeature = | WitnessPassing | InterfacesWithMultipleGenericInstantiation | StringInterpolation + | OverloadsForCustomOperations /// LanguageVersion management type LanguageVersion = diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index c2571c41a8e..3a2637e94c0 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -7897,27 +7897,36 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder Some (nm, maintainsVarSpaceUsingBind, maintainsVarSpace, allowInto, isLikeZip, isLikeJoin, isLikeGroupJoin, joinConditionWord, methInfo)) let customOperationMethodsIndexedByKeyword = - customOperationMethods - |> Seq.groupBy (fun (nm, _, _, _, _, _, _, _, _) -> nm) - |> Seq.map (fun (nm, group) -> - (nm, - group - |> Seq.distinctBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName) - |> Seq.toList)) + if cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations then + customOperationMethods + |> Seq.groupBy (fun (nm, _, _, _, _, _, _, _, _) -> nm) + |> Seq.map (fun (nm, group) -> + (nm, + group + |> Seq.distinctBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName) + |> Seq.toList)) + else + customOperationMethods + |> Seq.groupBy (fun (nm, _, _, _, _, _, _, _, _) -> nm) + |> Seq.map (fun (nm, g) -> (nm, Seq.toList g)) |> dict // Check for duplicates by method name (keywords and method names must be 1:1) let customOperationMethodsIndexedByMethodName = - customOperationMethods - |> Seq.groupBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName) - |> Seq.map (fun (nm, group) -> - (nm, - group - |> Seq.distinctBy (fun (nm, _, _, _, _, _, _, _, _) -> nm) - |> Seq.toList)) + if cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations then + customOperationMethods + |> Seq.groupBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName) + |> Seq.map (fun (nm, group) -> + (nm, + group + |> Seq.distinctBy (fun (nm, _, _, _, _, _, _, _, _) -> nm) + |> Seq.toList)) + else + customOperationMethods + |> Seq.groupBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName) + |> Seq.map (fun (nm, g) -> (nm, Seq.toList g)) |> dict - /// Decide if the identifier represents a use of a custom query operator let tryGetDataForCustomOperation (nm: Ident) = match customOperationMethodsIndexedByKeyword.TryGetValue nm.idText with @@ -8899,15 +8908,21 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder let maintainsVarSpace = customOperationMaintainsVarSpace nm let maintainsVarSpaceUsingBind = customOperationMaintainsVarSpaceUsingBind nm + let expectedArgCount = expectedArgCountForCustomOperator nm + let dataCompAfterOp = match opExpr with | StripApps(SingleIdent nm, args) -> - // Check for the [] attribute on each argument position - let args = args |> List.mapi (fun i arg -> - if isCustomOperationProjectionParameter (i+1) nm then - SynExpr.Lambda (false, false, varSpaceSimplePat, arg, arg.Range.MakeSynthetic()) - else arg) - mkSynCall methInfo.DisplayName mClause (dataCompPrior :: args) + if args.Length = expectedArgCount || cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations then + // Check for the [] attribute on each argument position + let args = args |> List.mapi (fun i arg -> + if isCustomOperationProjectionParameter (i+1) nm then + SynExpr.Lambda (false, false, varSpaceSimplePat, arg, arg.Range.MakeSynthetic()) + else arg) + mkSynCall methInfo.DisplayName mClause (dataCompPrior :: args) + else + errorR(Error(FSComp.SR.tcCustomOperationHasIncorrectArgCount(nm.idText, expectedArgCount, args.Length), nm.idRange)) + mkSynCall methInfo.DisplayName mClause ([ dataCompPrior ] @ List.init expectedArgCount (fun i -> arbExpr("_arg" + string i, mClause))) | _ -> failwith "unreachable" match optionalCont with From 86bd25d88e6d7391bf6cea71426496da2a1a002d Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Fri, 7 Aug 2020 20:03:11 -0500 Subject: [PATCH 13/17] Add feature flag to GetFeatureString --- src/fsharp/LanguageFeatures.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fsharp/LanguageFeatures.fs b/src/fsharp/LanguageFeatures.fs index 6a955350a13..d2c8cb63fac 100644 --- a/src/fsharp/LanguageFeatures.fs +++ b/src/fsharp/LanguageFeatures.fs @@ -146,6 +146,7 @@ type LanguageVersion (specifiedVersionAsString) = | LanguageFeature.WitnessPassing -> FSComp.SR.featureWitnessPassing() | LanguageFeature.InterfacesWithMultipleGenericInstantiation -> FSComp.SR.featureInterfacesWithMultipleGenericInstantiation() | LanguageFeature.StringInterpolation -> FSComp.SR.featureStringInterpolation() + | LanguageFeature.OverloadsForCustomOperations -> FSComp.SR.featureOverloadsForCustomOperations() /// Get a version string associated with the given feature. member _.GetFeatureVersionString feature = From e450abd4045b0f321c45cc861bc9c1629bb807df Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Fri, 7 Aug 2020 20:10:11 -0500 Subject: [PATCH 14/17] Add featureOverloadsForCustomOperations to FSComps --- src/fsharp/FSComp.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 2733248bea1..42aa9698518 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1533,4 +1533,5 @@ forFormatInvalidForInterpolated4,"Interpolated strings used as type IFormattable 3380,parsEofInInterpolatedVerbatimString,"Incomplete interpolated verbatim string begun at or before here" 3381,parsEofInInterpolatedTripleQuoteString,"Incomplete interpolated triple-quote string begun at or before here" 3382,lexRBraceInInterpolatedString,"A '}}' character must be escaped (by doubling) in an interpolated string." +featureOverloadsForCustomOperations,"overloads for custom operations" #3501 "This construct is not supported by your version of the F# compiler" CompilerMessage(ExperimentalAttributeMessages.NotSupportedYet, 3501, IsError=true) From f7c115b8f57d87d7a72938fc66a620d87c81386a Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Fri, 7 Aug 2020 20:27:20 -0500 Subject: [PATCH 15/17] Update FSComp.txt [FS-1056] --- src/fsharp/FSComp.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 42aa9698518..44509274360 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1224,6 +1224,7 @@ invalidFullNameForProvidedType,"invalid full name for provided type" 3085,tcCustomOperationMayNotBeUsedInConjunctionWithNonSimpleLetBindings,"A custom operation may not be used in conjunction with a non-value or recursive 'let' binding in another part of this computation expression" 3086,tcCustomOperationMayNotBeUsedHere,"A custom operation may not be used in conjunction with 'use', 'try/with', 'try/finally', 'if/then/else' or 'match' operators within this computation expression" 3087,tcCustomOperationMayNotBeOverloaded,"The custom operation '%s' refers to a method which is overloaded. The implementations of custom operations may not be overloaded." +featureOverloadsForCustomOperations,"overloads for custom operations" 3090,tcIfThenElseMayNotBeUsedWithinQueries,"An if/then/else expression may not be used within queries. Consider using either an if/then expression, or use a sequence expression instead." 3091,ilxgenUnexpectedArgumentToMethodHandleOfDuringCodegen,"Invalid argument to 'methodhandleof' during codegen" 3092,etProvidedTypeReferenceMissingArgument,"A reference to a provided type was missing a value for the static parameter '%s'. You may need to recompile one or more referenced assemblies." @@ -1533,5 +1534,4 @@ forFormatInvalidForInterpolated4,"Interpolated strings used as type IFormattable 3380,parsEofInInterpolatedVerbatimString,"Incomplete interpolated verbatim string begun at or before here" 3381,parsEofInInterpolatedTripleQuoteString,"Incomplete interpolated triple-quote string begun at or before here" 3382,lexRBraceInInterpolatedString,"A '}}' character must be escaped (by doubling) in an interpolated string." -featureOverloadsForCustomOperations,"overloads for custom operations" #3501 "This construct is not supported by your version of the F# compiler" CompilerMessage(ExperimentalAttributeMessages.NotSupportedYet, 3501, IsError=true) From 45214b9fe9c7b2c5a85d41d6fdee4fd92ba7f193 Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Mon, 10 Aug 2020 20:45:38 -0500 Subject: [PATCH 16/17] Update baselines [FS-1056] --- tests/fsharp/typecheck/sigs/neg60.bsl | 82 +++++++++++++++++++++++++++ tests/fsharp/typecheck/sigs/neg61.bsl | 12 +--- tests/fsharp/typecheck/sigs/neg87.bsl | 2 + 3 files changed, 87 insertions(+), 9 deletions(-) diff --git a/tests/fsharp/typecheck/sigs/neg60.bsl b/tests/fsharp/typecheck/sigs/neg60.bsl index 21e5c3951b0..f403c73f293 100644 --- a/tests/fsharp/typecheck/sigs/neg60.bsl +++ b/tests/fsharp/typecheck/sigs/neg60.bsl @@ -55,6 +55,8 @@ neg60.fs(65,19,65,24): typecheck error FS3087: The custom operation 'where' refe neg60.fs(65,19,65,24): typecheck error FS3087: The custom operation 'where' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. +neg60.fs(65,19,65,24): typecheck error FS3087: The custom operation 'where' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + neg60.fs(65,19,65,38): typecheck error FS0001: This expression was expected to have type 'bool' but here has type @@ -77,3 +79,83 @@ neg60.fs(80,19,80,20): typecheck error FS0043: Expecting a type supporting the o neg60.fs(81,22,81,34): typecheck error FS0002: This function takes too many arguments, or is used in a context where a function is not expected neg60.fs(87,10,87,13): typecheck error FS0043: The type 'System.Nullable' does not support the operator '?=?'. Consider opening the module 'Microsoft.FSharp.Linq.NullableOperators'. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(128,9,128,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(129,9,129,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(129,9,129,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(129,9,129,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(129,9,129,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(129,9,129,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(129,9,129,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(130,9,130,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(130,9,130,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(130,9,130,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(130,9,130,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(130,9,130,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(130,9,130,13): typecheck error FS3099: 'body' is used with an incorrect number of arguments. This is a custom operation in this query or computation expression. Expected 1 argument(s), but given 3. + +neg60.fs(131,9,131,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(131,9,131,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(131,9,131,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(131,9,131,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(131,9,131,13): typecheck error FS3087: The custom operation 'body' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg60.fs(131,9,131,13): typecheck error FS3099: 'body' is used with an incorrect number of arguments. This is a custom operation in this query or computation expression. Expected 1 argument(s), but given 3. + +neg60.fs(177,9,177,13): typecheck error FS3099: 'text' is used with an incorrect number of arguments. This is a custom operation in this query or computation expression. Expected 1 argument(s), but given 0. + +neg60.fs(186,9,186,24): typecheck error FS3099: 'with_validators' is used with an incorrect number of arguments. This is a custom operation in this query or computation expression. Expected 1 argument(s), but given 2. + +neg60.fs(195,9,195,24): typecheck error FS3099: 'with_validators' is used with an incorrect number of arguments. This is a custom operation in this query or computation expression. Expected 1 argument(s), but given 3. diff --git a/tests/fsharp/typecheck/sigs/neg61.bsl b/tests/fsharp/typecheck/sigs/neg61.bsl index accf054328e..5b1ecfb7c66 100644 --- a/tests/fsharp/typecheck/sigs/neg61.bsl +++ b/tests/fsharp/typecheck/sigs/neg61.bsl @@ -9,10 +9,7 @@ neg61.fs(22,13,22,16): typecheck error FS3145: This is not a known query operato neg61.fs(22,13,22,16): typecheck error FS0039: The value or constructor 'zip' is not defined. -neg61.fs(25,13,25,28): typecheck error FS0001: This expression was expected to have type - 'Linq.QuerySource<'a,'b> * ('a -> 'c)' -but here has type - 'Linq.QuerySource' +neg61.fs(26,13,26,19): typecheck error FS3099: 'select' is used with an incorrect number of arguments. This is a custom operation in this query or computation expression. Expected 1 argument(s), but given 0. neg61.fs(30,13,30,16): typecheck error FS3145: This is not a known query operator. Query operators are identifiers such as 'select', 'where', 'sortBy', 'thenBy', 'groupBy', 'groupValBy', 'join', 'groupJoin', 'sumBy' and 'averageBy', defined using corresponding methods on the 'QueryBuilder' type. @@ -84,10 +81,7 @@ neg61.fs(148,20,148,23): typecheck error FS3147: This 'let' definition may not b neg61.fs(156,21,156,22): typecheck error FS3147: This 'let' definition may not be used in a query. Only simple value definitions may be used in queries. -neg61.fs(170,13,170,32): typecheck error FS0001: This expression was expected to have type - 'Linq.QuerySource<'a,'b> * ('a -> 'c)' -but here has type - 'Linq.QuerySource' +neg61.fs(171,13,171,18): typecheck error FS3099: 'sumBy' is used with an incorrect number of arguments. This is a custom operation in this query or computation expression. Expected 1 argument(s), but given 0. neg61.fs(174,22,174,23): typecheck error FS0041: No overloads match for method 'Source'. @@ -105,4 +99,4 @@ neg61.fs(191,21,191,33): typecheck error FS3153: Arguments to query operators ma neg61.fs(197,21,197,33): typecheck error FS3153: Arguments to query operators may require parentheses, e.g. 'where (x > y)' or 'groupBy (x.Length / 10)' -neg61.fs(202,20,202,31): typecheck error FS3153: Arguments to query operators may require parentheses, e.g. 'where (x > y)' or 'groupBy (x.Length / 10)' +neg61.fs(202,20,202,31): typecheck error FS3153: Arguments to query operators may require parentheses, e.g. 'where (x > y)' or 'groupBy (x.Length / 10)' \ No newline at end of file diff --git a/tests/fsharp/typecheck/sigs/neg87.bsl b/tests/fsharp/typecheck/sigs/neg87.bsl index 20e2b49f345..298effe9103 100644 --- a/tests/fsharp/typecheck/sigs/neg87.bsl +++ b/tests/fsharp/typecheck/sigs/neg87.bsl @@ -36,3 +36,5 @@ neg87.fsx(14,5,14,10): typecheck error FS3087: The custom operation 'test2' refe neg87.fsx(14,5,14,10): typecheck error FS3087: The custom operation 'test2' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. neg87.fsx(14,5,14,10): typecheck error FS3087: The custom operation 'test2' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. + +neg87.fsx(14,5,14,10): typecheck error FS3087: The custom operation 'test2' refers to a method which is overloaded. The implementations of custom operations may not be overloaded. \ No newline at end of file From 602ecfe95dd9f9e31dfe6fafac53b6b8964526e3 Mon Sep 17 00:00:00 2001 From: Ryan Riley Date: Tue, 11 Aug 2020 07:49:36 -0500 Subject: [PATCH 17/17] Revert "New error messages" This reverts commit 3ee5a492ecd886793c88236217e5a21f4f1e7b65. --- .../DataExpressions/QueryExpressions/E_BadGroupValBy01.fs | 4 ++-- .../DataExpressions/QueryExpressions/E_BadGroupValBy02.fs | 2 +- .../DataExpressions/QueryExpressions/E_WhitespaceErrors01.fs | 2 +- .../Expressions/DataExpressions/QueryExpressions/env.lst | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy01.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy01.fs index 9ed2865a7ea..9e338f91218 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy01.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy01.fs @@ -1,7 +1,7 @@ // #Conformance #DataExpressions #Query // DevDiv:179889, groupValBy was hard to use with poor diagnostics -//This expression was expected to have type. 'Linq\.QuerySource\<'a,'b\> \* \('a \-\> 'c\) \* \('a \-\> 'd\)' .but here has type. 'Linq\.QuerySource\' -//The member or object constructor 'GroupValBy' takes 3 argument\(s\) but is here given 2\. The required signature is 'member Linq\.QueryBuilder\.GroupValBy \: source\:Linq\.QuerySource\<'T,'Q\> \* resultSelector\:\('T \-\> 'Value\) \* keySelector\:\('T \-\> 'Key\) \-\> Linq\.QuerySource\,'Q\> when 'Key \: equality'\.$ +//'groupValBy' is used with an incorrect number of arguments\. This is a custom operation in this query or computation expression\. Expected 2 argument\(s\), but given 0\.$ +//'groupValBy' is used with an incorrect number of arguments\. This is a custom operation in this query or computation expression\. Expected 2 argument\(s\), but given 1\.$ let q1 = query { diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy02.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy02.fs index 434230874b4..bc604c6f5ac 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy02.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_BadGroupValBy02.fs @@ -1,6 +1,6 @@ // #Conformance #DataExpressions #Query // DevDiv:210830, groupValBy with poor diagnostics -//The member or object constructor 'GroupValBy' takes 3 argument\(s\) but is here given 4\. The required signature is 'member Linq\.QueryBuilder\.GroupValBy \: source\:Linq\.QuerySource\<'T,'Q\> \* resultSelector\:\('T \-\> 'Value\) \* keySelector\:\('T \-\> 'Key\) \-\> Linq\.QuerySource\,'Q\> when 'Key \: equality'\. +//This expression was expected to have type.+'System\.Linq\.IGrouping<'a,'b>'.+but here has type.+'unit' let words = ["blueberry"; "chimpanzee"; ] let wordGroups = diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_WhitespaceErrors01.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_WhitespaceErrors01.fs index a9dd25f5173..efc3d64dbba 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_WhitespaceErrors01.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/E_WhitespaceErrors01.fs @@ -1,6 +1,6 @@ // #Conformance #DataExpressions #Query // DevDiv:188241, just baselines errors around spacing -//The member or object constructor 'Where' takes 2 argument\(s\) but is here given 4\. The required signature is 'member Linq\.QueryBuilder\.Where : source:Linq\.QuerySource<'T,'Q> \* predicate:\('T \-> bool\) \-> Linq\.QuerySource<'T,'Q>'\.$ +//'where' is used with an incorrect number of arguments\. This is a custom operation in this query or computation expression\. Expected 1 argument\(s\), but given 3\.$ let q1 = // no errors query { diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/env.lst b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/env.lst index 63cfbf8bd7b..58c79d96417 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/env.lst +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/QueryExpressions/env.lst @@ -13,7 +13,7 @@ NoMT SOURCE=ForWhereJoin01.fs SCFLAGS="--test:ErrorRange NoMT SOURCE=E_WhitespaceErrors01.fs SCFLAGS="--test:ErrorRanges" # E_WhitespaceErrors01.fs NoMT SOURCE=E_WhitespaceErrors02.fs SCFLAGS="--test:ErrorRanges" # E_WhitespaceErrors02.fs NoMT SOURCE=E_WhitespaceErrors03.fs SCFLAGS="--test:ErrorRanges" # E_WhitespaceErrors03.fs -NoMT SOURCE=E_BadGroupValBy01.fs SCFLAGS="--test:ErrorRanges --flaterrors" # E_BadGroupValBy01.fs +NoMT SOURCE=E_BadGroupValBy01.fs SCFLAGS="--test:ErrorRanges" # E_BadGroupValBy01.fs NoMT SOURCE=E_BadGroupValBy02.fs SCFLAGS="--test:ErrorRanges --flaterrors" # E_BadGroupValBy02.fs NoMT SOURCE=E_FirstOrDefaultWithNulls01.fs SCFLAGS="--test:ErrorRanges -r:Utils.dll" # E_FirstOrDefaultWithNulls01.fs