Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a few AND operator parser bugs and regressions #17113

Merged
merged 6 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/8.0.400.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Fix calling an overridden virtual static method via the interface ([PR #17013](https://github.com/dotnet/fsharp/pull/17013))
* Fix state machines compilation, when big decision trees are involved, by removing code split when resumable code is detected ([PR #17076](https://github.com/dotnet/fsharp/pull/17076))
* Fix for exponential runtime in CE builders when using nested implicit yields [PR #17096](https://github.com/dotnet/fsharp/pull/17096)
* Fix several AND operator parser bugs and regressions ([Issue #16447](https://github.com/dotnet/fsharp/issues/16447), [Issue #17134](https://github.com/dotnet/fsharp/issues/17134), [Issue #16309](https://github.com/dotnet/fsharp/issues/16309), [PR #17113](https://github.com/dotnet/fsharp/pull/17113))

### Added

Expand Down
30 changes: 17 additions & 13 deletions src/Compiler/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -2558,6 +2558,10 @@ opt_explicitValTyparDecls:
|
{ SynValTyparDecls(None, true) }

hashConstraint:
| HASH atomType
{ SynType.HashConstraint($2, lhs parseState) }

/* Any tokens in this grammar must be added to the lex filter rule 'peekAdjacentTypars' */
/* See the F# specification "Lexical analysis of type applications and type parameter definitions" */
opt_typeConstraints:
Expand All @@ -2579,20 +2583,20 @@ typeConstraints:
/* Any tokens in this grammar must be added to the lex filter rule 'peekAdjacentTypars' */
/* See the F# specification "Lexical analysis of type applications and type parameter definitions" */
intersectionConstraints:
| intersectionConstraints AMP atomType %prec prec_no_more_attr_bindings // todo precedence
| intersectionConstraints AMP hashConstraint %prec prec_no_more_attr_bindings
{ let constraints, mAmpersands = $1
($3 :: constraints), (rhs parseState 2 :: mAmpersands) }

match $3 with
| SynType.HashConstraint _ -> ()
| ty -> errorR(Error(FSComp.SR.parsConstraintIntersectionSyntaxUsedWithNonFlexibleType(), ty.Range))

| intersectionConstraints AMP atomType %prec prec_no_more_attr_bindings
{ let constraints, mAmpersands = $1
errorR(Error(FSComp.SR.parsConstraintIntersectionSyntaxUsedWithNonFlexibleType(), $3.Range))
($3 :: constraints), (rhs parseState 2 :: mAmpersands) }

| atomType
{ match $1 with
| SynType.HashConstraint _ -> ()
| ty -> errorR(Error(FSComp.SR.parsConstraintIntersectionSyntaxUsedWithNonFlexibleType(), ty.Range))
| hashConstraint
{ [ $1 ], [] }

| atomType
{ errorR(Error(FSComp.SR.parsConstraintIntersectionSyntaxUsedWithNonFlexibleType(), $1.Range))
[ $1 ], [] }

/* Any tokens in this grammar must be added to the lex filter rule 'peekAdjacentTypars' */
Expand Down Expand Up @@ -5993,11 +5997,11 @@ tupleOrQuotTypeElements:
{ [ SynTupleTypeSegment.Type $1 ] }

intersectionType:
| typar AMP intersectionConstraints %prec prec_no_more_attr_bindings // todo precedence
| typar AMP intersectionConstraints %prec prec_no_more_attr_bindings
{ let constraints, mAmpersands = $3
SynType.Intersection(Some $1, List.rev constraints, lhs parseState, { AmpersandRanges = rhs parseState 2 :: List.rev mAmpersands }) }

| atomType AMP intersectionConstraints %prec prec_no_more_attr_bindings // todo precedence
| hashConstraint AMP intersectionConstraints %prec prec_no_more_attr_bindings
{ let constraints, mAmpersands = $3
SynType.Intersection(None, $1 :: List.rev constraints, lhs parseState, { AmpersandRanges = rhs parseState 2 :: List.rev mAmpersands }) }

Expand Down Expand Up @@ -6213,8 +6217,8 @@ atomTypeOrAnonRecdType:
/* Any tokens in this grammar must be added to the lex filter rule 'peekAdjacentTypars' */
/* See the F# specification "Lexical analysis of type applications and type parameter definitions" */
atomType:
| HASH atomType
{ SynType.HashConstraint($2, lhs parseState) }
| hashConstraint
{ $1 }

| appTypeConPower %prec prec_atomtyp_path
{ $1 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ module And =
|> typecheck
|> shouldSucceed

[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"andPattern04.fs"|])>]
let ``And - andPattern04_fs`` compilation =
compilation
|> asFs
|> typecheck
|> shouldSucceed

// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/And)
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"E_IdentBoundTwice.fs"|])>]
let ``And - E_IdentBoundTwice_fs - --test:ErrorRanges`` compilation =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// #Conformance #PatternMatching #PatternMatchingGuards

open System

let x: Result<unit, exn> = Error (NullReferenceException())

match x with
| Error (_: exn & :? NullReferenceException) -> printfn "NullRef"
| _ -> ()
psfinaki marked this conversation as resolved.
Show resolved Hide resolved

match x with
| Error (_: exn & (:? NullReferenceException)) -> printfn "NullRef"
| _ -> ()

match x with
| Error ((_: exn) & :? NullReferenceException) -> printfn "NullRef"
| _ -> ()

match x with
| Error ((_: exn) & (:? NullReferenceException)) -> printfn "NullRef"
| _ -> ()
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,31 @@ module Named =
|> withOptions ["--test:ErrorRanges"]
|> typecheck
|> shouldSucceed

[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"activePatterns09.fs"|])>]
let ``Named - activePatterns09_fs`` compilation =
compilation
|> asFs
|> typecheck
|> shouldSucceed

[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"activePatterns10.fs"|])>]
let ``Named - activePatterns10_fs`` compilation =
compilation
|> asFs
|> typecheck
|> shouldFail
|> withDiagnostics [
(Warning 25, Line 6, Col 5, Line 6, Col 26, "Incomplete pattern matches on this expression.")
(Warning 25, Line 7, Col 5, Line 7, Col 28, "Incomplete pattern matches on this expression.")
(Warning 25, Line 8, Col 5, Line 8, Col 28, "Incomplete pattern matches on this expression.")
(Warning 25, Line 9, Col 5, Line 9, Col 30, "Incomplete pattern matches on this expression.")
(Warning 25, Line 13, Col 5, Line 13, Col 22, "Incomplete pattern matches on this expression. For example, the value '``some-other-subtype``' may indicate a case not covered by the pattern(s).")
(Warning 25, Line 14, Col 5, Line 14, Col 24, "Incomplete pattern matches on this expression. For example, the value '``some-other-subtype``' may indicate a case not covered by the pattern(s).")
(Warning 25, Line 15, Col 5, Line 15, Col 24, "Incomplete pattern matches on this expression. For example, the value '``some-other-subtype``' may indicate a case not covered by the pattern(s).")
(Warning 25, Line 16, Col 5, Line 16, Col 26, "Incomplete pattern matches on this expression. For example, the value '``some-other-subtype``' may indicate a case not covered by the pattern(s).")
]

// This test was automatically generated (moved from FSharpQA suite - Conformance/PatternMatching/Named)
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"ActivePatternUnconstrained01.fs"|])>]
let ``Named - ActivePatternUnconstrained01_fs - --test:ErrorRanges`` compilation =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// #Conformance #PatternMatching #ActivePatterns
#light

// Verify AND on active patterns with exceptions

let (_ : exn & Failure _ | _) = exn ()
let ((_ : exn) & (Failure _) | (_)) = exn ()
let (_ : exn & (Failure _) | _) = exn ()
let ((_ : exn) & Failure _ | (_)) = exn ()

exception MyExn

let (_ : exn & MyExn | _) = exn ()
let ((_ : exn) & (MyExn) | (_)) = exn ()
let (_ : exn & (MyExn) | _) = exn ()
let ((_ : exn) & MyExn | (_)) = exn ()

exit 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// #Conformance #PatternMatching #ActivePatterns
#light

// Verify AND on incomplete active patterns with exceptions

let (_ : exn & Failure _) = exn ()
let ((_ : exn) & Failure _) = exn ()
let (_ : exn & (Failure _)) = exn ()
let ((_ : exn) & (Failure _)) = exn ()

exception MyExn

let (_ : exn & MyExn) = exn ()
let ((_ : exn) & MyExn) = exn ()
let (_ : exn & (MyExn)) = exn ()
let ((_ : exn) & (MyExn)) = exn ()

exit 0
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,18 @@ let y (f: #seq<int> & System.IDisposable) = ()
|> withDiagnostics [
Error 3572, Line 2, Col 25, Line 2, Col 43, "Constraint intersection syntax may only be used with flexible types, e.g. '#IDisposable & #ISomeInterface'."
Error 3572, Line 4, Col 23, Line 4, Col 41, "Constraint intersection syntax may only be used with flexible types, e.g. '#IDisposable & #ISomeInterface'."
]
]

// bug 16309
[<Fact>]
let ``Constraint intersection handles invalid types``() =
FSharp """
let f (x: 't when 't :> ABRAKADABRAA & #seq<int>) = ()
"""
|> withLangVersion80
|> typecheck
|> shouldFail
|> withDiagnostics [
Error 0010, Line 2, Col 40, Line 2, Col 41, "Unexpected symbol # in pattern"
Error 0583, Line 2, Col 7, Line 2, Col 8, "Unmatched '('"
]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let (_ : exn & Failure _) = exn ()
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
ImplFile
(ParsedImplFileInput
("/root/OperatorName/ActivePatternAnd 01.fs", false,
QualifiedNameOfFile ActivePatternAnd 01, [], [],
[SynModuleOrNamespace
([ActivePatternAnd 01], false, AnonModule,
[Let
(false,
[SynBinding
(None, Normal, false, false, [],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector),
SynValData
(None, SynValInfo ([], SynArgInfo ([], false, None)), None),
Paren
(Ands
([Typed
(Wild (1,5--1,6),
LongIdent (SynLongIdent ([exn], [], [None])),
(1,5--1,12));
LongIdent
(SynLongIdent ([Failure], [], [None]), None, None,
Pats [Wild (1,23--1,24)], None, (1,15--1,24))],
(1,5--1,24)), (1,4--1,25)), None,
App
(NonAtomic, false, Ident exn, Const (Unit, (1,32--1,34)),
(1,28--1,34)), (1,4--1,25), Yes (1,0--1,34),
{ LeadingKeyword = Let (1,0--1,3)
InlineKeyword = None
EqualsRange = Some (1,26--1,27) })], (1,0--1,34))],
PreXmlDocEmpty, [], None, (1,0--1,34), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))

(1,0)-(1,34) parse warning The declarations in this file will be placed in an implicit module 'ActivePatternAnd 01' based on the file name 'ActivePatternAnd 01.fs'. However this is not a valid F# identifier, so the contents will not be accessible from other files. Consider renaming the file or adding a 'module' or 'namespace' declaration at the top of the file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let ((_ : exn) & Failure _) = exn ()
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
ImplFile
(ParsedImplFileInput
("/root/OperatorName/ActivePatternAnd 02.fs", false,
QualifiedNameOfFile ActivePatternAnd 02, [], [],
[SynModuleOrNamespace
([ActivePatternAnd 02], false, AnonModule,
[Let
(false,
[SynBinding
(None, Normal, false, false, [],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector),
SynValData
(None, SynValInfo ([], SynArgInfo ([], false, None)), None),
Paren
(Ands
([Paren
(Typed
(Wild (1,6--1,7),
LongIdent (SynLongIdent ([exn], [], [None])),
(1,6--1,13)), (1,5--1,14));
LongIdent
(SynLongIdent ([Failure], [], [None]), None, None,
Pats [Wild (1,25--1,26)], None, (1,17--1,26))],
(1,5--1,26)), (1,4--1,27)), None,
App
(NonAtomic, false, Ident exn, Const (Unit, (1,34--1,36)),
(1,30--1,36)), (1,4--1,27), Yes (1,0--1,36),
{ LeadingKeyword = Let (1,0--1,3)
InlineKeyword = None
EqualsRange = Some (1,28--1,29) })], (1,0--1,36))],
PreXmlDocEmpty, [], None, (1,0--1,36), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))

(1,0)-(1,36) parse warning The declarations in this file will be placed in an implicit module 'ActivePatternAnd 02' based on the file name 'ActivePatternAnd 02.fs'. However this is not a valid F# identifier, so the contents will not be accessible from other files. Consider renaming the file or adding a 'module' or 'namespace' declaration at the top of the file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let (_ : exn & (Failure _)) = exn ()
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
ImplFile
(ParsedImplFileInput
("/root/OperatorName/ActivePatternAnd 03.fs", false,
QualifiedNameOfFile ActivePatternAnd 03, [], [],
[SynModuleOrNamespace
([ActivePatternAnd 03], false, AnonModule,
[Let
(false,
[SynBinding
(None, Normal, false, false, [],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector),
SynValData
(None, SynValInfo ([], SynArgInfo ([], false, None)), None),
Paren
(Ands
([Typed
(Wild (1,5--1,6),
LongIdent (SynLongIdent ([exn], [], [None])),
(1,5--1,12));
Paren
(LongIdent
(SynLongIdent ([Failure], [], [None]), None, None,
Pats [Wild (1,24--1,25)], None, (1,16--1,25)),
(1,15--1,26))], (1,5--1,26)), (1,4--1,27)), None,
App
(NonAtomic, false, Ident exn, Const (Unit, (1,34--1,36)),
(1,30--1,36)), (1,4--1,27), Yes (1,0--1,36),
{ LeadingKeyword = Let (1,0--1,3)
InlineKeyword = None
EqualsRange = Some (1,28--1,29) })], (1,0--1,36))],
PreXmlDocEmpty, [], None, (1,0--1,36), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))

(1,0)-(1,36) parse warning The declarations in this file will be placed in an implicit module 'ActivePatternAnd 03' based on the file name 'ActivePatternAnd 03.fs'. However this is not a valid F# identifier, so the contents will not be accessible from other files. Consider renaming the file or adding a 'module' or 'namespace' declaration at the top of the file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let ((_ : exn) & (Failure _)) = exn ()
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
ImplFile
(ParsedImplFileInput
("/root/OperatorName/ActivePatternAnd 04.fs", false,
QualifiedNameOfFile ActivePatternAnd 04, [], [],
[SynModuleOrNamespace
([ActivePatternAnd 04], false, AnonModule,
[Let
(false,
[SynBinding
(None, Normal, false, false, [],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector),
SynValData
(None, SynValInfo ([], SynArgInfo ([], false, None)), None),
Paren
(Ands
([Paren
(Typed
(Wild (1,6--1,7),
LongIdent (SynLongIdent ([exn], [], [None])),
(1,6--1,13)), (1,5--1,14));
Paren
(LongIdent
(SynLongIdent ([Failure], [], [None]), None, None,
Pats [Wild (1,26--1,27)], None, (1,18--1,27)),
(1,17--1,28))], (1,5--1,28)), (1,4--1,29)), None,
App
(NonAtomic, false, Ident exn, Const (Unit, (1,36--1,38)),
(1,32--1,38)), (1,4--1,29), Yes (1,0--1,38),
{ LeadingKeyword = Let (1,0--1,3)
InlineKeyword = None
EqualsRange = Some (1,30--1,31) })], (1,0--1,38))],
PreXmlDocEmpty, [], None, (1,0--1,38), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))

(1,0)-(1,38) parse warning The declarations in this file will be placed in an implicit module 'ActivePatternAnd 04' based on the file name 'ActivePatternAnd 04.fs'. However this is not a valid F# identifier, so the contents will not be accessible from other files. Consider renaming the file or adding a 'module' or 'namespace' declaration at the top of the file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let (_ : exn & Failure _ | _) = exn ()
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
ImplFile
(ParsedImplFileInput
("/root/OperatorName/ActivePatternAnd 05.fs", false,
QualifiedNameOfFile ActivePatternAnd 05, [], [],
[SynModuleOrNamespace
([ActivePatternAnd 05], false, AnonModule,
[Let
(false,
[SynBinding
(None, Normal, false, false, [],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector),
SynValData
(None, SynValInfo ([], SynArgInfo ([], false, None)), None),
Paren
(Or
(Ands
([Typed
(Wild (1,5--1,6),
LongIdent (SynLongIdent ([exn], [], [None])),
(1,5--1,12));
LongIdent
(SynLongIdent ([Failure], [], [None]), None, None,
Pats [Wild (1,23--1,24)], None, (1,15--1,24))],
(1,5--1,24)), Wild (1,27--1,28), (1,5--1,28),
{ BarRange = (1,25--1,26) }), (1,4--1,29)), None,
App
(NonAtomic, false, Ident exn, Const (Unit, (1,36--1,38)),
(1,32--1,38)), (1,4--1,29), Yes (1,0--1,38),
{ LeadingKeyword = Let (1,0--1,3)
InlineKeyword = None
EqualsRange = Some (1,30--1,31) })], (1,0--1,38))],
PreXmlDocEmpty, [], None, (1,0--1,38), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))

(1,0)-(1,38) parse warning The declarations in this file will be placed in an implicit module 'ActivePatternAnd 05' based on the file name 'ActivePatternAnd 05.fs'. However this is not a valid F# identifier, so the contents will not be accessible from other files. Consider renaming the file or adding a 'module' or 'namespace' declaration at the top of the file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let ((_ : exn) & (Failure _) | (_)) = exn ()