Skip to content
Merged
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
3 changes: 3 additions & 0 deletions docs/release-notes/.FSharp.Core/10.0.200.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Fixed

* Fix IL2091 trimming warning in `LazyExtensions.Create` by adding `DynamicallyAccessedMembers` attribute to the generic type parameter. ([Issue #17356](https://github.com/dotnet/fsharp/issues/17356), [PR #18302](https://github.com/dotnet/fsharp/pull/18302))
3 changes: 2 additions & 1 deletion src/FSharp.Core/prim-types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7299,11 +7299,12 @@ namespace Microsoft.FSharp.Core
namespace Microsoft.FSharp.Control

open System
open System.Diagnostics.CodeAnalysis
open Microsoft.FSharp.Core
open Microsoft.FSharp.Core.Operators

module LazyExtensions =
type Lazy<'T> with
type Lazy<[<DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)>]'T> with
[<CompiledName("Create")>] // give the extension member a 'nice', unmangled compiled name, unique within this module
static member Create(creator : unit -> 'T) : Lazy<'T> =
let creator = Func<'T>(creator)
Expand Down
3 changes: 2 additions & 1 deletion src/FSharp.Core/prim-types.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -6144,6 +6144,7 @@ namespace Microsoft.FSharp.Core

namespace Microsoft.FSharp.Control

open System.Diagnostics.CodeAnalysis
open Microsoft.FSharp.Core

/// <summary>Extensions related to Lazy values.</summary>
Expand All @@ -6152,7 +6153,7 @@ namespace Microsoft.FSharp.Control
[<AutoOpen>]
module LazyExtensions =

type System.Lazy<'T> with
type System.Lazy<[<DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)>]'T> with

/// <summary>Creates a lazy computation that evaluates to the result of the given function when forced.</summary>
///
Expand Down
16 changes: 16 additions & 0 deletions tests/AheadOfTime/Trimming/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9365,6 +9365,20 @@ module NonStructuralComparisonOverTimeSpanDirect =
do check "test9407" (NonStructuralComparison.hash 11L) (Operators.hash 11L)
do check "test9408" (NonStructuralComparison.hash 11UL) (Operators.hash 11UL)

let testLazySimple () =
let f23 () = let z = lazy (12345) in z.Force()
check "lazy_simple" 12345 (f23())

let testSeqWithTryFinally () =
let result =
seq {
try
yield 1
yield 2
with
| ex -> ()
} |> Seq.toList
check "seq_try_with" [1; 2] result

[<EntryPoint>]
let main _ =
Expand All @@ -9385,6 +9399,8 @@ let main _ =
PercentAPublicTests.tests ()
PercentAInternalTests.tests ()
ClassWithEvents.testWithEventClass ()
testLazySimple ()
testSeqWithTryFinally ()

match !failures with
| [] ->
Expand Down
52 changes: 40 additions & 12 deletions tests/AheadOfTime/Trimming/check.ps1
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
function CheckTrim($root, $tfm, $outputfile, $expected_len) {
function CheckTrim($root, $tfm, $outputfile, $expected_len, $callerLineNumber) {
Write-Host "Publish and Execute: ${tfm} - ${root}"
Write-Host "Expecting ${expected_len} for ${outputfile}"

$errors = @()
$scriptFile = $PSCommandPath

$cwd = Get-Location
Set-Location (Join-Path $PSScriptRoot "${root}")
$build_output = dotnet publish -restore -c release -f:$tfm "${root}.fsproj" -bl:"../../../../artifacts/log/Release/AheadOfTime/Trimming/${root}_${tfm}.binlog"
Set-Location ${cwd}
if ($LASTEXITCODE -ne 0)
{
Write-Error "Build failed with exit code ${LASTEXITCODE}"
Write-Error "${build_output}" -ErrorAction Stop
$errors += "Build failed with exit code ${LASTEXITCODE}"
Write-Host "##vso[task.logissue type=error;sourcepath=${scriptFile};linenumber=${callerLineNumber}]Build failed for ${root} with exit code ${LASTEXITCODE}"
return $errors
}

$process = Start-Process -FilePath $(Join-Path $PSScriptRoot "${root}\bin\release\${tfm}\win-x64\publish\${root}.exe") -Wait -NoNewWindow -PassThru -RedirectStandardOutput $(Join-Path $PSScriptRoot "output.txt")

# Checking that the test passed
$output = Get-Content $(Join-Path $PSScriptRoot output.txt)
$expected = "All tests passed"
if ($LASTEXITCODE -ne 0)
if ($process.ExitCode -ne 0)
{
Write-Error "Test failed with exit code ${LASTEXITCODE}" -ErrorAction Stop
$errors += "Test failed with exit code $($process.ExitCode)"
Write-Host "##vso[task.logissue type=error;sourcepath=${scriptFile};linenumber=${callerLineNumber}]Test execution failed for ${root} with exit code $($process.ExitCode)"
}
if ($output -eq $expected)
elseif ($output -ne $expected)
{
Write-Host "Test passed"
$errors += "Test failed with unexpected output: Expected '${expected}', Actual '${output}'"
Write-Host "##vso[task.logissue type=error;sourcepath=${scriptFile};linenumber=${callerLineNumber}]Test failed for ${root} with unexpected output: Expected '${expected}', Actual '${output}'"
}
else
{
Write-Error "Test failed with unexpected output:`nExpected:`n`t${expected}`nActual`n`t${output}" -ErrorAction Stop
Write-Host "Test passed"
}

# Checking that the trimmed outputfile binary is of expected size (needs adjustments if test is updated).
Expand All @@ -39,24 +45,46 @@ function CheckTrim($root, $tfm, $outputfile, $expected_len) {
}
elseif ($file_len -ne $expected_len)
{
Write-Error "Test failed with unexpected ${tfm} - trimmed ${outputfile} length:`nExpected:`n`t${expected_len} Bytes`nActual:`n`t${file_len} Bytes`nEither codegen or trimming logic have changed. Please investigate and update expected dll size or report an issue." -ErrorAction Stop
$errors += "Test failed with unexpected ${tfm} - trimmed ${outputfile} length: Expected ${expected_len} Bytes, Actual ${file_len} Bytes"
Write-Host "##vso[task.logissue type=error;sourcepath=${scriptFile};linenumber=${callerLineNumber}]Trimmed ${outputfile} size mismatch for ${root}: Expected ${expected_len} Bytes, Actual ${file_len} Bytes. Either codegen or trimming logic have changed. Please investigate and update expected dll size or report an issue."
}

$fileBeforePublish = Get-Item (Join-Path $PSScriptRoot "${root}\bin\release\${tfm}\win-x64\${outputfile}")
$sizeBeforePublish = $fileBeforePublish.Length
$sizeDiff = $sizeBeforePublish - $file_len
Write-Host "Size of ${tfm} - ${outputfile} before publish: ${sizeBeforePublish} Bytes, which means the diff is ${sizeDiff} Bytes"

return $errors
}

# NOTE: Trimming now errors out on desktop TFMs, as shown below:
# error NETSDK1124: Trimming assemblies requires .NET Core 3.0 or higher.

$allErrors = @()

# Check net9.0 trimmed assemblies
CheckTrim -root "SelfContained_Trimming_Test" -tfm "net9.0" -outputfile "FSharp.Core.dll" -expected_len 300032
$allErrors += CheckTrim -root "SelfContained_Trimming_Test" -tfm "net9.0" -outputfile "FSharp.Core.dll" -expected_len 311296 -callerLineNumber 66

# Check net9.0 trimmed assemblies with static linked FSharpCore
CheckTrim -root "StaticLinkedFSharpCore_Trimming_Test" -tfm "net9.0" -outputfile "StaticLinkedFSharpCore_Trimming_Test.dll" -expected_len 9154048
$allErrors += CheckTrim -root "StaticLinkedFSharpCore_Trimming_Test" -tfm "net9.0" -outputfile "StaticLinkedFSharpCore_Trimming_Test.dll" -expected_len 9169408 -callerLineNumber 69

# Check net9.0 trimmed assemblies with F# metadata resources removed
CheckTrim -root "FSharpMetadataResource_Trimming_Test" -tfm "net9.0" -outputfile "FSharpMetadataResource_Trimming_Test.dll" -expected_len 7607296
$allErrors += CheckTrim -root "FSharpMetadataResource_Trimming_Test" -tfm "net9.0" -outputfile "FSharpMetadataResource_Trimming_Test.dll" -expected_len 7609344 -callerLineNumber 72

# Report all errors and exit with failure if any occurred
if ($allErrors.Count -gt 0) {
Write-Host ""
Write-Host "============================================"
Write-Host "TRIMMING TESTS FAILED"
Write-Host "============================================"
Write-Host "Total errors: $($allErrors.Count)"
foreach ($err in $allErrors) {
Write-Error $err
}
exit 1
}

Write-Host ""
Write-Host "============================================"
Write-Host "ALL TRIMMING TESTS PASSED"
Write-Host "============================================"
Loading