Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/11.0.100.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### Fixed

* Restore packaging of an F# design-time type provider that is activated via a `ProjectReference` carrying `IsFSharpDesignTimeProvider="true"`. The provider assembly is again included under `fsharp41` when packing (including `pack --no-build`); `PackageFSharpDesignTimeTools` now resolves the provider via `GetTargetPath`, which works in `dotnet pack`'s `BuildProjectReferences=false` content build without forcing an early `ResolveReferences`. ([Issue #18924](https://github.com/dotnet/fsharp/issues/18924), [PR #19979](https://github.com/dotnet/fsharp/pull/19979))
* Tooltip "Full name" now shows demangled companion module names (e.g. `MyType.func` instead of `MyTypeModule.func`). ([Issue #17335](https://github.com/dotnet/fsharp/issues/17335), [PR #19867](https://github.com/dotnet/fsharp/pull/19867))
* Fix internal error (FS0193) when calling an indexed property setter with a named argument that matches an indexer parameter. ([Issue #16034](https://github.com/dotnet/fsharp/issues/16034), [PR #19851](https://github.com/dotnet/fsharp/pull/19851))
* Fix missing FS1182 ("unused binding") warning for unused `let` function bindings inside class types. ([Issue #13849](https://github.com/dotnet/fsharp/issues/13849), [PR #19805](https://github.com/dotnet/fsharp/pull/19805))
Expand Down
52 changes: 22 additions & 30 deletions src/FSharp.Build/Microsoft.FSharp.NetSdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,11 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and
<PackProjectInputFile>$(MSBuildProjectFullPath)</PackProjectInputFile>
</PropertyGroup>

<!-- Gate inclusion of PackageFSharpDesignTimeTools target when design-time provider is present -->
<PropertyGroup Condition=" '$(IsFSharpDesignTimeProvider)' == 'true' ">
<!-- Register unconditionally at eval time (NuGet fixes the TargetsForTfmSpecificContentInPackage schedule before any target runs); the target's own Condition gates execution. -->
<PropertyGroup>
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);PackageFSharpDesignTimeTools</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>

<!-- Check for design-time provider references and add target if needed -->
<!-- This target attempts to update TargetsForTfmSpecificContentInPackage based on reference metadata -->
<Target Name="_CheckForDesignTimeProviderReferences" BeforeTargets="GenerateNuspec" Condition=" '$(IsFSharpDesignTimeProvider)' != 'true' ">
<ItemGroup>
<_FSharpDesignTimeProviderProject Include="@(ProjectReference)" Condition="'%(ProjectReference.IsFSharpDesignTimeProvider)' == 'true'" />
<_FSharpDesignTimeProviderPackage Include="@(PackageReference)" Condition="'%(PackageReference.IsFSharpDesignTimeProvider)' == 'true'" />
</ItemGroup>
<PropertyGroup Condition=" '@(_FSharpDesignTimeProviderProject)' != '' or '@(_FSharpDesignTimeProviderPackage)' != '' ">
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);PackageFSharpDesignTimeTools</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>
</Target>

<PropertyGroup Condition=" '$(DisableImplicitLibraryPacksFolder)' != 'true' ">
<RestoreAdditionalProjectSources Condition="Exists('$(_FSharpCoreLibraryPacksFolder)')">$(RestoreAdditionalProjectSources);$(_FSharpCoreLibraryPacksFolder)</RestoreAdditionalProjectSources>
</PropertyGroup>
Expand All @@ -78,7 +66,9 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and
</ItemGroup>
</Target>

<Target Name="PackageFSharpDesignTimeTools" AfterTargets="ResolveReferences">
<!-- Pack-only (run via TargetsForTfmSpecificContentInPackage, no AfterTargets); execution-time Condition skips non-providers. -->
<Target Name="PackageFSharpDesignTimeTools"
Condition="'$(IsFSharpDesignTimeProvider)' == 'true' or '@(ProjectReference->AnyHaveMetadataValue('IsFSharpDesignTimeProvider', 'true'))' == 'true'">
<PropertyGroup>
<FSharpDesignTimeProtocol Condition = " '$(FSharpDesignTimeProtocol)' == '' ">fsharp41</FSharpDesignTimeProtocol>
<FSharpToolsDirectory Condition = " '$(FSharpToolsDirectory)' == '' ">tools</FSharpToolsDirectory>
Expand All @@ -87,22 +77,24 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and
<Error Text="'$(FSharpToolsDirectory)' is an invalid value for 'FSharpToolsDirectory' valid values are 'typeproviders' and 'tools'." Condition="'$(FSharpToolsDirectory)' != 'typeproviders' and '$(FSharpToolsDirectory)' != 'tools'" />
<Error Text="The 'FSharpDesignTimeProtocol' property can be only 'fsharp41'" Condition="'$(FSharpDesignTimeProtocol)' != 'fsharp41'" />

<!-- pack uses BuildProjectReferences=false (=> _ResolvedProjectReferencePaths empty); GetTargetPath reads each provider's already-built path without building it (no NETSDK1085) or forcing an early ResolveReferences. -->
<MSBuild Projects="@(ProjectReference->WithMetadataValue('IsFSharpDesignTimeProvider', 'true'))"
Targets="GetTargetPath"
RemoveProperties="TargetFramework">
<Output TaskParameter="TargetOutputs" ItemName="_FSharpDesignTimeProviderPath" />
</MSBuild>

<ItemGroup>
<_ResolvedOutputFiles
Include="%(_ResolvedProjectReferencePaths.RootDir)%(_ResolvedProjectReferencePaths.Directory)/**/*"
Exclude="%(_ResolvedProjectReferencePaths.RootDir)%(_ResolvedProjectReferencePaths.Directory)/**/FSharp.Core.dll;%(_ResolvedProjectReferencePaths.RootDir)%(_ResolvedProjectReferencePaths.Directory)/**/System.ValueTuple.dll"
Condition="'%(_ResolvedProjectReferencePaths.IsFSharpDesignTimeProvider)' == 'true'">
<NearestTargetFramework>%(_ResolvedProjectReferencePaths.NearestTargetFramework)</NearestTargetFramework>
</_ResolvedOutputFiles>

<_ResolvedOutputFiles
Include="@(BuiltProjectOutputGroupKeyOutput)"
Condition=" '$(IsFSharpDesignTimeProvider)' == 'true' and '%(BuiltProjectOutputGroupKeyOutput->Filename)%(BuiltProjectOutputGroupKeyOutput->Extension)' != 'FSharp.Core.dll' and '%(BuiltProjectOutputGroupKeyOutput->Filename)%(BuiltProjectOutputGroupKeyOutput->Extension)' != 'System.ValueTuple.dll' ">
<NearestTargetFramework>$(TargetFramework)</NearestTargetFramework>
</_ResolvedOutputFiles>

<TfmSpecificPackageFile Include="@(_ResolvedOutputFiles)">
<PackagePath>$(FSharpToolsDirectory)/$(FSharpDesignTimeProtocol)/%(_ResolvedOutputFiles.NearestTargetFramework)/%(_ResolvedOutputFiles.FileName)%(_ResolvedOutputFiles.Extension)</PackagePath>
<!-- ProjectReference case: bounded top-level *.dll beside the provider; guard + no rooted/recursive glob so an empty path can never widen to a cwd/drive-root scan. -->
<_ResolvedOutputFiles Condition="'@(_FSharpDesignTimeProviderPath)' != ''" Include="%(_FSharpDesignTimeProviderPath.RootDir)%(_FSharpDesignTimeProviderPath.Directory)*.dll" />

<!-- Direct case (<IsFSharpDesignTimeProvider>true</...>): this project's own primary output. -->
<_ResolvedOutputFiles Condition="'$(IsFSharpDesignTimeProvider)' == 'true'" Include="@(BuiltProjectOutputGroupKeyOutput)" />

<!-- One exclusion point for both cases: consumers always carry their own FSharp.Core/System.ValueTuple. TFM is always the packing project's, so inline $(TargetFramework). -->
<TfmSpecificPackageFile Include="@(_ResolvedOutputFiles)"
Condition="'%(_ResolvedOutputFiles.Filename)' != 'FSharp.Core' and '%(_ResolvedOutputFiles.Filename)' != 'System.ValueTuple'">
<PackagePath>$(FSharpToolsDirectory)/$(FSharpDesignTimeProtocol)/$(TargetFramework)/%(_ResolvedOutputFiles.FileName)%(_ResolvedOutputFiles.Extension)</PackagePath>
</TfmSpecificPackageFile>
</ItemGroup>
</Target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ echo [Test 2] PASSED: Provider test passed

echo.
echo === Test 3: Host with ProjectReference to Provider ===
echo [Test 3] Packing Host with ProjectReference to Provider...
echo [Test 3] Note: This tests experimental execution-time reference checking
echo [Test 3] Packing Host that activates a design-time provider via ProjectReference metadata...
echo [Test 3] Command: dotnet pack Host\Host.fsproj -o %~dp0artifacts -c %configuration% -v minimal -bl:%~dp0artifacts\host.binlog -p:FSharpTestCompilerVersion=coreclr
dotnet pack Host\Host.fsproj -o %~dp0artifacts -c %configuration% -v minimal -bl:%~dp0artifacts\host.binlog -p:FSharpTestCompilerVersion=coreclr
if ERRORLEVEL 1 (
Expand All @@ -94,9 +93,17 @@ if ERRORLEVEL 1 (
goto :failure
)

rem Note: This test may not work as expected due to MSBuild evaluation phase limitations
rem The current implementation only checks IsFSharpDesignTimeProvider property directly
echo [Test 3] PASSED: Host test completed (implementation limitation noted - may not check references correctly)
rem Check that tools folder exists in nupkg (provider activated via ProjectReference IsFSharpDesignTimeProvider metadata)
echo [Test 3] Checking that package contains tools/fsharp41 folder...
powershell -command "& { Add-Type -AssemblyName System.IO.Compression.FileSystem; $zip = [System.IO.Compression.ZipFile]::OpenRead('%~dp0artifacts\Host.1.0.0.nupkg'); $hasTools = $zip.Entries | Where-Object { $_.FullName -like 'tools/fsharp41/*' }; if ($hasTools) { exit 0 } else { exit 1 } }"
if ERRORLEVEL 1 (
echo [Test 3] FAILED: Package does not contain tools/fsharp41 folder
echo [Test 3] Expected: provider referenced via ProjectReference should be packaged
echo [Test 3] Actual: No tools/fsharp41 folder found in Host.1.0.0.nupkg
goto :failure
)

echo [Test 3] PASSED: Host (ProjectReference gesture) test passed

echo.
echo === Test 4: Pack with --no-build (No Provider) ===
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,24 @@ echo "[Test 2] PASSED: Provider test passed"

echo
echo "=== Test 3: Host with ProjectReference to Provider ==="
echo "[Test 3] Packing Host with ProjectReference to Provider..."
echo "[Test 3] Note: This tests experimental execution-time reference checking"
echo "[Test 3] Packing Host that activates a design-time provider via ProjectReference metadata..."
echo "[Test 3] Command: dotnet pack Host/Host.fsproj -o artifacts -c $configuration -v minimal -bl:artifacts/host.binlog -p:FSharpTestCompilerVersion=coreclr"
if ! dotnet pack Host/Host.fsproj -o artifacts -c $configuration -v minimal -bl:artifacts/host.binlog -p:FSharpTestCompilerVersion=coreclr; then
echo "[Test 3] FAILED: Pack command returned error code $?"
echo "[Test 3] Check artifacts/host.binlog for details"
exit 1
fi

# Note: This test may not work as expected due to MSBuild evaluation phase limitations
# The current implementation only checks IsFSharpDesignTimeProvider property directly
echo "[Test 3] PASSED: Host test completed (implementation limitation noted - may not check references correctly)"
# Check that tools folder exists in nupkg (provider activated via ProjectReference IsFSharpDesignTimeProvider metadata)
echo "[Test 3] Checking that package contains tools/fsharp41 folder..."
if ! unzip -l artifacts/Host.1.0.0.nupkg | grep -q "tools/fsharp41/"; then
echo "[Test 3] FAILED: Package does not contain tools/fsharp41 folder"
echo "[Test 3] Expected: provider referenced via ProjectReference should be packaged"
echo "[Test 3] Actual: No tools/fsharp41 folder found in Host.1.0.0.nupkg"
exit 1
fi

echo "[Test 3] PASSED: Host (ProjectReference gesture) test passed"

echo
echo "=== Test 4: Pack with --no-build (No Provider) ==="
Expand Down
Loading