diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md index 674a2ec7d47..17ccb2f4019 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md @@ -1,6 +1,7 @@ ### Fixed * Improve error reporting for abstract members when used in classes. ([PR #17063](https://github.com/dotnet/fsharp/pull/17063)) +* Improve error reporting when property has same name as DU case. ([Issue #16646](https://github.com/dotnet/fsharp/issues/16646), [PR #17088](https://github.com/dotnet/fsharp/pull/17088)) * Make typechecking of indexed setters with tuples on the right more consistent. ([Issue #16987](https://github.com/dotnet/fsharp/issues/16987), [PR #17017](https://github.com/dotnet/fsharp/pull/17017)) * Static abstract method on classes no longer yields internal error. ([Issue #17044](https://github.com/dotnet/fsharp/issues/17044), [PR #17055](https://github.com/dotnet/fsharp/pull/17055)) * Disallow calling abstract methods directly on interfaces. ([Issue #14012](https://github.com/dotnet/fsharp/issues/14012), [Issue #16299](https://github.com/dotnet/fsharp/issues/16299), [PR #17021](https://github.com/dotnet/fsharp/pull/17021)) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 2acbb45097e..16e46ae706b 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -9411,7 +9411,16 @@ and TcLookupItemThen cenv overallTy env tpenv mObjExpr objExpr objExprTy delayed TcTraitItemThen cenv overallTy env (Some objExpr) traitInfo tpenv mItem delayed | Item.DelegateCtor _ -> error (Error (FSComp.SR.tcConstructorsCannotBeFirstClassValues(), mItem)) + + | Item.UnionCase(info, _) -> + let clashingNames = info.Tycon.MembersOfFSharpTyconSorted |> List.tryFind(fun mem -> mem.DisplayNameCore = info.DisplayNameCore) + match clashingNames with + | None -> () + | Some value -> + let kind = if value.IsMember then "member" else "value" + errorR (NameClash(info.DisplayNameCore, kind, info.DisplayNameCore, value.Range, FSComp.SR.typeInfoUnionCase(), info.DisplayNameCore, value.Range)) + error (Error (FSComp.SR.tcSyntaxFormUsedOnlyWithRecordLabelsPropertiesAndFields(), mItem)) // These items are not expected here - they can't be the result of a instance member dot-lookup "expr.Ident" | Item.ActivePatternResult _ | Item.CustomOperation _ @@ -9421,7 +9430,6 @@ and TcLookupItemThen cenv overallTy env tpenv mObjExpr objExpr objExprTy delayed | Item.ModuleOrNamespaces _ | Item.TypeVar _ | Item.Types _ - | Item.UnionCase _ | Item.UnionCaseField _ | Item.UnqualifiedType _ | Item.Value _ diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs index 75ee664d938..fb11a41005d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs @@ -721,3 +721,33 @@ type U = |> shouldFail |> withSingleDiagnostic (Error 912, Line 4, Col 3, Line 4, Col 28, "This declaration element is not permitted in an augmentation") + + [] + let ``Error when property has same name as DU case`` () = + Fsx """ +type MyId = + | IdA of int + | IdB of string + | IdC of float + + member this.IdA = + match this with + | IdA x -> Some x + | _ -> None + + member this.IdX = + match this with + | IdB x -> Some x + | _ -> None + + member this.IdC = + match this with + | IdC x -> Some x + | _ -> None + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 23, Line 7, Col 17, Line 7, Col 20, "The member 'IdA' can not be defined because the name 'IdA' clashes with the union case 'IdA' in this type or module") + (Error 23, Line 17, Col 17, Line 17, Col 20, "The member 'IdC' can not be defined because the name 'IdC' clashes with the union case 'IdC' in this type or module") + ] diff --git a/tests/FSharp.Compiler.ComponentTests/Language/DotLambdaTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/DotLambdaTests.fs index 6dff28ab6a7..3d2333ec9a4 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/DotLambdaTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/DotLambdaTests.fs @@ -290,4 +290,40 @@ let _ = asQ.Select _.Length """ |> withLangVersion80 |> typecheck - |> shouldSucceed \ No newline at end of file + |> shouldSucceed + +[] + let ``Error when property has same name as DU case`` () = + Fsx """ +type MyId = + | IdA of int + | IdB of string + | IdC of float + + member this.IdA = + match this with + | IdA x -> Some x + | _ -> None + + member this.IdX = + match this with + | IdB x -> Some x + | _ -> None + + member this.IdC = + match this with + | IdC x -> Some x + | _ -> None + +let onlyIdA (ids: MyId list) = ids |> List.choose _.IdA +let onlyIdX (ids: MyId list) = ids |> List.choose _.IdX +let onlyIdC (ids: MyId list) = ids |> List.choose _.IdC + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 23, Line 7, Col 17, Line 7, Col 20, "The member 'IdA' can not be defined because the name 'IdA' clashes with the union case 'IdA' in this type or module"); + (Error 812, Line 22, Col 51, Line 22, Col 56, "The syntax 'expr.id' may only be used with record labels, properties and fields"); + (Error 23, Line 17, Col 17, Line 17, Col 20, "The member 'IdC' can not be defined because the name 'IdC' clashes with the union case 'IdC' in this type or module"); + (Error 812, Line 24, Col 51, Line 24, Col 56, "The syntax 'expr.id' may only be used with record labels, properties and fields") + ] \ No newline at end of file