diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 086d5279488..61054bba210 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1653,3 +1653,5 @@ reprStateMachineInvalidForm,"The state machine has an unexpected form" 3536,tcUsingInterfaceWithStaticAbstractMethodAsType,"'%s' is normally used as a type constraint in generic code, e.g. \"'T when ISomeInterface<'T>\" or \"let f (x: #ISomeInterface<_>)\". See https://aka.ms/fsharp-iwsams for guidance. You can disable this warning by using '#nowarn \"3536\"' or '--nowarn:3536'." 3537,tcTraitHasMultipleSupportTypes,"The trait '%s' invoked by this call has multiple support types. This invocation syntax is not permitted for such traits. See https://aka.ms/fsharp-srtp for guidance." 3545,tcMissingRequiredMembers,"The following required properties have to be initalized:%s" +3546,parsExpectingPatternInTuple,"Expecting pattern" +3547,parsExpectedPatternAfterToken,"Expected a pattern after this point" diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs index ef3673fa44f..aefc238d10e 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs @@ -1031,6 +1031,13 @@ let rec normalizeTupleExpr exprs commas : SynExpr list * range list = innerExprs @ rest, innerCommas @ commas | _ -> exprs, commas +let rec normalizeTuplePat pats : SynPat list = + match pats with + | SynPat.Tuple (false, innerPats, _) :: rest -> + let innerExprs = normalizeTuplePat (List.rev innerPats) + innerExprs @ rest + | _ -> pats + /// Remove all members that were captures as SynMemberDefn.GetSetMember let rec desugarGetSetMembers (memberDefns: SynMemberDefns) = memberDefns diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi b/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi index 5af8180d05e..b78563d4bce 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi @@ -350,6 +350,8 @@ val mkDynamicArgExpr: expr: SynExpr -> SynExpr val normalizeTupleExpr: exprs: SynExpr list -> commas: range list -> SynExpr list * range List +val normalizeTuplePat: pats: SynPat list -> SynPat list + val desugarGetSetMembers: memberDefns: SynMemberDefns -> SynMemberDefns val getTypeFromTuplePath: path: SynTupleTypeSegment list -> SynType list diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index d7bbdaaf68e..6e194678018 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -3126,8 +3126,10 @@ headBindingPattern: | headBindingPattern COLON_COLON headBindingPattern { SynPat.LongIdent (SynLongIdent(mkSynCaseName (rhs parseState 2) opNameCons, [], [ Some (IdentTrivia.OriginalNotation "::") ]), None, None, SynArgPats.Pats [SynPat.Tuple (false, [$1;$3], rhs2 parseState 1 3)], None, lhs parseState) } - | tuplePatternElements %prec pat_tuple - { SynPat.Tuple(false, List.rev $1, lhs parseState) } + | tuplePatternElements %prec pat_tuple + { let pats = normalizeTuplePat $1 + let m = (rhs parseState 1, pats) ||> unionRangeWithListBy (fun p -> p.Range) + SynPat.Tuple(false, List.rev pats, m) } | conjPatternElements %prec pat_conj { SynPat.Ands(List.rev $1, lhs parseState) } @@ -3135,12 +3137,37 @@ headBindingPattern: | constrPattern { $1 } -tuplePatternElements: - | tuplePatternElements COMMA headBindingPattern +tuplePatternElements: + | tuplePatternElements COMMA headBindingPattern { $3 :: $1 } - | headBindingPattern COMMA headBindingPattern - { $3 :: $1 :: [] } + | headBindingPattern COMMA headBindingPattern + { [$3; $1] } + + | tuplePatternElements COMMA ends_coming_soon_or_recover + { let commaRange = rhs parseState 2 + reportParseErrorAt commaRange (FSComp.SR.parsExpectingPatternInTuple ()) + let pat2 = SynPat.Wild(commaRange.EndRange) + pat2 :: $1 } + + | headBindingPattern COMMA ends_coming_soon_or_recover + { let commaRange = rhs parseState 2 + reportParseErrorAt commaRange (FSComp.SR.parsExpectingPatternInTuple ()) + let pat2 = SynPat.Wild(commaRange.EndRange) + [pat2; $1] } + + | COMMA headBindingPattern + { let commaRange = rhs parseState 1 + reportParseErrorAt commaRange (FSComp.SR.parsExpectingPatternInTuple ()) + let pat1 = SynPat.Wild(commaRange.StartRange) + [$2; pat1] } + + | COMMA ends_coming_soon_or_recover + { let commaRange = rhs parseState 1 + if not $2 then reportParseErrorAt commaRange (FSComp.SR.parsExpectedPatternAfterToken ()) + let pat1 = SynPat.Wild(commaRange.StartRange) + let pat2 = SynPat.Wild(commaRange.EndRange) + [pat2; pat1] } conjPatternElements: | conjPatternElements AMP headBindingPattern @@ -3351,8 +3378,10 @@ parenPattern: { let mBar = rhs parseState 2 SynPat.Or($1, $3, rhs2 parseState 1 3, { BarRange = mBar }) } - | tupleParenPatternElements - { SynPat.Tuple(false, List.rev $1, lhs parseState) } + | tupleParenPatternElements + { let pats = normalizeTuplePat $1 + let m = (rhs parseState 1, pats) ||> unionRangeWithListBy (fun p -> p.Range) + SynPat.Tuple(false, List.rev pats, m) } | conjParenPatternElements { SynPat.Ands(List.rev $1, rhs2 parseState 1 3) } @@ -3371,11 +3400,36 @@ parenPattern: | constrPattern { $1 } tupleParenPatternElements: - | tupleParenPatternElements COMMA parenPattern + | tupleParenPatternElements COMMA parenPattern { $3 :: $1 } - | parenPattern COMMA parenPattern - { $3 :: $1 :: [] } + | parenPattern COMMA parenPattern + { [$3; $1] } + + | tupleParenPatternElements COMMA ends_coming_soon_or_recover + { let commaRange = rhs parseState 2 + reportParseErrorAt commaRange (FSComp.SR.parsExpectingPatternInTuple()) + let pat2 = SynPat.Wild(commaRange.EndRange) + pat2 :: $1 } + + | parenPattern COMMA ends_coming_soon_or_recover + { let commaRange = rhs parseState 2 + reportParseErrorAt commaRange (FSComp.SR.parsExpectingPatternInTuple()) + let pat2 = SynPat.Wild(commaRange.EndRange) + [pat2; $1] } + + | COMMA parenPattern + { let commaRange = rhs parseState 1 + reportParseErrorAt commaRange (FSComp.SR.parsExpectingPatternInTuple()) + let pat1 = SynPat.Wild(commaRange.StartRange) + [$2; pat1] } + + | COMMA ends_coming_soon_or_recover + { let commaRange = rhs parseState 1 + if not $2 then reportParseErrorAt commaRange (FSComp.SR.parsExpectedPatternAfterToken ()) + let pat1 = SynPat.Wild(commaRange.StartRange) + let pat2 = SynPat.Wild(commaRange.EndRange) + [pat2; pat1] } conjParenPatternElements: | conjParenPatternElements AMP parenPattern diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index a9e1c015194..e0e999dc993 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -592,6 +592,16 @@ Neočekávaný token v definici typu. Za typem {0} se očekává =. + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 98d3cec79d8..9b090dcdb5c 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -592,6 +592,16 @@ Unerwartetes Token in Typdefinition. Nach Typ "{0}" wurde "=" erwartet. + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 9ea5c76f74c..a410c3381fd 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -592,6 +592,16 @@ Token inesperado en la definición de tipo. Se esperaba "=" después del tipo "{0}". + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 608877dac83..542a1f4fc33 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -592,6 +592,16 @@ Jeton inattendu dans la définition de type. Signe '=' attendu après le type '{0}'. + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index c616f13a22a..885462d4313 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -592,6 +592,16 @@ Token imprevisto nella definizione del tipo. Dopo il tipo '{0}' è previsto '='. + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 18b818fea07..e75546a4060 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -592,6 +592,16 @@ 型定義に予期しないトークンがあります。型 '{0}' の後には '=' が必要です。 + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index b361fa40679..0d61eacd4aa 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -592,6 +592,16 @@ 형식 정의에 예기치 않은 토큰이 있습니다. '{0}' 형식 뒤에 '='가 필요합니다. + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index e746b8f8732..32a58e4b23a 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -592,6 +592,16 @@ Nieoczekiwany token w definicji typu. Oczekiwano znaku „=” po typie „{0}”. + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 00ab6117c7a..41465827411 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -592,6 +592,16 @@ Token inesperado na definição de tipo. Esperava-se '=' após o tipo '{0}'. + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 8d68379843e..303abbe53e7 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -592,6 +592,16 @@ Неожиданный токен в определении типа. После типа "{0}" ожидается "=". + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 25de80c1025..d3e695d0686 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -592,6 +592,16 @@ Tür tanımında beklenmeyen belirteç var. '{0}' türünden sonra '=' bekleniyordu. + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index ab75c3f45f0..29db57871b0 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -592,6 +592,16 @@ 类型定义中出现意外标记。类型“{0}”后应为 "="。 + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 781002375e3..45bf1a52370 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -592,6 +592,16 @@ 型別定義中出現非預期的權杖。類型 '{0}' 之後應該要有 '='。 + + Expected a pattern after this point + Expected a pattern after this point + + + + Expecting pattern + Expecting pattern + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) diff --git a/tests/service/Common.fs b/tests/service/Common.fs index 7f2a8e56813..e19ed1f1c49 100644 --- a/tests/service/Common.fs +++ b/tests/service/Common.fs @@ -232,6 +232,11 @@ let getSingleParenInnerExpr expr = | SynModuleDecl.Expr(SynExpr.Paren(expr, _, _, _), _) -> expr | _ -> failwith "Unexpected tree" +let getLetDeclHeadPattern (moduleDecl: SynModuleDecl) = + match moduleDecl with + | SynModuleDecl.Let(_, [SynBinding(headPat = pat)], _) -> pat + | _ -> failwith "Unexpected tree" + let parseSourceCodeAndGetModule (source: string) = parseSourceCode ("test.fsx", source) |> getSingleModuleLikeDecl @@ -458,7 +463,7 @@ let coreLibAssemblyName = "mscorlib" #endif -let getRange (e: SynExpr) = e.Range +let inline getRange (node: ^T) = (^T: (member Range: range) node) let assertRange (expectedStartLine: int, expectedStartColumn: int) diff --git a/tests/service/ParserTests.fs b/tests/service/ParserTests.fs index b96083b77e7..cc4a9923ab7 100644 --- a/tests/service/ParserTests.fs +++ b/tests/service/ParserTests.fs @@ -131,9 +131,7 @@ match () with match getSingleExprInModule parseResults with | SynExpr.Match (clauses=[ SynMatchClause (pat=pat) ]) -> match pat with - | SynPat.Or - (SynPat.FromParseError (SynPat.Paren (SynPat.FromParseError (SynPat.Wild _, _), _), _), - SynPat.Named _, _, _) -> () + | SynPat.Paren(SynPat.Or(SynPat.Tuple(_, [SynPat.Named _; SynPat.Wild _], _), SynPat.Named _, _, _), _) -> () | _ -> failwith "Unexpected pattern" | _ -> failwith "Unexpected tree" @@ -185,7 +183,7 @@ let f (x, match getSingleDeclInModule parseResults with | SynModuleDecl.Let (_, [ SynBinding (headPat = SynPat.LongIdent (argPats = SynArgPats.Pats [ pat ])) ], _) -> match pat with - | SynPat.FromParseError (SynPat.Paren (SynPat.FromParseError (SynPat.Wild _, _), _), _) -> () + | SynPat.FromParseError (SynPat.Paren (SynPat.Tuple(_, [SynPat.Named _; SynPat.Wild _], _), _), _) -> () | _ -> failwith "Unexpected tree" | _ -> failwith "Unexpected tree" @@ -194,7 +192,11 @@ let assertIsBefore (f: _ -> range) (a, b) = let r2 = f b Position.posGeq r2.Start r1.End |> shouldEqual true -let checkExprOrder exprs = +let inline assertIsEmptyRange node = + let range = getRange node + Position.posEq range.Start range.End |> shouldEqual true + +let inline checkNodeOrder exprs = exprs |> List.pairwise |> List.iter (assertIsBefore getRange) @@ -220,7 +222,7 @@ let ``Expr - Tuple 01`` () = | [ SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e11; SynExpr.ArbitraryAfterError _ as e12], c1, _) SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e21; SynExpr.ArbitraryAfterError _ as e22; SynExpr.ArbitraryAfterError _ as e23], c2, _) SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e31; SynExpr.ArbitraryAfterError _ as e32; SynExpr.ArbitraryAfterError _ as e33; SynExpr.ArbitraryAfterError _ as e34], c3, _) ] -> - [ e11; e12; e21; e22; e23; e31; e32; e33; e34 ] |> checkExprOrder + [ e11; e12; e21; e22; e23; e31; e32; e33; e34 ] |> checkNodeOrder [ c1, 1; c2, 2; c3, 3 ] |> checkRangeCountAndOrder | _ -> failwith "Unexpected tree" @@ -237,7 +239,7 @@ let ``Expr - Tuple 02`` () = | [ SynExpr.Tuple(_, [SynExpr.Const _ as e11; SynExpr.ArbitraryAfterError _ as e12], c1, _) SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e21; SynExpr.Const _ as e22], c2, _) SynExpr.Tuple(_, [SynExpr.Const _ as e31; SynExpr.Const _ as e32], c3, _) ] -> - [ e11; e12; e21; e22; e31; e32 ] |> checkExprOrder + [ e11; e12; e21; e22; e31; e32 ] |> checkNodeOrder [ c1, 1; c2, 1; c3, 1 ] |> checkRangeCountAndOrder | _ -> failwith "Unexpected tree" @@ -269,7 +271,7 @@ let ``Expr - Tuple 03`` () = [ e11; e12; e13; e21; e22; e23; e31; e32; e33 e41; e42; e43; e51; e52; e53; e61; e62; e63 e71; e72; e73 ] - |> checkExprOrder + |> checkNodeOrder [ c1, 2; c2, 2; c3, 2 c4, 2; c5, 2; c6, 2 @@ -294,9 +296,7 @@ let ``Expr - Tuple 04`` () = SynExpr.ArbitraryAfterError _ as e6 SynExpr.Const _ as e7 SynExpr.ArbitraryAfterError _ as e8 ], c, _) ] -> - [ e1; e2; e3; e4; e5; e6; e7; e8 ] - |> checkExprOrder - + [ e1; e2; e3; e4; e5; e6; e7; e8 ] |> checkNodeOrder [ c, 7 ] |> checkRangeCountAndOrder | _ -> failwith "Unexpected tree" @@ -333,3 +333,138 @@ let x = 1, shouldEqual expr.Range.StartLine expr.Range.EndLine shouldEqual range.StartLine range.EndLine | _ -> failwith "Unexpected tree" + +[] +let ``Pattern - Head - Tuple 01`` () = + let parseResults = getParseResults """ +let , = () +let ,, = () +let ,,, = () +""" + let pats = getSingleModuleMemberDecls parseResults |> List.map getLetDeclHeadPattern + match pats with + | [ SynPat.Tuple(_, [SynPat.Wild _ as p11; SynPat.Wild _ as p12], _) + SynPat.Tuple(_, [SynPat.Wild _ as p21; SynPat.Wild _ as p22; SynPat.Wild _ as p23], _) + SynPat.Tuple(_, [SynPat.Wild _ as p31; SynPat.Wild _ as p32; SynPat.Wild _ as p33; SynPat.Wild _ as p34], _) ] -> + [ p11; p12; p21; p22; p23; p31; p32; p33; p34 ] |> checkNodeOrder + [ p11; p12; p21; p22; p23; p31; p32; p33; p34 ] |> List.iter assertIsEmptyRange + + | _ -> failwith "Unexpected tree" + +[] +let ``Pattern - Head - Tuple 02`` () = + let parseResults = getParseResults """ +let 1, = () +let ,1 = () +let 1,1 = () +""" + let pats = getSingleModuleMemberDecls parseResults |> List.map getLetDeclHeadPattern + match pats with + | [ SynPat.Tuple(_, [SynPat.Const _ as p11; SynPat.Wild _ as p12], _) + SynPat.Tuple(_, [SynPat.Wild _ as p21; SynPat.Const _ as p22], _) + SynPat.Tuple(_, [SynPat.Const _ as p31; SynPat.Const _ as p32], _) ] -> + [ p11; p12; p21; p22; p31; p32 ] |> checkNodeOrder + [ p12; p21 ] |> List.iter assertIsEmptyRange + + | _ -> failwith "Unexpected tree" + +[] +let ``Pattern - Head - Tuple 03`` () = + let parseResults = getParseResults """ +let 1,, = () +let ,1, = () +let ,,1 = () + +let 1,1, = () +let ,1,1 = () +let 1,,1 = () + +let 1,1,1 = () +""" + let pats = getSingleModuleMemberDecls parseResults |> List.map getLetDeclHeadPattern + match pats with + | [ SynPat.Tuple(_, [SynPat.Const _ as p11; SynPat.Wild _ as p12; SynPat.Wild _ as p13], _) + SynPat.Tuple(_, [SynPat.Wild _ as p21; SynPat.Const _ as p22; SynPat.Wild _ as p23], _) + SynPat.Tuple(_, [SynPat.Wild _ as p31; SynPat.Wild _ as p32; SynPat.Const _ as p33], _) + + SynPat.Tuple(_, [SynPat.Const _ as p41; SynPat.Const _ as p42; SynPat.Wild _ as p43], _) + SynPat.Tuple(_, [SynPat.Wild _ as p51; SynPat.Const _ as p52; SynPat.Const _ as p53], _) + SynPat.Tuple(_, [SynPat.Const _ as p61; SynPat.Wild _ as p62; SynPat.Const _ as p63], _) + + SynPat.Tuple(_, [SynPat.Const _ as p71; SynPat.Const _ as p72; SynPat.Const _ as p73], _) ] -> + [ p11; p12; p13; p21; p22; p23; p31; p32; p33 + p41; p42; p43; p51; p52; p53; p61; p62; p63 + p71; p72; p73 ] |> checkNodeOrder + [ p12; p13; p21; p23; p31; p32; p43; p51; p62 ] |> List.iter assertIsEmptyRange + + | _ -> failwith "Unexpected tree" + +let getParenPatInnerPattern pat = + match pat with + | SynPat.Paren(pat, _) -> pat + | _ -> failwith "Unexpected tree" + +[] +let ``Pattern - Paren - Tuple 01`` () = + let parseResults = getParseResults """ +let (,) = () +let (,,) = () +let (,,,) = () +""" + let pats = getSingleModuleMemberDecls parseResults |> List.map (getLetDeclHeadPattern >> getParenPatInnerPattern) + match pats with + | [ SynPat.Tuple(_, [SynPat.Wild _ as p11; SynPat.Wild _ as p12], _) + SynPat.Tuple(_, [SynPat.Wild _ as p21; SynPat.Wild _ as p22; SynPat.Wild _ as p23], _) + SynPat.Tuple(_, [SynPat.Wild _ as p31; SynPat.Wild _ as p32; SynPat.Wild _ as p33; SynPat.Wild _ as p34], _) ] -> + [ p11; p12; p21; p22; p23; p31; p32; p33; p34 ] |> checkNodeOrder + [ p11; p12; p21; p22; p23; p31; p32; p33; p34 ] |> List.iter assertIsEmptyRange + + | _ -> failwith "Unexpected tree" + +[] +let ``Pattern - Paren - Tuple 02`` () = + let parseResults = getParseResults """ +let (1,) = () +let (,1) = () +let (1,1) = () +""" + let pats = getSingleModuleMemberDecls parseResults |> List.map (getLetDeclHeadPattern >> getParenPatInnerPattern) + match pats with + | [ SynPat.Tuple(_, [SynPat.Const _ as p11; SynPat.Wild _ as p12], _) + SynPat.Tuple(_, [SynPat.Wild _ as p21; SynPat.Const _ as p22], _) + SynPat.Tuple(_, [SynPat.Const _ as p31; SynPat.Const _ as p32], _) ] -> + [ p11; p12; p21; p22; p31; p32 ] |> checkNodeOrder + [ p12; p21 ] |> List.iter assertIsEmptyRange + + | _ -> failwith "Unexpected tree" + +[] +let ``Pattern - Paren - Tuple 03`` () = + let parseResults = getParseResults """ +let (1,,) = () +let (,1,) = () +let (,,1) = () + +let (1,1,) = () +let (,1,1) = () +let (1,,1) = () + +let (1,1,1) = () +""" + let pats = getSingleModuleMemberDecls parseResults |> List.map (getLetDeclHeadPattern >> getParenPatInnerPattern) + match pats with + | [ SynPat.Tuple(_, [SynPat.Const _ as p11; SynPat.Wild _ as p12; SynPat.Wild _ as p13], _) + SynPat.Tuple(_, [SynPat.Wild _ as p21; SynPat.Const _ as p22; SynPat.Wild _ as p23], _) + SynPat.Tuple(_, [SynPat.Wild _ as p31; SynPat.Wild _ as p32; SynPat.Const _ as p33], _) + + SynPat.Tuple(_, [SynPat.Const _ as p41; SynPat.Const _ as p42; SynPat.Wild _ as p43], _) + SynPat.Tuple(_, [SynPat.Wild _ as p51; SynPat.Const _ as p52; SynPat.Const _ as p53], _) + SynPat.Tuple(_, [SynPat.Const _ as p61; SynPat.Wild _ as p62; SynPat.Const _ as p63], _) + + SynPat.Tuple(_, [SynPat.Const _ as p71; SynPat.Const _ as p72; SynPat.Const _ as p73], _) ] -> + [ p11; p12; p13; p21; p22; p23; p31; p32; p33 + p41; p42; p43; p51; p52; p53; p61; p62; p63 + p71; p72; p73 ] |> checkNodeOrder + [ p12; p13; p21; p23; p31; p32; p43; p51; p62 ] |> List.iter assertIsEmptyRange + + | _ -> failwith "Unexpected tree" diff --git a/tests/service/PatternMatchCompilationTests.fs b/tests/service/PatternMatchCompilationTests.fs index 4e56b7672e2..8654a59caf3 100644 --- a/tests/service/PatternMatchCompilationTests.fs +++ b/tests/service/PatternMatchCompilationTests.fs @@ -781,6 +781,7 @@ let z as = """ dumpDiagnostics checkResults |> shouldEqual [ "(10,7--10,9): Unexpected keyword 'as' in binding" + "(10,5--10,6): Expecting pattern" "(11,10--11,12): Unexpected keyword 'as' in binding. Expected '=' or other token." "(12,9--12,11): Unexpected keyword 'as' in binding" "(13,8--13,10): Unexpected keyword 'as' in binding" @@ -801,6 +802,7 @@ let z as = "(6,4--6,10): This runtime coercion or type test from type 'a to int involves an indeterminate type based on information prior to this program point. Runtime type tests are not allowed on some types. Further type annotations are needed." "(8,29--8,30): This expression was expected to have type 'unit' but here has type 'int'" "(9,26--9,27): This expression was expected to have type 'unit' but here has type 'int'" + "(10,14--10,15): This expression was expected to have type ''a * 'b' but here has type 'int'" "(15,4--15,5): The pattern discriminator 'r' is not defined." "(15,4--15,12): Incomplete pattern matches on this expression." ] @@ -1182,6 +1184,7 @@ let as :? z = """ dumpDiagnostics checkResults |> shouldEqual [ "(10,7--10,9): Unexpected keyword 'as' in binding" + "(10,5--10,6): Expecting pattern" "(11,10--11,12): Unexpected keyword 'as' in binding. Expected '=' or other token." "(12,9--12,11): Unexpected keyword 'as' in binding" "(13,8--13,10): Unexpected keyword 'as' in binding" @@ -1209,6 +1212,8 @@ let as :? z = "(8,25--8,29): The type 'unit' does not have any proper subtypes and cannot be used as the source of a type test or runtime coercion." "(9,25--9,26): The type 'g' is not defined." "(9,22--9,26): The type 'unit' does not have any proper subtypes and cannot be used as the source of a type test or runtime coercion." + "(10,13--10,14): The type 'i' is not defined." + "(10,10--10,14): The type ''a * 'b' does not have any proper subtypes and cannot be used as the source of a type test or runtime coercion." "(16,4--16,5): The pattern discriminator 't' is not defined." "(16,14--16,15): The type 'u' is not defined." "(16,11--16,15): This runtime coercion or type test from type 'a to 'b involves an indeterminate type based on information prior to this program point. Runtime type tests are not allowed on some types. Further type annotations are needed."