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 b24a17b85fb..124baf0dd6e 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md @@ -1,7 +1,8 @@ ### Fixed +* 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)) -* Various parenthesization API fixes. ([PR #16977](https://github.com/dotnet/fsharp/pull/16977)) +* Various parenthesization API fixes. ([PR #16977](https://github.com/dotnet/fsharp/pull/16977)) * Fix bug in optimization of for-loops over integral ranges with steps and units of measure. ([Issue #17025](https://github.com/dotnet/fsharp/issues/17025), [PR #17040](https://github.com/dotnet/fsharp/pull/17040), [PR #17048](https://github.com/dotnet/fsharp/pull/17048)) * Fix calling an overridden virtual static method via the interface ([PR #17013](https://github.com/dotnet/fsharp/pull/17013)) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 4f7b56ebf11..3466b162c3a 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -5412,7 +5412,10 @@ and TcExprThen (cenv: cenv) overallTy env tpenv isArg synExpr delayed = TcNonControlFlowExpr env <| fun env -> if g.langVersion.SupportsFeature LanguageFeature.IndexerNotationWithoutDot then warning(Error(FSComp.SR.tcIndexNotationDeprecated(), mDot)) - TcIndexerThen cenv env overallTy mWholeExpr mDot tpenv (Some (expr3, mOfLeftOfSet)) expr1 indexArgs delayed + // Wrap in extra parens: like MakeDelayedSet, + // but we don't actually want to delay it here. + let setInfo = SynExpr.Paren (expr3, range0, None, expr3.Range), mOfLeftOfSet + TcIndexerThen cenv env overallTy mWholeExpr mDot tpenv (Some setInfo) expr1 indexArgs delayed // Part of 'T.Ident | SynExpr.Typar (typar, m) -> @@ -5827,7 +5830,10 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE // synExpr1.longId(synExpr2) <- expr3, very rarely used named property setters | SynExpr.DotNamedIndexedPropertySet (synExpr1, synLongId, synExpr2, expr3, mStmt) -> TcNonControlFlowExpr env <| fun env -> - TcExprDotNamedIndexedPropertySet cenv overallTy env tpenv (synExpr1, synLongId, synExpr2, expr3, mStmt) + // Wrap in extra parens: like MakeDelayedSet, + // but we don't actually want to delay it here. + let setInfo = SynExpr.Paren (expr3, range0, None, expr3.Range) + TcExprDotNamedIndexedPropertySet cenv overallTy env tpenv (synExpr1, synLongId, synExpr2, setInfo, mStmt) | SynExpr.LongIdentSet (synLongId, synExpr2, m) -> TcNonControlFlowExpr env <| fun env -> @@ -5836,7 +5842,10 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE // Type.Items(synExpr1) <- synExpr2 | SynExpr.NamedIndexedPropertySet (synLongId, synExpr1, synExpr2, mStmt) -> TcNonControlFlowExpr env <| fun env -> - TcExprNamedIndexPropertySet cenv overallTy env tpenv (synLongId, synExpr1, synExpr2, mStmt) + // Wrap in extra parens: like MakeDelayedSet, + // but we don't actually want to delay it here. + let setInfo = SynExpr.Paren (synExpr2, range0, None, synExpr2.Range) + TcExprNamedIndexPropertySet cenv overallTy env tpenv (synLongId, synExpr1, setInfo, mStmt) | SynExpr.TraitCall (TypesForTypar tps, synMemberSig, arg, m) -> TcNonControlFlowExpr env <| fun env -> diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 4f04946a466..ddafa873e23 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -233,6 +233,7 @@ + diff --git a/tests/FSharp.Compiler.ComponentTests/Language/IndexedSetTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/IndexedSetTests.fs new file mode 100644 index 00000000000..573685aabd9 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/IndexedSetTests.fs @@ -0,0 +1,182 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +module Language.IndexedSetTests + +open FSharp.Test.Compiler +open Xunit + +module Array = + [] + let ``Dotless indexed set of parenthesized tuple compiles`` () = + FSharp " + let xs = Array.zeroCreate 1 + xs[0] <- (1, 2, 3) + " + |> typecheck + |> shouldSucceed + + [] + let ``Dotless indexed set of unparenthesized tuple compiles`` () = + FSharp " + let xs = Array.zeroCreate 1 + xs[0] <- 1, 2, 3 + " + |> typecheck + |> shouldSucceed + + [] + let ``Dotless indexed set of double-parenthesized tuple compiles`` () = + FSharp " + let xs = Array.zeroCreate 1 + xs[0] <- ((1, 2, 3)) + " + |> typecheck + |> shouldSucceed + + [] + let ``Dot-indexed set of parenthesized tuple compiles`` () = + FSharp " + let xs = Array.zeroCreate 1 + xs.[0] <- (1, 2, 3) + " + |> typecheck + |> shouldSucceed + + [] + let ``Dot-indexed set of unparenthesized tuple compiles`` () = + FSharp " + let xs = Array.zeroCreate 1 + xs.[0] <- 1, 2, 3 + " + |> typecheck + |> shouldSucceed + + [] + let ``Dot-indexed set of double-parenthesized tuple compiles`` () = + FSharp " + let xs = Array.zeroCreate 1 + xs.[0] <- ((1, 2, 3)) + " + |> typecheck + |> shouldSucceed + +module Dictionary = + // Parsed as SynExpr.Set. + [] + let ``Dotless indexed set of parenthesized tuple compiles`` () = + FSharp " + let xs = System.Collections.Generic.Dictionary () + xs[0] <- (1, 2, 3) + " + |> typecheck + |> shouldSucceed + + // Parsed as SynExpr.Set. + [] + let ``Dotless indexed set of unparenthesized tuple compiles`` () = + FSharp " + let xs = System.Collections.Generic.Dictionary () + xs[0] <- 1, 2, 3 + " + |> typecheck + |> shouldSucceed + + // Parsed as SynExpr.Set. + [] + let ``Dotless indexed set of double-parenthesized tuple compiles`` () = + FSharp " + let xs = System.Collections.Generic.Dictionary () + xs[0] <- ((1, 2, 3)) + " + |> typecheck + |> shouldSucceed + + // Parsed as SynExpr.DotIndexedSet. + [] + let ``Dot-indexed set of parenthesized tuple compiles`` () = + FSharp " + let xs = System.Collections.Generic.Dictionary () + xs.[0] <- (1, 2, 3) + " + |> typecheck + |> shouldSucceed + + // Parsed as SynExpr.DotIndexedSet. + [] + let ``Dot-indexed set of unparenthesized tuple compiles`` () = + FSharp " + let xs = System.Collections.Generic.Dictionary () + xs.[0] <- 1, 2, 3 + " + |> typecheck + |> shouldSucceed + + // Parsed as SynExpr.DotIndexedSet. + [] + let ``Dot-indexed set of double-parenthesized tuple compiles`` () = + FSharp " + let xs = System.Collections.Generic.Dictionary () + xs.[0] <- ((1, 2, 3)) + " + |> typecheck + |> shouldSucceed + + // Parsed as SynExpr.NamedIndexedPropertySet. + [] + let ``Named indexed property set of parenthesized tuple compiles`` () = + FSharp " + let xs = System.Collections.Generic.Dictionary () + xs.Item 0 <- (1, 2, 3) + " + |> typecheck + |> shouldSucceed + + // Parsed as SynExpr.NamedIndexedPropertySet. + [] + let ``Named indexed property set of unparenthesized tuple compiles`` () = + FSharp " + let xs = System.Collections.Generic.Dictionary () + xs.Item 0 <- 1, 2, 3 + " + |> typecheck + |> shouldSucceed + + // Parsed as SynExpr.NamedIndexedPropertySet. + [] + let ``Named indexed property set of double-parenthesized tuple compiles`` () = + FSharp " + let xs = System.Collections.Generic.Dictionary () + xs.Item 0 <- ((1, 2, 3)) + " + |> typecheck + |> shouldSucceed + + // Parsed as SynExpr.DotNamedIndexedPropertySet. + [] + let ``Dot-named indexed property set of parenthesized tuple compiles`` () = + FSharp " + let xs = System.Collections.Generic.Dictionary () + (xs).Item 0 <- (1, 2, 3) + " + |> typecheck + |> shouldSucceed + + // Parsed as SynExpr.DotNamedIndexedPropertySet. + [] + let ``Dot-named indexed property set of unparenthesized tuple compiles`` () = + FSharp " + let xs = System.Collections.Generic.Dictionary () + (xs).Item 0 <- 1, 2, 3 + " + |> typecheck + |> shouldSucceed + + // Parsed as SynExpr.DotNamedIndexedPropertySet. + [] + let ``Dot-named indexed property set of double-parenthesized tuple compiles`` () = + FSharp " + let xs = System.Collections.Generic.Dictionary () + (xs).Item 0 <- ((1, 2, 3)) + " + |> typecheck + |> shouldSucceed