diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index a8acd94267c..85defc1dbf6 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1498,6 +1498,7 @@ notAFunctionButMaybeDeclaration,"This value is not a function and cannot be appl 3351,chkFeatureNotRuntimeSupported,"Feature '%s' is not supported by target runtime." 3352,typrelInterfaceMemberNoMostSpecificImplementation,"Interface member '%s' does not have a most specific implementation." 3353,chkFeatureNotSupportedInLibrary,"Feature '%s' requires the F# library for language version %s or greater." +3360,parsEqualsMissingInTypeDefinition,"Unexpected token in type definition. Expected '=' after the type '%s'." useSdkRefs,"Use reference assemblies for .NET framework references when available (Enabled by default)." optsLangVersion,"Display the allowed values for language version, specify language version such as 'latest' or 'preview'" optsSupportedLangVersions,"Supported language versions:" diff --git a/src/fsharp/pars.fsy b/src/fsharp/pars.fsy index c9b4a5861bf..c6344e5104d 100644 --- a/src/fsharp/pars.fsy +++ b/src/fsharp/pars.fsy @@ -1496,8 +1496,14 @@ tyconDefn: | typeNameInfo { TypeDefn($1, SynTypeDefnRepr.Simple(SynTypeDefnSimpleRepr.None($1.Range), $1.Range), [], $1.Range) } - | typeNameInfo EQUALS tyconDefnRhsBlock - { let nameRange = rhs parseState 1 + | typeNameInfo opt_equals tyconDefnRhsBlock + { if not $2 then ( + let (ComponentInfo(_, _, _, lid, _, _, _, _)) = $1 + // While the spec doesn't allow long idents here, the parser doesn't enforce this, so take one ident + let typeNameId = List.last lid + raiseParseErrorAt (rhs parseState 2) (FSComp.SR.parsEqualsMissingInTypeDefinition(typeNameId.ToString())) + ) + let nameRange = rhs parseState 1 let (tcDefRepr:SynTypeDefnRepr), members = $3 nameRange let declRange = unionRanges (rhs parseState 1) tcDefRepr.Range let mWhole = (declRange, members) ||> unionRangeWithListBy (fun (mem:SynMemberDefn) -> mem.Range) @@ -5445,6 +5451,10 @@ deprecated_opt_equals: | EQUALS { deprecatedWithError (FSComp.SR.parsNoEqualShouldFollowNamespace()) (lhs parseState); () } | /* EMPTY */ { } +opt_equals: + | EQUALS { true } + | /* EMPTY */ { false } + opt_OBLOCKSEP: | OBLOCKSEP { } | /* EMPTY */ { } diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs new file mode 100644 index 00000000000..70d7beebc92 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.ComponentTests.ErrorMessages + +open Xunit +open FSharp.Test.Utilities +open FSharp.Compiler.SourceCodeServices + + +module ``Type definition missing equals`` = + + [] + let ``Missing equals in DU``() = + CompilerAssert.TypeCheckSingleError + """ +type X | A | B + """ + FSharpErrorSeverity.Error + 3360 + (2, 8, 2, 9) + "Unexpected token in type definition. Expected '=' after the type 'X'." diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 74d960c1c92..440a4e8cf94 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -22,6 +22,7 @@ +