diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index ed1e382d6c7..d80af52687b 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,5 +1,7 @@ ### Fixed +* Fix internal error "no 'value__' field found for enumeration type" when an `enum` constraint is checked against an enum declared in the same recursive group (`module rec` or an `and` group). The constraint is now solved once the representations of the group are established. ([Issue #14580](https://github.com/dotnet/fsharp/issues/14580), [PR #20454](https://github.com/dotnet/fsharp/pull/20454)) +* Better diagnostic for a bare `enum` constraint: `'T : enum` now reports FS0699 "An 'enum' constraint must be of the form 'enum'" instead of "Unexpected identifier: 'enum (4)'", and parser messages for invalid constraints no longer leak internal ` (2)`/` (3)`/` (4)` markers. ([Issue #14580](https://github.com/dotnet/fsharp/issues/14580), [PR #20454](https://github.com/dotnet/fsharp/pull/20454)) * Fix `NativePtr.stackalloc` nested in a larger expression (e.g. a call argument or the right of an assignment) producing an assembly that throws `InvalidProgramException` at load. ([Issue #8083](https://github.com/dotnet/fsharp/issues/8083), [PR #20302](https://github.com/dotnet/fsharp/pull/20302)) * Fix internal error "Unexpected generalized type variables when compiling an active pattern" when an active pattern is used in a `let` binding whose right-hand side is a generic value, e.g. `let (T) = id`. Such a binding is now checked like the equivalent `match` and is not generalized. ([Issue #16856](https://github.com/dotnet/fsharp/issues/16856), [PR #20383](https://github.com/dotnet/fsharp/pull/20383)) * Fix Release-only (`--optimize+`) `System.InvalidProgramException` from `Seq.collect` / `yield!` over a value-type (struct) collection implementing `seq<'T>` (e.g. `ImmutableArray<_>`) when materialised with `List.ofSeq` / `Seq.toList` / `Seq.toArray` or a list/array comprehension. The collector lowering now boxes a struct sub-collection to `seq<'T>` before calling `AddMany`/`AddManyAndClose` (matching the coercion the type checker already inserts for `yield!`), and uses `unit` as the try/finally result type instead of the body type (removing a spurious `ldnull` store). ([Issue #20203](https://github.com/dotnet/fsharp/issues/20203)) diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index 9e25161892d..9ffc00d3fae 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -3121,7 +3121,22 @@ and SolveTypeIsEnum (csenv: ConstraintSolverEnv) ndeep m2 trace ty underlying = AddConstraint csenv ndeep m2 trace destTypar (TyparConstraint.IsEnum(underlying, m)) | _ -> if isEnumTy g ty then - SolveTypeEqualsTypeKeepAbbrevs csenv ndeep m2 trace underlying (underlyingTypeOfEnumTy g ty) + match tryUnderlyingTypeOfEnumTy g ty with + | ValueSome underlyingTyOfEnum -> + SolveTypeEqualsTypeKeepAbbrevs csenv ndeep m2 trace underlying underlyingTyOfEnum + // The underlying type is unknown until the representations of the recursive group are established + | ValueNone -> + csenv.SolverState.PushPostInferenceCheck( + false, + fun () -> + PostponeOnFailedMemberConstraintResolution + csenv + NoTrace + (fun csenv -> SolveTypeIsEnum csenv ndeep m2 NoTrace ty underlying) + (fun res -> ErrorD(ErrorFromAddingConstraint(denv, res, m))) + |> RaiseOperationResult) + + CompleteD else ErrorD (ConstraintSolverError(FSComp.SR.csTypeIsNotEnumType(NicePrint.minimalRichTextOfType denv ty), m, m2)) diff --git a/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fs b/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fs index fb19654a38b..f37ea1148b0 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fs @@ -1267,12 +1267,12 @@ module internal TypeTesters = | _ -> getErasedTypes g domainTy false @ getErasedTypes g rangeTy false | TType_measure _ -> [ ty ] - let underlyingTypeOfEnumTy (g: TcGlobals) ty = + let tryUnderlyingTypeOfEnumTy (g: TcGlobals) ty = assert (isEnumTy g ty) match metadataOfTy g ty with #if !NO_TYPEPROVIDERS - | ProvidedTypeMetadata info -> info.UnderlyingTypeOfEnum() + | ProvidedTypeMetadata info -> ValueSome(info.UnderlyingTypeOfEnum()) #endif | ILTypeMetadata(TILObjectReprData(_, _, tdef)) -> @@ -1280,25 +1280,30 @@ module internal TypeTesters = let ilTy = getTyOfILEnumInfo info match ilTy.TypeSpec.Name with - | "System.Byte" -> g.byte_ty - | "System.SByte" -> g.sbyte_ty - | "System.Int16" -> g.int16_ty - | "System.Int32" -> g.int32_ty - | "System.Int64" -> g.int64_ty - | "System.UInt16" -> g.uint16_ty - | "System.UInt32" -> g.uint32_ty - | "System.UInt64" -> g.uint64_ty - | "System.Single" -> g.float32_ty - | "System.Double" -> g.float_ty - | "System.Char" -> g.char_ty - | "System.Boolean" -> g.bool_ty - | _ -> g.int32_ty + | "System.Byte" -> ValueSome g.byte_ty + | "System.SByte" -> ValueSome g.sbyte_ty + | "System.Int16" -> ValueSome g.int16_ty + | "System.Int32" -> ValueSome g.int32_ty + | "System.Int64" -> ValueSome g.int64_ty + | "System.UInt16" -> ValueSome g.uint16_ty + | "System.UInt32" -> ValueSome g.uint32_ty + | "System.UInt64" -> ValueSome g.uint64_ty + | "System.Single" -> ValueSome g.float32_ty + | "System.Double" -> ValueSome g.float_ty + | "System.Char" -> ValueSome g.char_ty + | "System.Boolean" -> ValueSome g.bool_ty + | _ -> ValueSome g.int32_ty | FSharpOrArrayOrByrefOrTupleOrExnTypeMetadata -> - let tycon = (tcrefOfAppTy g ty).Deref + match (tcrefOfAppTy g ty).Deref.GetFieldByName "value__" with + | Some rf -> ValueSome rf.FormalType + | None -> ValueNone - match tycon.GetFieldByName "value__" with - | Some rf -> rf.FormalType - | None -> error (InternalError("no 'value__' field found for enumeration type " + tycon.LogicalName, tycon.Range)) + let underlyingTypeOfEnumTy (g: TcGlobals) ty = + match tryUnderlyingTypeOfEnumTy g ty with + | ValueSome underlyingTy -> underlyingTy + | ValueNone -> + let tycon = (tcrefOfAppTy g ty).Deref + error (InternalError("no 'value__' field found for enumeration type " + tycon.LogicalName, tycon.Range)) let normalizeEnumTy g ty = (if isEnumTy g ty then underlyingTypeOfEnumTy g ty else ty) diff --git a/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fsi b/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fsi index de866c4175d..a6a7717865f 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fsi +++ b/src/Compiler/TypedTree/TypedTreeOps.ExprConstruction.fsi @@ -636,6 +636,10 @@ module internal TypeTesters = // Return all components of this type expression that cannot be tested at runtime val getErasedTypes: TcGlobals -> TType -> checkForNullness: bool -> TType list + /// Determine the underlying type of an enum type (normally int32). + /// ValueNone while the representation of an F# enum is still being established. + val tryUnderlyingTypeOfEnumTy: TcGlobals -> TType -> TType voption + /// Determine the underlying type of an enum type (normally int32) val underlyingTypeOfEnumTy: TcGlobals -> TType -> TType diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 8d325fa7537..56e7f2da9ab 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -2719,7 +2719,7 @@ typeConstraint: { SynTypeConstraint.WhereTyparSupportsNull($1, lhs parseState) } | typar COLON IDENT NULL - { if $3 <> "not" then reportParseErrorAt (rhs parseState 3) (FSComp.SR.parsUnexpectedIdentifier($3 + " (2)")) + { if $3 <> "not" then reportParseErrorAt (rhs parseState 3) (FSComp.SR.parsUnexpectedIdentifier($3)) let trivia : SynTypeConstraintWhereTyparNotSupportsNullTrivia = { ColonRange = rhs parseState 2; NotRange = rhs parseState 3 } SynTypeConstraint.WhereTyparNotSupportsNull($1, lhs parseState, trivia) } @@ -2741,14 +2741,15 @@ typeConstraint: | "enum" -> let _ltm, _gtm, args, _commas, mWhole = $4 SynTypeConstraint.WhereTyparIsEnum($1, args, unionRanges $1.Range mWhole) - | nm -> raiseParseErrorAt (rhs parseState 3) (FSComp.SR.parsUnexpectedIdentifier(nm + " (3)")) } + | nm -> raiseParseErrorAt (rhs parseState 3) (FSComp.SR.parsUnexpectedIdentifier(nm)) } | typar COLON IDENT { match $3 with | "comparison" -> SynTypeConstraint.WhereTyparIsComparable($1, lhs parseState) | "equality" -> SynTypeConstraint.WhereTyparIsEquatable($1, lhs parseState) | "unmanaged" -> SynTypeConstraint.WhereTyparIsUnmanaged($1, lhs parseState) - | nm -> raiseParseErrorAt (rhs parseState 3) (FSComp.SR.parsUnexpectedIdentifier(nm + " (4)")) } + | "enum" -> raiseParseErrorAt (rhs parseState 3) (FSComp.SR.tcInvalidEnumConstraint()) + | nm -> raiseParseErrorAt (rhs parseState 3) (FSComp.SR.parsUnexpectedIdentifier(nm)) } | appTypeWithoutNull { SynTypeConstraint.WhereSelfConstrained($1, lhs parseState) } diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Constraints/ConstraintSyntax.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Constraints/ConstraintSyntax.fs new file mode 100644 index 00000000000..65b51ba44d2 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Constraints/ConstraintSyntax.fs @@ -0,0 +1,169 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Conformance.Constraints + +open Xunit +open FSharp.Test.Compiler + +module ConstraintSyntax = + + // https://github.com/dotnet/fsharp/issues/14580 + [] + let ``Bare 'enum' constraint reports the enum constraint form error`` () = + Fsx """ +type I<'T when 'T : enum> = interface end + """ + |> withOptions ["--test:ErrorRanges"] + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 699, Line 2, Col 21, Line 2, Col 25, "An 'enum' constraint must be of the form 'enum'") + + [] + let ``Unknown identifier constraint reports the identifier without internal markers`` () = + Fsx """ +type I<'T when 'T : notAConstraint> = interface end + """ + |> withOptions ["--test:ErrorRanges"] + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 571, Line 2, Col 21, Line 2, Col 35, "Unexpected identifier: 'notAConstraint'") + + [] + let ``Unknown identifier constraint with type arguments reports the identifier without internal markers`` () = + Fsx """ +type I<'T when 'T : notAConstraint> = interface end + """ + |> withOptions ["--test:ErrorRanges"] + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 571, Line 2, Col 21, Line 2, Col 35, "Unexpected identifier: 'notAConstraint'") + + [] + let ``Unknown identifier before 'null' constraint reports the identifier without internal markers`` () = + Fsx """ +type I<'T when 'T : maybe null> = interface end + """ + |> withOptions ["--test:ErrorRanges"] + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 571, Line 2, Col 21, Line 2, Col 26, "Unexpected identifier: 'maybe'") + + [] + let ``'enum' constraint with an underlying type is accepted`` () = + Fsx """ +type I<'T when 'T : enum> = interface end +type E = A = 1 +type Ok = I + """ + |> typecheck + |> shouldSucceed + + // https://github.com/dotnet/fsharp/issues/14580 + [] + let ``'enum' constraint on a type of the same recursive group is accepted`` () = + FSharp """ +module rec MyModule + +type MyEnum = + | Alpha = 1 + | Beta = 2 + +type MyInter<'TEnum when 'TEnum : enum> = interface end + +type MyAlias = MyInter + """ + |> asLibrary + |> compile + |> shouldSucceed + + [] + let ``'enum' constraint on a type of the same 'and' group is accepted`` () = + FSharp """ +module MyModule + +type MyEnum = + | Alpha = 1 + | Beta = 2 + +and MyInter<'TEnum when 'TEnum : enum> = interface end + +and MyAlias = MyInter + """ + |> asLibrary + |> compile + |> shouldSucceed + + [] + let ``'enum' constraint on an inherited interface of the same recursive group is accepted`` () = + FSharp """ +module rec MyModule + +type MyEnum = + | Alpha = 1 + +type MyInter<'TEnum when 'TEnum : enum> = interface end + +type C() = + interface MyInter + """ + |> asLibrary + |> compile + |> shouldSucceed + + [] + let ``Mismatched 'enum' constraint on a type of the same recursive group is reported`` () = + FSharp """ +module rec MyModule + +type MyEnum = + | Alpha = 1 + +type MyInter<'TEnum when 'TEnum : enum> = interface end + +type MyAlias = MyInter + """ + |> asLibrary + |> withOptions ["--test:ErrorRanges"] + |> typecheck + |> shouldFail + |> withDiagnosticMessageMatches "The type 'int64' does not match the type 'int'" + + [] + let ``Mismatched 'enum' constraint outside a recursive group is reported`` () = + FSharp """ +module MyModule + +type MyEnum = + | Alpha = 1 + +type MyInter<'TEnum when 'TEnum : enum> = interface end + +type MyAlias = MyInter + """ + |> asLibrary + |> withOptions ["--test:ErrorRanges"] + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 1, Line 9, Col 16, Line 9, Col 31, "The type 'int64' does not match the type 'int'") + + [] + let ``Generic code over an 'enum' constraint in a recursive module runs`` () = + FSharp """ +module rec MyModule + +type Color = + | Red = 1 + | Blue = 4 + +let combine<'T when 'T : enum> (a: 'T) (b: 'T) : 'T = + LanguagePrimitives.EnumOfValue (LanguagePrimitives.EnumToValue a ||| LanguagePrimitives.EnumToValue b) + +[] +let main _ = + if LanguagePrimitives.EnumToValue (combine Color.Red Color.Blue) <> 5 then + failwith "expected Red ||| Blue to be 5" + 0 + """ + |> asExe + |> compileExeAndRun + |> shouldSucceed diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index cc7e109373f..c621468851e 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -84,6 +84,7 @@ + diff --git a/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Enum 01.fs b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Enum 01.fs new file mode 100644 index 00000000000..4f37c6b40c9 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Enum 01.fs @@ -0,0 +1,3 @@ +module Module + +type I<'T when 'T : enum> = interface end diff --git a/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Enum 01.fs.bsl b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Enum 01.fs.bsl new file mode 100644 index 00000000000..9a072d592f4 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Enum 01.fs.bsl @@ -0,0 +1,23 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynTyparDecl/Constraint - Enum 01.fs", false, + QualifiedNameOfFile Module, [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Types + ([SynTypeDefn + (SynComponentInfo + ([], None, [], None, + PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), + false, None, (3,5--3,25)), + ObjectModel (Interface, [], (3,28--3,41)), [], None, + (3,5--3,41), { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,26--3,27) + WithKeyword = None })], (3,0--3,41))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--3,41), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + WarnDirectives = [] + CodeComments = [] }, set [])) + +(3,20)-(3,24) parse error An 'enum' constraint must be of the form 'enum' diff --git a/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 01.fs b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 01.fs new file mode 100644 index 00000000000..84baff9a18a --- /dev/null +++ b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 01.fs @@ -0,0 +1,3 @@ +module Module + +type I<'T when 'T : notAConstraint> = interface end diff --git a/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 01.fs.bsl b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 01.fs.bsl new file mode 100644 index 00000000000..d155c15dec3 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 01.fs.bsl @@ -0,0 +1,23 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynTyparDecl/Constraint - Unknown identifier 01.fs", false, + QualifiedNameOfFile Module, [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Types + ([SynTypeDefn + (SynComponentInfo + ([], None, [], None, + PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), + false, None, (3,5--3,35)), + ObjectModel (Interface, [], (3,38--3,51)), [], None, + (3,5--3,51), { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,36--3,37) + WithKeyword = None })], (3,0--3,51))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--3,51), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + WarnDirectives = [] + CodeComments = [] }, set [])) + +(3,20)-(3,34) parse error Unexpected identifier: 'notAConstraint' diff --git a/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 02.fs b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 02.fs new file mode 100644 index 00000000000..b5fbfaa09bc --- /dev/null +++ b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 02.fs @@ -0,0 +1,3 @@ +module Module + +type I<'T when 'T : notAConstraint> = interface end diff --git a/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 02.fs.bsl b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 02.fs.bsl new file mode 100644 index 00000000000..4ab9f81fc49 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 02.fs.bsl @@ -0,0 +1,23 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynTyparDecl/Constraint - Unknown identifier 02.fs", false, + QualifiedNameOfFile Module, [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Types + ([SynTypeDefn + (SynComponentInfo + ([], None, [], None, + PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), + false, None, (3,5--3,39)), + ObjectModel (Interface, [], (3,43--3,56)), [], None, + (3,5--3,56), { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,41--3,42) + WithKeyword = None })], (3,0--3,56))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--3,56), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + WarnDirectives = [] + CodeComments = [] }, set [])) + +(3,20)-(3,34) parse error Unexpected identifier: 'notAConstraint' diff --git a/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 03.fs b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 03.fs new file mode 100644 index 00000000000..da6caf02a35 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 03.fs @@ -0,0 +1,3 @@ +module Module + +type I<'T when 'T : maybe null> = interface end diff --git a/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 03.fs.bsl b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 03.fs.bsl new file mode 100644 index 00000000000..92b03773acd --- /dev/null +++ b/tests/service/data/SyntaxTree/SynTyparDecl/Constraint - Unknown identifier 03.fs.bsl @@ -0,0 +1,33 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynTyparDecl/Constraint - Unknown identifier 03.fs", false, + QualifiedNameOfFile Module, [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Types + ([SynTypeDefn + (SynComponentInfo + ([], + Some + (PostfixList + ([SynTyparDecl + ([], SynTypar (T, None, false), [], + { AmpersandRanges = [] })], + [WhereTyparNotSupportsNull + (SynTypar (T, None, false), (3,15--3,30), + { ColonRange = (3,18--3,19) + NotRange = (3,20--3,25) })], (3,6--3,31))), [], + Some (LongIdent (SynLongIdent ([I], [], [None]))), + PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), + true, None, (3,5--3,6)), + ObjectModel (Interface, [], (3,34--3,47)), [], None, + (3,5--3,47), { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,32--3,33) + WithKeyword = None })], (3,0--3,47))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--3,47), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + WarnDirectives = [] + CodeComments = [] }, set [])) + +(3,20)-(3,25) parse error Unexpected identifier: 'maybe'