Sitelet https://github.com/fsprojects/fsharp-automation/pull/6
Skip to content

[msbuild-quality] Guard ValueTupleImplicitPackageVersion default so consumers can override it - #6

Draft
github-actions[bot] wants to merge 1 commit into
mainfrom
msbuild-quality/valuetuple-version-guard-788bff1a9eb1c34b
Draft

github-actions[bot] wants to merge 1 commit into
mainfrom
msbuild-quality/valuetuple-version-guard-788bff1a9eb1c34b

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Found by the MSBuild file-quality review of the shipped F# SDK build logic.

Problem

src/FSharp.Build/Microsoft.FSharp.NetSdk.props assigns the implicit System.ValueTuple package version unconditionally:

<PropertyGroup>
  <ValueTupleImplicitPackageVersion>4.6.2</ValueTupleImplicitPackageVersion>
</PropertyGroup>

This file is imported by every F# project, and the property feeds the two implicit System.ValueTuple PackageReference item groups in the same file. Because the assignment has no condition, a project (or a Directory.Build.props) that sets $(ValueTupleImplicitPackageVersion) has its value silently discarded — MSBuild's property pass always runs this line last within the import, before the item pass reads the property. There is no way to pin a different System.ValueTuple version short of DisableImplicitSystemValueTupleReference=true.

Every other overridable default in this file (EnableDefaultCompileItems, Prefer32Bit, WarningLevel, FsiExec, FscToolPath, DisableImplicitFSharpCoreReference, ...) already carries the Condition="'$(Prop)' == ''" guard, so this one is the odd one out rather than a deliberate hard override — there is no comment suggesting otherwise.

Change

Add the standard default guard:

<ValueTupleImplicitPackageVersion Condition="'$(ValueTupleImplicitPackageVersion)' == ''">4.6.2</ValueTupleImplicitPackageVersion>

One line, no behavioural change for any project that does not set the property: the default value and evaluation order are identical. The only difference is that an explicit value now survives.

Validation

XML well-formedness checked locally. A full ./build.sh exceeds this workflow's timeout, so full validation is deferred to the PR CI checks — keeping this as a draft for a human to sign off.

Related

The remaining findings from this review pass are unchanged from #4 (CoreCompileDependsOn overwrite, missing @(FileWrites) registration in GenerateFSharpILLinkSubstitutions, shim import guards). Those all require judgement about intent or target ordering and are deliberately not auto-fixed here.

Generated by F# MSBuild File Quality Review Agent · opus50 209.3K · ◷

The implicit System.ValueTuple package version was assigned
unconditionally in Microsoft.FSharp.NetSdk.props, so a project setting
$(ValueTupleImplicitPackageVersion) had its value silently discarded.
Add the standard Condition="'$(Prop)' == ''" default guard, matching
every other overridable default in this file.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor Author

🤖 This is an automated response from Repo Assist.

I independently verified the premise of this PR against HEAD 199945ab34433a3ec257e35e1fd30577a89ae350 (2026-08-28) and against the shipped copy in /usr/share/dotnet/sdk/10.0.401/FSharp/Microsoft.FSharp.NetSdk.props (identical: unconditional assignment at line 106, consumed by the PackageReference item groups at lines 90 and 136).

The core claim holds, with one correction worth folding into the PR description.

Repro — a folder containing:

<!-- Directory.Build.props -->
<Project><PropertyGroup><ValueTupleImplicitPackageVersion>9.9.9</ValueTupleImplicitPackageVersion></PropertyGroup></Project>
<!-- a.fsproj -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup><TargetFramework>net472</TargetFramework></PropertyGroup>
</Project>

dotnet msbuild a.fsproj -getProperty:ValueTupleImplicitPackageVersion → 4.6.2. The Directory.Build.props value is silently discarded, exactly as this PR describes.

Correction: the PR body states "There is no way to pin a different System.ValueTuple version short of DisableImplicitSystemValueTupleReference=true." That is slightly overstated. Adding the property to the project body does survive:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup><TargetFramework>net472</TargetFramework><ValueTupleImplicitPackageVersion>7.7.7</ValueTupleImplicitPackageVersion></PropertyGroup>
</Project>

→ 7.7.7. With the Sdk="..." attribute form, the SDK .props are imported at the very top of the project, so a project-body assignment evaluates afterwards and wins. Only props-phase contributions (Directory.Build.props, imported .props files, NuGet build/*.props) are lost.

So the affected scenario is specifically repo-wide pinning via Directory.Build.props, which is the idiomatic way to do this — the fix is still worthwhile, and the one-line guard is consistent with every other default in the same file. I'd just suggest narrowing that sentence so a reviewer doesn't reject the PR on a claim that's easy to disprove.

I have not built the compiler to validate the change end-to-end; CI is the right place for that.

Leaving the merge decision to a human maintainer.

Generated by 🌈 Repo Assist, see workflow run. Learn more.

Add this agentic workflows to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@7c7feb61a52b662eb2089aa2945588b7a200d404

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants