From 79ed1525824a7e045c68dda3f093dd58be07a033 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 26 Mar 2026 17:30:55 +0100 Subject: [PATCH 1/3] Fix #3939: Hide compiler-generated auto-property symbols from Symbols API Fixes https://github.com/dotnet/fsharp/issues/3939 Mark the compiler-generated `v` setter parameter and backing field identifiers in auto-property desugaring with synthetic ranges, so they are excluded from GetAllUsesOfAllSymbolsInFile(). Previously these internal symbols leaked through the API with empty EnclosingEntity and misleading DisplayName/CompiledName values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/Checking/CheckDeclarations.fs | 6 +++--- .../FSharp.Compiler.Service.Tests/Symbols.fs | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index f425f49dafc..3d80f056de0 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -4418,7 +4418,7 @@ module TcDeclarations = // Only the keep the field-targeted attributes let attribs = attribs |> List.filter (fun a -> match a.Target with Some t when t.idText = "field" -> true | _ -> false) let mLetPortion = synExpr.Range - let fldId = ident (CompilerGeneratedName id.idText, mLetPortion) + let fldId = ident (CompilerGeneratedName id.idText, mLetPortion.MakeSynthetic()) let headPat = SynPat.LongIdent (SynLongIdent([fldId], [], [None]), None, Some noInferredTypars, SynArgPats.Pats [], None, mLetPortion) let retInfo = match tyOpt with None -> None | Some ty -> Some (None, SynReturnInfo((ty, SynInfo.unnamedRetVal), ty.Range)) let isMutable = @@ -4446,7 +4446,7 @@ module TcDeclarations = let mMemberPortion = id.idRange // Only the keep the non-field-targeted attributes let attribs = attribs |> List.filter (fun a -> match a.Target with Some t when t.idText = "field" -> false | _ -> true) - let fldId = ident (CompilerGeneratedName id.idText, mMemberPortion) + let fldId = ident (CompilerGeneratedName id.idText, mMemberPortion.MakeSynthetic()) let headPatIds = if isStatic then [id] else [ident ("__", mMemberPortion);id] let headPat = SynPat.LongIdent (SynLongIdent(headPatIds, [], List.replicate headPatIds.Length None), None, Some noInferredTypars, SynArgPats.Pats [], None, mMemberPortion) let memberFlags = { memberFlags with GetterOrSetterIsCompilerGenerated = true } @@ -4475,7 +4475,7 @@ module TcDeclarations = | SynMemberKind.PropertySet | SynMemberKind.PropertyGetSet -> let setter = - let vId = ident("v", mMemberPortion) + let vId = ident("v", mMemberPortion.MakeSynthetic()) let headPat = SynPat.LongIdent (SynLongIdent(headPatIds, [], List.replicate headPatIds.Length None), None, Some noInferredTypars, SynArgPats.Pats [mkSynPatVar None vId], None, mMemberPortion) let rhsExpr = mkSynAssign (SynExpr.Ident fldId) (SynExpr.Ident vId) let binding = mkSynBinding (xmlDoc, headPat) (setterAccess, false, false, mMemberPortion, DebugPointAtBinding.NoneAtInvisible, None, rhsExpr, rhsExpr.Range, [], [], Some memberFlagsForSet, SynBindingTrivia.Zero) diff --git a/tests/FSharp.Compiler.Service.Tests/Symbols.fs b/tests/FSharp.Compiler.Service.Tests/Symbols.fs index 3f4d4fcdbd9..69bfb70519a 100644 --- a/tests/FSharp.Compiler.Service.Tests/Symbols.fs +++ b/tests/FSharp.Compiler.Service.Tests/Symbols.fs @@ -634,18 +634,23 @@ type Foo = Assert.True(setMfv.CompiledName.StartsWith("set_")) | _ -> failwith $"Expected three symbols, got %A{symbols}" - [] - let ``AutoProperty with get, set has property symbol 02`` () = - let symbol = Checker.getSymbolUse """ + // https://github.com/dotnet/fsharp/issues/3939 + [] + let ``AutoProperty with get, set does not expose compiler-generated v symbol`` () = + let _, checkResults = getParseAndCheckResults """ namespace Foo type Foo = - member val AutoPropGetSet{caret} = 0 with get, set + member val AutoPropGetSet = 0 with get, set """ - // The setter should have a symbol for the generated parameter `v`. - let setVMfv = symbol |> chooseMemberOrFunctionOrValue - if Option.isNone setVMfv then - failwith "No generated v symbol for the setter was found" + let allSymbols = checkResults.GetAllUsesOfAllSymbolsInFile() + let allMfvs = allSymbols |> Seq.choose (fun su -> match su.Symbol with :? FSharpMemberOrFunctionOrValue as mfv -> Some mfv | _ -> None) |> Seq.toList + // The compiler-generated `v` setter parameter should NOT appear in symbol uses + let vSymbols = allMfvs |> List.filter (fun mfv -> mfv.DisplayName = "v") + Assert.True(vSymbols.IsEmpty, $"Compiler-generated 'v' symbol should not be exposed via GetAllUsesOfAllSymbolsInFile, but found {vSymbols.Length} occurrences") + // The compiler-generated backing field should also not appear + let backingFieldSymbols = allMfvs |> List.filter (fun mfv -> mfv.DisplayName.Contains("@")) + Assert.True(backingFieldSymbols.IsEmpty, $"Compiler-generated backing field should not appear, but found: {backingFieldSymbols |> List.map (fun m -> m.DisplayName)}") [] let ``Property symbol is resolved for property`` () = From 8e69e466247e402d47ac9f0f86d00900f3bbc958 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 3 Apr 2026 13:07:11 +0200 Subject: [PATCH 2/3] Fix CI: update ProjectAnalysisTests to match synthetic auto-property symbols Remove compiler-generated auto-property backing fields and setter parameter 'v' from expected symbol arrays in 'Test Project24 all symbols' and 'Test symbol uses of properties with both getters and setters'. These symbols are now correctly hidden by MakeSynthetic() ranges. Also merge with latest main. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ProjectAnalysisTests.fs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs b/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs index cd494f7e659..551bdf02ea2 100644 --- a/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs @@ -3512,12 +3512,6 @@ let ``Test Project24 all symbols`` () = ("v", "file1", ((22, 17), (22, 18)), ["defn"], []); ("int", "file1", ((25, 21), (25, 24)), ["type"], ["abbrev"]); ("v", "file1", ((25, 18), (25, 19)), ["defn"], []); - ("``AutoPropGet@``", "file1", ((27, 15), (27, 26)), [], ["compgen"]); - ("``AutoPropGetSet@``", "file1", ((28, 15), (28, 29)), [], ["compgen"; "mutable"]) - ("v", "file1", ((28, 15), (28, 29)), ["defn"], []); - ("``StaticAutoPropGet@``", "file1", ((30, 22), (30, 39)), [], ["compgen"]); - ("``StaticAutoPropGetSet@``", "file1", ((31, 22), (31, 42)), [], - ["compgen"; "mutable"]); ("v", "file1", ((31, 22), (31, 42)), ["defn"], []); ("``.cctor``", "file1", ((4, 5), (4, 23)), ["defn"], ["member"]); ("TypeWithProperties", "file1", ((33, 9), (33, 27)), [], ["member"; "ctor"]); ("NameGetSet", "file1", ((33, 9), (33, 40)), [], ["member"; "prop"]); @@ -3614,12 +3608,6 @@ let ``Test symbol uses of properties with both getters and setters`` () = ("v", "file1", ((22, 17), (22, 18)), []); ("int", "file1", ((25, 21), (25, 24)), ["abbrev"]); ("v", "file1", ((25, 18), (25, 19)), []); - ("``AutoPropGet@``", "file1", ((27, 15), (27, 26)), ["compgen"]); - ("``AutoPropGetSet@``", "file1", ((28, 15), (28, 29)), ["compgen"; "mutable"]); - ("v", "file1", ((28, 15), (28, 29)), []); - ("``StaticAutoPropGet@``", "file1", ((30, 22), (30, 39)), ["compgen"]); - ("``StaticAutoPropGetSet@``", "file1", ((31, 22), (31, 42)), - ["compgen"; "mutable"]); ("v", "file1", ((31, 22), (31, 42)), []); ("``.cctor``", "file1", ((4, 5), (4, 23)), ["member"]); ("TypeWithProperties", "file1", ((33, 9), (33, 27)), ["member"; "ctor"]); ("NameGetSet", "file1", ((33, 9), (33, 40)), ["member"; "prop"]); From f97817946692852128fc4acefce71ec690f0b1ad Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 9 Apr 2026 20:30:44 +0200 Subject: [PATCH 3/3] Bump FSBuildVersion to 101: packages 11.0.100 and 43.12.100 already published Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index a5802082fb8..8248454c00f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -19,7 +19,7 @@ 11 0 - 100 + 101 0