Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 71 additions & 4 deletions src/fsharp/TypeChecker.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7658,17 +7658,24 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder

Some (nm, maintainsVarSpaceUsingBind, maintainsVarSpace, allowInto, isLikeZip, isLikeJoin, isLikeGroupJoin, joinConditionWord, methInfo))

let customOperationMethodsIndexedByKeyword =
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.groupBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName)
|> Seq.map (fun (nm, g) ->
(nm,
g
|> Seq.distinctBy (fun (nm, _, _, _, _, _, _, _, _) -> nm) |> Seq.toList ))
|> dict


Expand Down Expand Up @@ -8299,6 +8306,66 @@ and TcComputationExpression cenv env overallTy mWhole (interpExpr: Expr) builder
// Now run the consumeCustomOpClauses
Some (consumeCustomOpClauses q varSpace dataCompPriorToOp comp false mClause)

let dataCompAfterOp =
match opExpr with
| StripApps(SingleIdent nm, args) ->
// Check for the [<ProjectionParameter>] 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
| None ->
match optionalIntoPat with
| Some intoPat -> errorR(Error(FSComp.SR.tcIntoNeedsRestOfQuery(), intoPat.Range))
| None -> ()
dataCompAfterOp

| Some contExpr ->

// select a.Name into name; ...
// distinct into d; ...
//
// Rebind the into pattern and process the rest of the clauses
match optionalIntoPat with
| Some intoPat ->
if not (customOperationAllowsInto nm) then
error(Error(FSComp.SR.tcOperatorDoesntAcceptInto(nm.idText), intoPat.Range))

// Rebind using either for ... or let!....
let rebind =
if maintainsVarSpaceUsingBind then
SynExpr.LetOrUseBang(NoSequencePointAtLetBinding, false, false, intoPat, dataCompAfterOp, contExpr, intoPat.Range)
else
SynExpr.ForEach (NoSequencePointAtForLoop, SeqExprOnly false, false, intoPat, dataCompAfterOp, contExpr, intoPat.Range)

trans true q emptyVarSpace rebind id

// select a.Name; ...
// distinct; ...
//
// Process the rest of the clauses
| None ->
if maintainsVarSpace || maintainsVarSpaceUsingBind then
consumeClauses varSpace dataCompAfterOp contExpr maintainsVarSpaceUsingBind
else
consumeClauses emptyVarSpace dataCompAfterOp contExpr false

// No more custom operator clauses in compClausesExpr, but there may be clauses like join, yield etc.
// Bind/iterate the dataCompPrior and use compClausesExpr as the body.
| _ ->
// Rebind using either for ... or let!....
let rebind =
if lastUsesBind then
SynExpr.LetOrUseBang(NoSequencePointAtLetBinding, false, false, varSpacePat, dataCompPrior, compClausesExpr, compClausesExpr.Range)
else
SynExpr.ForEach (NoSequencePointAtForLoop, SeqExprOnly false, false, varSpacePat, dataCompPrior, compClausesExpr, compClausesExpr.Range)

trans true q varSpace rebind id

// Now run the consumeClauses
Some (consumeClauses varSpace dataCompPriorToOp comp false)

| SynExpr.Sequential (sp, true, innerComp1, innerComp2, m) ->

// Check for 'where x > y' and other mis-applications of infix operators. If detected, give a good error message, and just ignore innerComp1
Expand Down
2 changes: 0 additions & 2 deletions tests/fsharp/typecheck/sigs/neg60.bsl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 8 additions & 2 deletions tests/fsharp/typecheck/sigs/neg61.bsl
Original file line number Diff line number Diff line change
Expand Up @@ -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<int,System.Collections.IEnumerable>'

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.

Expand Down Expand Up @@ -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<int,System.Collections.IEnumerable>'

neg61.fs(174,22,174,23): typecheck error FS0041: No overloads match for method 'Source'.

Expand Down
2 changes: 0 additions & 2 deletions tests/fsharp/typecheck/sigs/neg87.bsl
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// #Conformance #DataExpressions #Query
// DevDiv:179889, groupValBy was hard to use with poor diagnostics
//<Expects status="error" span="(9,9-9,19)" id="FS3099">'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\.$</Expects>
//<Expects status="error" span="(15,9-15,19)" id="FS3099">'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\.$</Expects>
//<Expects status="error" span="(8,9-8,28)" id="FS0001">This expression was expected to have type. 'Linq\.QuerySource\<'a,'b\> \* \('a \-\> 'c\) \* \('a \-\> 'd\)' .but here has type. 'Linq\.QuerySource\<int,System\.Collections\.IEnumerable\>'</Expects>
//<Expects status="error" span="(15,9-15,21)" id="FS0501">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\<System\.Linq\.IGrouping\<'Key,'Value\>,'Q\> when 'Key \: equality'\.$</Expects>

let q1 =
query {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// #Conformance #DataExpressions #Query
// DevDiv:210830, groupValBy with poor diagnostics
//<Expects status="error" span="(9,6-9,32)" id="FS0001">This expression was expected to have type.+'System\.Linq\.IGrouping<'a,'b>'.+but here has type.+'unit'</Expects>
//<Expects status="error" span="(9,6-9,32)" id="FS0501">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\<System\.Linq\.IGrouping\<'Key,'Value\>,'Q\> when 'Key \: equality'\.</Expects>

let words = ["blueberry"; "chimpanzee"; ]
let wordGroups =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// #Conformance #DataExpressions #Query
// DevDiv:188241, just baselines errors around spacing
//<Expects status="error" span="(15,13-15,18)" id="FS3099">'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\.$</Expects>
//<Expects status="error" span="(15,13-16,25)" id="FS0501">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>'\.$</Expects>

let q1 = // no errors
query {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down