diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md index 8aa2e5006de..a3aa6476896 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -27,6 +27,7 @@ * Enforce AttributeTargets on enums ([PR #16887](https://github.com/dotnet/fsharp/pull/16887)) * Completion: fix for unfinished record field decl ([PR #16893](https://github.com/dotnet/fsharp/pull/16893)) * Enforce AttributeTargets on delegates ([PR #16891](https://github.com/dotnet/fsharp/pull/16891)) +* Obsolete attribute is ignored in constructor property assignment ([PR #16900](https://github.com/dotnet/fsharp/pull/16900)) * Completion: fix completion in empty dot lambda prefix ([#16829](https://github.com/dotnet/fsharp/pull/16829)) * Fix StackOverflow when checking non-recursive bindings in module or namespace in `fscAnyCpu`/`fsiAnyCpu`. ([PR #16908](https://github.com/dotnet/fsharp/pull/16908)) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 220e4da4c82..06de913a461 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -10086,7 +10086,6 @@ and TcMethodApplication // Handle post-hoc property assignments let setterExprPrebinders, callExpr2b = let expr = callExpr2 - CheckRequiredProperties g env cenv finalCalledMethInfo finalAssignedItemSetters mMethExpr if isCheckingAttributeCall then @@ -10161,6 +10160,8 @@ and TcSetterArgExpr (cenv: cenv) env denv objExpr ad assignedSetter calledFromCo match setter with | AssignedPropSetter (propStaticTyOpt, pinfo, pminfo, pminst) -> + CheckPropInfoAttributes pinfo id.idRange |> CommitOperationResult + if g.langVersion.SupportsFeature(LanguageFeature.RequiredPropertiesSupport) && pinfo.IsSetterInitOnly && not calledFromConstructor then errorR (Error (FSComp.SR.tcInitOnlyPropertyCannotBeSet1 pinfo.PropertyName, m)) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/ObsoleteAttributeCheckingTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/ObsoleteAttributeCheckingTests.fs index d503daa77e0..f31371a9653 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/ObsoleteAttributeCheckingTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/ObsoleteAttributeCheckingTests.fs @@ -1,5 +1,6 @@ namespace Language +open FSharp.Test open Xunit open FSharp.Test.Compiler @@ -1262,3 +1263,185 @@ let f (x: IFirst) = x.F() (Error 101, Line 13, Col 11, Line 13, Col 17, "This construct is deprecated. Use G instead") (Error 72, Line 13, Col 21, Line 13, Col 24, "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.") ] + + [] + let ``Obsolete attribute warning is taken into account in a constructor property assignment`` () = + Fsx """ +open System +type JsonSerializerOptions() = + [] + member val DefaultOptions = false with get, set + + member val UseCustomOptions = false with get, set + +let options = JsonSerializerOptions(DefaultOptions = true, UseCustomOptions = false) +let options2 = JsonSerializerOptions(DefaultOptions = true, DefaultOptions = false) + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Warning 44, Line 9, Col 37, Line 9, Col 51, "This construct is deprecated. This is bad") + (Error 364, Line 10, Col 16, Line 10, Col 84, "The named argument 'DefaultOptions' has been assigned more than one value") + (Warning 44, Line 10, Col 38, Line 10, Col 52, "This construct is deprecated. This is bad") + (Warning 44, Line 10, Col 61, Line 10, Col 75, "This construct is deprecated. This is bad") + ] + + [] + let ``Obsolete attribute warning is not taken into account in prop setters that can be included in methods which are not constructors`` () = + Fsx """ +open System + +type JsonSerializerOptions() = + [] + member val DefaultOptions = false with get, set + member val UseCustomOptions = false with get, set + member this.With() = this + +let options = JsonSerializerOptions() +let options2 = + options + .With(DefaultOptions = true) + .With(UseCustomOptions = false) + """ + |> typecheck + |> withDiagnostics [ + (Warning 44, Line 13, Col 15, Line 13, Col 29, "This construct is deprecated. This is bad") + ] + + [] + let ``Obsolete attribute error is not taken into account in prop setters that can be included in methods which are not constructors`` () = + Fsx """ +open System + +type JsonSerializerOptions() = + [] + member val DefaultOptions = false with get, set + member val UseCustomOptions = false with get, set + member this.With() = this + +let options = JsonSerializerOptions() +let options2 = + options + .With(DefaultOptions = true) + .With(UseCustomOptions = false) + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 101, Line 13, Col 15, Line 13, Col 29, "This construct is deprecated. This is bad") + ] + + [] + let ``Obsolete attribute error is taken into account in a constructor property assignment`` () = + Fsx """ +open System +type JsonSerializerOptions() = + [] + member val DefaultOptions = false with get, set + + member val UseCustomOptions = false with get, set + +let options = JsonSerializerOptions(DefaultOptions = true, UseCustomOptions = false) +let options2 = JsonSerializerOptions(DefaultOptions = true, DefaultOptions = false) + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 101, Line 9, Col 37, Line 9, Col 51, "This construct is deprecated. This is bad"); + (Error 364, Line 10, Col 16, Line 10, Col 84, "The named argument 'DefaultOptions' has been assigned more than one value"); + (Error 101, Line 10, Col 38, Line 10, Col 52, "This construct is deprecated. This is bad") + ] + + [] + let ``Obsolete attribute warning is taken into account in a nested constructor property assignment`` () = + Fsx """ +open System +type JsonSerializer1Options() = + [] + member val DefaultOptions = false with get, set + + member val UseCustomOptions = false with get, set + +type JsonSerializerOptions() = + member val DefaultOptions = JsonSerializer1Options() with get, set + + member val UseCustomOptions = false with get, set + +let options = JsonSerializerOptions(DefaultOptions = JsonSerializer1Options(DefaultOptions = true), UseCustomOptions = false) + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Warning 44, Line 14, Col 77, Line 14, Col 91, "This construct is deprecated. This is bad") + ] + + [] + let ``Obsolete attribute error is taken into account in a nested constructor property assignment`` () = + Fsx """ +open System +type JsonSerializer1Options() = + [] + member val DefaultOptions = false with get, set + + member val UseCustomOptions = false with get, set + +type JsonSerializerOptions() = + member val DefaultOptions = JsonSerializer1Options() with get, set + + member val UseCustomOptions = false with get, set + +let options = JsonSerializerOptions(DefaultOptions = JsonSerializer1Options(DefaultOptions = true), UseCustomOptions = false) + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 101, Line 14, Col 77, Line 14, Col 91, "This construct is deprecated. This is bad") + ] + + [] + let ``Obsolete attribute warning is taken into account in a constructor property assignment from a csharp class`` () = + let CSLib = + CSharp """ +using System; +public class JsonProtocolTestData { + [Obsolete("Use Json instead")] + public bool IgnoreNullValues { get; set; } +} + """ |> withName "CSLib" + + let app = + FSharp """ +module ObsoleteStruct.FS +let res = JsonProtocolTestData(IgnoreNullValues = false) + """ |> withReferences [CSLib] + + app + |> compile + |> shouldFail + |> withDiagnostics [ + (Warning 44, Line 3, Col 32, Line 3, Col 48, "This construct is deprecated. Use Json instead") + ] + + [] + let ``Obsolete attribute error is taken into account in a constructor property assignment from a csharp class`` () = + let CSLib = + CSharp """ +using System; +public class JsonProtocolTestData { + [Obsolete("Use Json instead", true)] + public bool IgnoreNullValues { get; set; } +} + """ |> withName "CSLib" + + let app = + FSharp """ +module ObsoleteStruct.FS +let res = JsonProtocolTestData(IgnoreNullValues = false) + """ |> withReferences [CSLib] + + app + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 101, Line 3, Col 32, Line 3, Col 48, "This construct is deprecated. Use Json instead") + ] \ No newline at end of file