From 366f3fc075c3460cf10eee1c23eab30be485ca41 Mon Sep 17 00:00:00 2001 From: Thomas Boby Date: Tue, 7 Jul 2020 20:56:11 +0100 Subject: [PATCH 1/5] Improve error reporting: Missing = on type declaration --- src/fsharp/FSComp.txt | 1 + src/fsharp/pars.fsy | 9 ++++++-- .../ErrorMessages/TypeEqualsMissingTests.fs | 21 +++++++++++++++++++ .../FSharp.Compiler.ComponentTests.fsproj | 1 + 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index a8acd94267c..e00d846766a 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 symbol in type definition. Did you forget to use the = operator?" 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..2764d44f99f 100644 --- a/src/fsharp/pars.fsy +++ b/src/fsharp/pars.fsy @@ -1496,8 +1496,9 @@ tyconDefn: | typeNameInfo { TypeDefn($1, SynTypeDefnRepr.Simple(SynTypeDefnSimpleRepr.None($1.Range), $1.Range), [], $1.Range) } - | typeNameInfo EQUALS tyconDefnRhsBlock - { let nameRange = rhs parseState 1 + | typeNameInfo type_opt_equals tyconDefnRhsBlock + { if not $2 then raiseParseErrorAt (rhs parseState 2) (FSComp.SR.parsEqualsMissingInTypeDefinition()) + 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 +5446,10 @@ deprecated_opt_equals: | EQUALS { deprecatedWithError (FSComp.SR.parsNoEqualShouldFollowNamespace()) (lhs parseState); () } | /* EMPTY */ { } +type_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..aea137edf63 --- /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.ErrorMessages.ComponentTests + +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 symbol in type definition. Did you forget to use the = operator?" 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 @@ + From c044bcf9eb727764817167609180da280fb48d89 Mon Sep 17 00:00:00 2001 From: Thomas Boby Date: Sun, 11 Oct 2020 15:25:05 +0100 Subject: [PATCH 2/5] Rename parser rule --- src/fsharp/pars.fsy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fsharp/pars.fsy b/src/fsharp/pars.fsy index 2764d44f99f..e1d1c80e94a 100644 --- a/src/fsharp/pars.fsy +++ b/src/fsharp/pars.fsy @@ -1496,7 +1496,7 @@ tyconDefn: | typeNameInfo { TypeDefn($1, SynTypeDefnRepr.Simple(SynTypeDefnSimpleRepr.None($1.Range), $1.Range), [], $1.Range) } - | typeNameInfo type_opt_equals tyconDefnRhsBlock + | typeNameInfo opt_equals tyconDefnRhsBlock { if not $2 then raiseParseErrorAt (rhs parseState 2) (FSComp.SR.parsEqualsMissingInTypeDefinition()) let nameRange = rhs parseState 1 let (tcDefRepr:SynTypeDefnRepr), members = $3 nameRange @@ -5446,7 +5446,7 @@ deprecated_opt_equals: | EQUALS { deprecatedWithError (FSComp.SR.parsNoEqualShouldFollowNamespace()) (lhs parseState); () } | /* EMPTY */ { } -type_opt_equals: +opt_equals: | EQUALS { true } | /* EMPTY */ { false } From 2d4d77feb0ec34d2b0f2b3a01b886b4c9d366f06 Mon Sep 17 00:00:00 2001 From: Thomas Boby Date: Sun, 11 Oct 2020 15:25:24 +0100 Subject: [PATCH 3/5] Update message to suggested wording --- src/fsharp/FSComp.txt | 2 +- .../ErrorMessages/TypeEqualsMissingTests.fs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index e00d846766a..d59eed8deca 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1498,7 +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 symbol in type definition. Did you forget to use the = operator?" +3360,parsEqualsMissingInTypeDefinition,"Unexpected token in type definition. Expected '='." 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/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs index aea137edf63..89c6c107dea 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs @@ -18,4 +18,4 @@ type X | A | B FSharpErrorSeverity.Error 3360 (2, 8, 2, 9) - "Unexpected symbol in type definition. Did you forget to use the = operator?" + "Unexpected token in type definition. Expected '='." From 601cba66a1647f0a2c216817241312320b05e313 Mon Sep 17 00:00:00 2001 From: Thomas Boby Date: Mon, 12 Oct 2020 10:55:38 +0100 Subject: [PATCH 4/5] Move to correct test namespace --- .../ErrorMessages/TypeEqualsMissingTests.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs index 89c6c107dea..7ee7df956ae 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -namespace FSharp.Compiler.ErrorMessages.ComponentTests +namespace FSharp.Compiler.ComponentTests.ErrorMessages open Xunit open FSharp.Test.Utilities From a125c05182f4f577af3ca6a2c90f31d4150cc789 Mon Sep 17 00:00:00 2001 From: Thomas Boby Date: Mon, 12 Oct 2020 11:55:31 +0100 Subject: [PATCH 5/5] Include typename in error message This is taken from the end of the list of idents. While the spec says this should be an ident not a long-ident, the parser doesn't enforce this, so we assume it has at least one item but don't check. --- src/fsharp/FSComp.txt | 2 +- src/fsharp/pars.fsy | 7 ++++++- .../ErrorMessages/TypeEqualsMissingTests.fs | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index d59eed8deca..85defc1dbf6 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1498,7 +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 '='." +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 e1d1c80e94a..c6344e5104d 100644 --- a/src/fsharp/pars.fsy +++ b/src/fsharp/pars.fsy @@ -1497,7 +1497,12 @@ tyconDefn: { TypeDefn($1, SynTypeDefnRepr.Simple(SynTypeDefnSimpleRepr.None($1.Range), $1.Range), [], $1.Range) } | typeNameInfo opt_equals tyconDefnRhsBlock - { if not $2 then raiseParseErrorAt (rhs parseState 2) (FSComp.SR.parsEqualsMissingInTypeDefinition()) + { 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 diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs index 7ee7df956ae..70d7beebc92 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeEqualsMissingTests.fs @@ -18,4 +18,4 @@ type X | A | B FSharpErrorSeverity.Error 3360 (2, 8, 2, 9) - "Unexpected token in type definition. Expected '='." + "Unexpected token in type definition. Expected '=' after the type 'X'."