diff --git a/src/Compiler/Checking/CheckPatterns.fs b/src/Compiler/Checking/CheckPatterns.fs index 238e3668de7..70382723f92 100644 --- a/src/Compiler/Checking/CheckPatterns.fs +++ b/src/Compiler/Checking/CheckPatterns.fs @@ -289,6 +289,11 @@ and TcPat warnOnUpper (cenv: cenv) env valReprInfo vFlags (patEnv: TcPatLinearEn | SynPat.Or (pat1, pat2, m, _) -> TcPatOr warnOnUpper cenv env vFlags patEnv ty pat1 pat2 m + | SynPat.ListCons(pat1, pat2, m, trivia) -> + let longDotId = SynLongIdent((mkSynCaseName trivia.ColonColonRange opNameCons), [], [Some (FSharp.Compiler.SyntaxTrivia.IdentTrivia.OriginalNotation "::")]) + let args = SynArgPats.Pats [ SynPat.Tuple(false, [ pat1; pat2 ], m) ] + TcPatLongIdent warnOnUpper cenv env ad valReprInfo vFlags patEnv ty (longDotId, None, args, None, m) + | SynPat.Ands (pats, m) -> TcPatAnds warnOnUpper cenv env vFlags patEnv ty pats m diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fs b/src/Compiler/Service/ServiceParseTreeWalk.fs index c75b133a371..f3443fd95ff 100755 --- a/src/Compiler/Service/ServiceParseTreeWalk.fs +++ b/src/Compiler/Service/ServiceParseTreeWalk.fs @@ -789,7 +789,8 @@ module SyntaxTraversal = match p with | SynPat.Paren (p, _) -> traversePat path p | SynPat.As (p1, p2, _) - | SynPat.Or (p1, p2, _, _) -> [ p1; p2 ] |> List.tryPick (traversePat path) + | SynPat.Or (p1, p2, _, _) + | SynPat.ListCons (p1, p2, _, _) -> [ p1; p2 ] |> List.tryPick (traversePat path) | SynPat.Ands (ps, _) | SynPat.Tuple (_, ps, _) | SynPat.ArrayOrList (_, ps, _) -> ps |> List.tryPick (traversePat path) diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index ab24bcb5a44..86d560091ea 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -619,7 +619,8 @@ module ParsedInput = | SynPat.As (pat1, pat2, _) -> List.tryPick walkPat [ pat1; pat2 ] | SynPat.Typed (pat, t, _) -> walkPat pat |> Option.orElseWith (fun () -> walkType t) | SynPat.Attrib (pat, Attributes attrs, _) -> walkPat pat |> Option.orElseWith (fun () -> List.tryPick walkAttribute attrs) - | SynPat.Or (pat1, pat2, _, _) -> List.tryPick walkPat [ pat1; pat2 ] + | SynPat.Or (pat1, pat2, _, _) + | SynPat.ListCons (pat1, pat2, _, _) -> List.tryPick walkPat [ pat1; pat2 ] | SynPat.LongIdent (typarDecls = typars; argPats = ConstructorPats pats; range = r) -> ifPosInRange r (fun _ -> kind) |> Option.orElseWith (fun () -> @@ -1638,7 +1639,8 @@ module ParsedInput = walkPat pat List.iter walkAttribute attrs | SynPat.As (pat1, pat2, _) - | SynPat.Or (pat1, pat2, _, _) -> List.iter walkPat [ pat1; pat2 ] + | SynPat.Or (pat1, pat2, _, _) + | SynPat.ListCons (pat1, pat2, _, _) -> List.iter walkPat [ pat1; pat2 ] | SynPat.LongIdent (longDotId = ident; typarDecls = typars; argPats = ConstructorPats pats) -> addLongIdentWithDots ident diff --git a/src/Compiler/Service/ServiceXmlDocParser.fs b/src/Compiler/Service/ServiceXmlDocParser.fs index ae9217e8a02..4a7eca7868d 100644 --- a/src/Compiler/Service/ServiceXmlDocParser.fs +++ b/src/Compiler/Service/ServiceXmlDocParser.fs @@ -25,6 +25,7 @@ module XmlDocParsing = | SynPat.Typed (pat, _type, _range) -> digNamesFrom pat | SynPat.Attrib (pat, _attrs, _range) -> digNamesFrom pat | SynPat.LongIdent(argPats = ConstructorPats pats) -> pats |> List.collect digNamesFrom + | SynPat.ListCons (p1, p2, _, _) -> List.collect digNamesFrom [ p1; p2 ] | SynPat.Tuple (_, pats, _range) -> pats |> List.collect digNamesFrom | SynPat.Paren (pat, _range) -> digNamesFrom pat | SynPat.OptionalVal (id, _) -> [ id.idText ] diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index 11c0c28375b..9412e8486ae 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fs +++ b/src/Compiler/SyntaxTree/SyntaxTree.fs @@ -908,6 +908,8 @@ type SynPat = | Or of lhsPat: SynPat * rhsPat: SynPat * range: range * trivia: SynPatOrTrivia + | ListCons of lhsPat: SynPat * rhsPat: SynPat * range: range * trivia: SynPatListConsTrivia + | Ands of pats: SynPat list * range: range | As of lhsPat: SynPat * rhsPat: SynPat * range: range @@ -953,6 +955,7 @@ type SynPat = | SynPat.Wild (range = m) | SynPat.Named (range = m) | SynPat.Or (range = m) + | SynPat.ListCons (range = m) | SynPat.Ands (range = m) | SynPat.As (range = m) | SynPat.LongIdent (range = m) diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fsi b/src/Compiler/SyntaxTree/SyntaxTree.fsi index 2a34ba55c46..1dfd44d2c0f 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTree.fsi @@ -1050,6 +1050,9 @@ type SynPat = /// A disjunctive pattern 'pat1 | pat2' | Or of lhsPat: SynPat * rhsPat: SynPat * range: range * trivia: SynPatOrTrivia + /// A conjunctive pattern 'pat1 :: pat2' + | ListCons of lhsPat: SynPat * rhsPat: SynPat * range: range * trivia: SynPatListConsTrivia + /// A conjunctive pattern 'pat1 & pat2' | Ands of pats: SynPat list * range: range diff --git a/src/Compiler/SyntaxTree/SyntaxTrivia.fs b/src/Compiler/SyntaxTree/SyntaxTrivia.fs index 5f500caec88..e4b58c85c00 100644 --- a/src/Compiler/SyntaxTree/SyntaxTrivia.fs +++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fs @@ -122,6 +122,9 @@ type SynUnionCaseTrivia = { BarRange: range option } [] type SynPatOrTrivia = { BarRange: range } +[] +type SynPatListConsTrivia = { ColonColonRange: range } + [] type SynTypeDefnTrivia = { diff --git a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi index 3cac74f9026..3e0dea3db0b 100644 --- a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi @@ -199,6 +199,14 @@ type SynPatOrTrivia = BarRange: range } +/// Represents additional information for SynPat.Cons +[] +type SynPatListConsTrivia = + { + /// The syntax range of the `::` token. + ColonColonRange: range + } + /// Represents additional information for SynTypeDefn [] type SynTypeDefnTrivia = diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 63dba4eb2cb..c9dd108bf2d 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -3124,7 +3124,8 @@ headBindingPattern: SynPat.Or($1, $3, rhs2 parseState 1 3, { BarRange = mBar }) } | 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) } + { let mColonColon = rhs parseState 2 + SynPat.ListCons($1, $3, rhs2 parseState 1 3, { ColonColonRange = mColonColon }) } | tuplePatternElements %prec pat_tuple { let pats = normalizeTuplePat $1 @@ -3398,7 +3399,8 @@ parenPattern: SynPat.Attrib($2, $1, mLhs) } | parenPattern COLON_COLON parenPattern - { 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) } + { let mColonColon = rhs parseState 2 + SynPat.ListCons($1, $3, rhs2 parseState 1 3, { ColonColonRange = mColonColon }) } | constrPattern { $1 } diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected index 4bb3025a106..a6713fdbc26 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected @@ -8004,6 +8004,14 @@ FSharp.Compiler.Syntax.SynPat+IsInst: FSharp.Compiler.Syntax.SynType get_pat() FSharp.Compiler.Syntax.SynPat+IsInst: FSharp.Compiler.Syntax.SynType pat FSharp.Compiler.Syntax.SynPat+IsInst: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.Syntax.SynPat+IsInst: FSharp.Compiler.Text.Range range +FSharp.Compiler.Syntax.SynPat+ListCons: FSharp.Compiler.Syntax.SynPat get_lhsPat() +FSharp.Compiler.Syntax.SynPat+ListCons: FSharp.Compiler.Syntax.SynPat get_rhsPat() +FSharp.Compiler.Syntax.SynPat+ListCons: FSharp.Compiler.Syntax.SynPat lhsPat +FSharp.Compiler.Syntax.SynPat+ListCons: FSharp.Compiler.Syntax.SynPat rhsPat +FSharp.Compiler.Syntax.SynPat+ListCons: FSharp.Compiler.SyntaxTrivia.SynPatListConsTrivia get_trivia() +FSharp.Compiler.Syntax.SynPat+ListCons: FSharp.Compiler.SyntaxTrivia.SynPatListConsTrivia trivia +FSharp.Compiler.Syntax.SynPat+ListCons: FSharp.Compiler.Text.Range get_range() +FSharp.Compiler.Syntax.SynPat+ListCons: FSharp.Compiler.Text.Range range FSharp.Compiler.Syntax.SynPat+LongIdent: FSharp.Compiler.Syntax.SynArgPats argPats FSharp.Compiler.Syntax.SynPat+LongIdent: FSharp.Compiler.Syntax.SynArgPats get_argPats() FSharp.Compiler.Syntax.SynPat+LongIdent: FSharp.Compiler.Syntax.SynLongIdent get_longDotId() @@ -8059,6 +8067,7 @@ FSharp.Compiler.Syntax.SynPat+Tags: Int32 DeprecatedCharRange FSharp.Compiler.Syntax.SynPat+Tags: Int32 FromParseError FSharp.Compiler.Syntax.SynPat+Tags: Int32 InstanceMember FSharp.Compiler.Syntax.SynPat+Tags: Int32 IsInst +FSharp.Compiler.Syntax.SynPat+Tags: Int32 ListCons FSharp.Compiler.Syntax.SynPat+Tags: Int32 LongIdent FSharp.Compiler.Syntax.SynPat+Tags: Int32 Named FSharp.Compiler.Syntax.SynPat+Tags: Int32 Null @@ -8093,6 +8102,7 @@ FSharp.Compiler.Syntax.SynPat: Boolean IsDeprecatedCharRange FSharp.Compiler.Syntax.SynPat: Boolean IsFromParseError FSharp.Compiler.Syntax.SynPat: Boolean IsInstanceMember FSharp.Compiler.Syntax.SynPat: Boolean IsIsInst +FSharp.Compiler.Syntax.SynPat: Boolean IsListCons FSharp.Compiler.Syntax.SynPat: Boolean IsLongIdent FSharp.Compiler.Syntax.SynPat: Boolean IsNamed FSharp.Compiler.Syntax.SynPat: Boolean IsNull @@ -8113,6 +8123,7 @@ FSharp.Compiler.Syntax.SynPat: Boolean get_IsDeprecatedCharRange() FSharp.Compiler.Syntax.SynPat: Boolean get_IsFromParseError() FSharp.Compiler.Syntax.SynPat: Boolean get_IsInstanceMember() FSharp.Compiler.Syntax.SynPat: Boolean get_IsIsInst() +FSharp.Compiler.Syntax.SynPat: Boolean get_IsListCons() FSharp.Compiler.Syntax.SynPat: Boolean get_IsLongIdent() FSharp.Compiler.Syntax.SynPat: Boolean get_IsNamed() FSharp.Compiler.Syntax.SynPat: Boolean get_IsNull() @@ -8133,6 +8144,7 @@ FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat NewDeprecatedCharRa FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat NewFromParseError(FSharp.Compiler.Syntax.SynPat, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat NewInstanceMember(FSharp.Compiler.Syntax.Ident, FSharp.Compiler.Syntax.Ident, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynAccess], FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat NewIsInst(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Text.Range) +FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat NewListCons(FSharp.Compiler.Syntax.SynPat, FSharp.Compiler.Syntax.SynPat, FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynPatListConsTrivia) FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat NewLongIdent(FSharp.Compiler.Syntax.SynLongIdent, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynValTyparDecls], FSharp.Compiler.Syntax.SynArgPats, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynAccess], FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat NewNamed(FSharp.Compiler.Syntax.SynIdent, Boolean, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynAccess], FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat NewNull(FSharp.Compiler.Text.Range) @@ -8153,6 +8165,7 @@ FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat+DeprecatedCharRange FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat+FromParseError FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat+InstanceMember FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat+IsInst +FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat+ListCons FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat+LongIdent FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat+Named FSharp.Compiler.Syntax.SynPat: FSharp.Compiler.Syntax.SynPat+Null @@ -9556,6 +9569,11 @@ FSharp.Compiler.SyntaxTrivia.SynModuleSigDeclNestedModuleTrivia: Microsoft.FShar FSharp.Compiler.SyntaxTrivia.SynModuleSigDeclNestedModuleTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] get_ModuleKeyword() FSharp.Compiler.SyntaxTrivia.SynModuleSigDeclNestedModuleTrivia: System.String ToString() FSharp.Compiler.SyntaxTrivia.SynModuleSigDeclNestedModuleTrivia: Void .ctor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range]) +FSharp.Compiler.SyntaxTrivia.SynPatListConsTrivia +FSharp.Compiler.SyntaxTrivia.SynPatListConsTrivia: FSharp.Compiler.Text.Range ColonColonRange +FSharp.Compiler.SyntaxTrivia.SynPatListConsTrivia: FSharp.Compiler.Text.Range get_ColonColonRange() +FSharp.Compiler.SyntaxTrivia.SynPatListConsTrivia: System.String ToString() +FSharp.Compiler.SyntaxTrivia.SynPatListConsTrivia: Void .ctor(FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTrivia.SynPatOrTrivia FSharp.Compiler.SyntaxTrivia.SynPatOrTrivia: FSharp.Compiler.Text.Range BarRange FSharp.Compiler.SyntaxTrivia.SynPatOrTrivia: FSharp.Compiler.Text.Range get_BarRange() diff --git a/tests/service/SyntaxTreeTests/PatternTests.fs b/tests/service/SyntaxTreeTests/PatternTests.fs index 72b10da7790..c03325e6077 100644 --- a/tests/service/SyntaxTreeTests/PatternTests.fs +++ b/tests/service/SyntaxTreeTests/PatternTests.fs @@ -73,10 +73,10 @@ let (head::tail) = [ 1;2;4] match parseResults with | ParsedInput.ImplFile (ParsedImplFileInput (contents = [ SynModuleOrNamespace.SynModuleOrNamespace(decls = [ SynModuleDecl.Let( - bindings = [ SynBinding(headPat = SynPat.Paren(SynPat.LongIdent(longDotId = SynLongIdent([ opColonColonIdent ], _, [ Some (IdentTrivia.OriginalNotation "::") ])), _)) ] + bindings = [ SynBinding(headPat = SynPat.Paren(pat = SynPat.ListCons(trivia = trivia))) ] ) ]) ])) -> - Assert.AreEqual("op_ColonColon", opColonColonIdent.idText) + assertRange (2,9) (2,11) trivia.ColonColonRange | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" [] @@ -92,11 +92,11 @@ match x with | ParsedInput.ImplFile (ParsedImplFileInput (contents = [ SynModuleOrNamespace.SynModuleOrNamespace(decls = [ SynModuleDecl.Expr( expr = SynExpr.Match(clauses = [ - SynMatchClause(pat = SynPat.LongIdent(longDotId = SynLongIdent([ opColonColonIdent ], _, [ Some (IdentTrivia.OriginalNotation "::") ]))) + SynMatchClause(pat = SynPat.ListCons(trivia = trivia)) ]) ) ]) ])) -> - Assert.AreEqual("op_ColonColon", opColonColonIdent.idText) + assertRange (3, 9) (3, 11) trivia.ColonColonRange | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" [] @@ -122,3 +122,19 @@ match data with ]) ])) -> assertRange (3, 13) (5, 13) trivia.ParenRange | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" + +[] +let ``:: in head pattern`` () = + let parseResults = + getParseResults + """ +let 1 :: _ = [ 4; 5; 6 ] +""" + + match parseResults with + | ParsedInput.ImplFile(ParsedImplFileInput(contents = [ SynModuleOrNamespace(decls = [ + SynModuleDecl.Let(bindings = [ SynBinding(headPat = + SynPat.ListCons(trivia = trivia)) ]) + ]) ])) -> + assertRange (2,6) (2, 8) trivia.ColonColonRange + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}"