diff --git a/.vsts-signed.yaml b/.vsts-signed.yaml index 3ec301bbe0c..ed30cb74ef2 100644 --- a/.vsts-signed.yaml +++ b/.vsts-signed.yaml @@ -105,6 +105,14 @@ jobs: continueOnError: true condition: succeeded() + # Publish native PDBs for archiving + - task: PublishBuildArtifacts@1 + displayName: Publish Artifact Symbols + inputs: + PathtoPublish: '$(Build.SourcesDirectory)/artifacts/SymStore/$(BuildConfiguration)' + ArtifactName: NativeSymbols + condition: succeeded() + # Execute cleanup tasks - task: ms-vseng.MicroBuildTasks.521a94ea-9e68-468a-8167-6dcf361ea776.MicroBuildCleanup@1 displayName: Execute cleanup tasks diff --git a/FSharpBuild.Directory.Build.props b/FSharpBuild.Directory.Build.props index f342ca6fe6a..95fa8fcd020 100644 --- a/FSharpBuild.Directory.Build.props +++ b/FSharpBuild.Directory.Build.props @@ -75,6 +75,7 @@ https://github.com/Microsoft/visualfsharp git + <_DotGitDir>$(RepoRoot).git <_HeadFileContent Condition="Exists('$(_DotGitDir)/HEAD')">$([System.IO.File]::ReadAllText('$(_DotGitDir)/HEAD').Trim()) @@ -87,7 +88,7 @@ $(NoWarn);FS2003 true - portable + embedded fs false true diff --git a/NuGet.config b/NuGet.config index 8f21de1b15b..a8664a73c57 100644 --- a/NuGet.config +++ b/NuGet.config @@ -8,6 +8,20 @@ + + + + + + + + + + + + + + diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2207a4792eb..87306e5c604 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -113,6 +113,12 @@ jobs: PathtoPublish: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(_BuildConfig)\VisualFSharpFull.vsix' ArtifactName: 'Nightly' condition: succeeded() + - task: PublishBuildArtifacts@1 + displayName: Publish Artifact Symbols + inputs: + PathtoPublish: '$(Build.SourcesDirectory)\artifacts\SymStore\$(_BuildConfig)' + ArtifactName: 'NativeSymbols' + condition: succeeded() #---------------------------------------------------------------------------------------------------------------------# # PR builds # diff --git a/eng/Build.ps1 b/eng/Build.ps1 index 9a6cf3f73da..314fc6637d1 100644 --- a/eng/Build.ps1 +++ b/eng/Build.ps1 @@ -225,13 +225,14 @@ function UpdatePath() { TestAndAddToPath "$ArtifactsDir\bin\fsiAnyCpu\$configuration\net472" } -function VerifyAssemblyVersions() { - $fsiPath = Join-Path $ArtifactsDir "bin\fsi\Proto\net472\publish\fsi.exe" +function VerifyAssemblyVersionsAndSymbols() { + $assemblyVerCheckPath = Join-Path $ArtifactsDir "Bootstrap\AssemblyCheck\AssemblyCheck.dll" # Only verify versions on CI or official build if ($ci -or $official) { - $asmVerCheckPath = "$RepoRoot\scripts" - Exec-Console $fsiPath """$asmVerCheckPath\AssemblyVersionCheck.fsx"" -- ""$ArtifactsDir""" + $dotnetPath = InitializeDotNetCli + $dotnetExe = Join-Path $dotnetPath "dotnet.exe" + Exec-Console $dotnetExe """$assemblyVerCheckPath"" ""$ArtifactsDir""" } } @@ -308,7 +309,7 @@ try { } if ($build) { - VerifyAssemblyVersions + VerifyAssemblyVersionsAndSymbols } $desktopTargetFramework = "net472" diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 0c5078f9f9c..8a78856321e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 0f5dd7680174620f31c9a00cdb2ac0b0e70e631f + a8e982d3bac01d8f4f91a4c57191147570079448 diff --git a/eng/build-utils.ps1 b/eng/build-utils.ps1 index fcda1a58e26..772de110ca2 100644 --- a/eng/build-utils.ps1 +++ b/eng/build-utils.ps1 @@ -236,10 +236,11 @@ function Make-BootstrapBuild() { Remove-Item -re $dir -ErrorAction SilentlyContinue Create-Directory $dir - # prepare FsLex and Fsyacc + # prepare FsLex and Fsyacc and AssemblyCheck Run-MSBuild "$RepoRoot\src\buildtools\buildtools.proj" "/restore /t:Publish" -logFileName "BuildTools" -configuration $bootstrapConfiguration Copy-Item "$ArtifactsDir\bin\fslex\$bootstrapConfiguration\netcoreapp2.1\publish" -Destination "$dir\fslex" -Force -Recurse Copy-Item "$ArtifactsDir\bin\fsyacc\$bootstrapConfiguration\netcoreapp2.1\publish" -Destination "$dir\fsyacc" -Force -Recurse + Copy-Item "$ArtifactsDir\bin\AssemblyCheck\$bootstrapConfiguration\netcoreapp2.1\publish" -Destination "$dir\AssemblyCheck" -Force -Recurse # prepare compiler $projectPath = "$RepoRoot\proto.proj" diff --git a/eng/common/SigningValidation.proj b/eng/common/SigningValidation.proj index 7045fb6fb9d..3d0ac80af3f 100644 --- a/eng/common/SigningValidation.proj +++ b/eng/common/SigningValidation.proj @@ -3,7 +3,7 @@ + + + $(WorkItemDirectory) + $(WorkItemCommand) --bdn-arguments="--anyCategories $(BDNCategories) $(ExtraBenchmarkDotNetArguments) $(CoreRunArgument) --artifacts $(ArtifactsDirectory) --partition-count $(PartitionCount) --partition-index %(HelixWorkItem.Index)" + 4:00 + + + + + $(WorkItemDirectory) + $(WorkItemCommand) --bdn-arguments="--anyCategories $(BDNCategories) $(ExtraBenchmarkDotNetArguments) $(CoreRunArgument) --artifacts $(ArtifactsDirectory)" + 4:00 + + + \ No newline at end of file diff --git a/eng/common/performance/performance-setup.ps1 b/eng/common/performance/performance-setup.ps1 new file mode 100644 index 00000000000..7e5441f7974 --- /dev/null +++ b/eng/common/performance/performance-setup.ps1 @@ -0,0 +1,91 @@ +Param( + [string] $SourceDirectory=$env:BUILD_SOURCESDIRECTORY, + [string] $CoreRootDirectory, + [string] $Architecture="x64", + [string] $Framework="netcoreapp3.0", + [string] $CompilationMode="Tiered", + [string] $Repository=$env:BUILD_REPOSITORY_NAME, + [string] $Branch=$env:BUILD_SOURCEBRANCH, + [string] $CommitSha=$env:BUILD_SOURCEVERSION, + [string] $BuildNumber=$env:BUILD_BUILDNUMBER, + [string] $RunCategories="coreclr corefx", + [string] $Csproj="src\benchmarks\micro\MicroBenchmarks.csproj", + [string] $Kind="micro", + [switch] $Internal, + [string] $Configurations="CompilationMode=$CompilationMode" +) + +$RunFromPerformanceRepo = ($Repository -eq "dotnet/performance") +$UseCoreRun = ($CoreRootDirectory -ne [string]::Empty) + +$PayloadDirectory = (Join-Path $SourceDirectory "Payload") +$PerformanceDirectory = (Join-Path $PayloadDirectory "performance") +$WorkItemDirectory = (Join-Path $SourceDirectory "workitem") +$ExtraBenchmarkDotNetArguments = "--iterationCount 1 --warmupCount 0 --invocationCount 1 --unrollFactor 1 --strategy ColdStart --stopOnFirstError true" +$Creator = $env:BUILD_DEFINITIONNAME +$PerfLabArguments = "" +$HelixSourcePrefix = "pr" + +$Queue = "Windows.10.Amd64.ClientRS4.DevEx.15.8.Open" + +if ($Framework.StartsWith("netcoreapp")) { + $Queue = "Windows.10.Amd64.ClientRS4.Open" +} + +if ($Internal) { + $Queue = "Windows.10.Amd64.ClientRS5.Perf" + $PerfLabArguments = "--upload-to-perflab-container" + $ExtraBenchmarkDotNetArguments = "" + $Creator = "" + $HelixSourcePrefix = "official" +} + +$CommonSetupArguments="--frameworks $Framework --queue $Queue --build-number $BuildNumber --build-configs $Configurations" +$SetupArguments = "--repository https://github.com/$Repository --branch $Branch --get-perf-hash --commit-sha $CommitSha $CommonSetupArguments" + +if ($RunFromPerformanceRepo) { + $SetupArguments = "--perf-hash $CommitSha $CommonSetupArguments" + + robocopy $SourceDirectory $PerformanceDirectory /E /XD $PayloadDirectory $SourceDirectory\artifacts $SourceDirectory\.git +} +else { + git clone --branch master --depth 1 --quiet https://github.com/dotnet/performance $PerformanceDirectory +} + +if ($UseCoreRun) { + $NewCoreRoot = (Join-Path $PayloadDirectory "Core_Root") + Move-Item -Path $CoreRootDirectory -Destination $NewCoreRoot +} + +$DocsDir = (Join-Path $PerformanceDirectory "docs") +robocopy $DocsDir $WorkItemDirectory + +# Set variables that we will need to have in future steps +$ci = $true + +. "$PSScriptRoot\..\pipeline-logging-functions.ps1" + +# Directories +Write-PipelineSetVariable -Name 'PayloadDirectory' -Value "$PayloadDirectory" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'PerformanceDirectory' -Value "$PerformanceDirectory" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'WorkItemDirectory' -Value "$WorkItemDirectory" -IsMultiJobVariable $false + +# Script Arguments +Write-PipelineSetVariable -Name 'Python' -Value "py -3" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'ExtraBenchmarkDotNetArguments' -Value "$ExtraBenchmarkDotNetArguments" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'SetupArguments' -Value "$SetupArguments" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'PerfLabArguments' -Value "$PerfLabArguments" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'BDNCategories' -Value "$RunCategories" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'TargetCsproj' -Value "$Csproj" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'Kind' -Value "$Kind" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'Architecture' -Value "$Architecture" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'UseCoreRun' -Value "$UseCoreRun" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'RunFromPerfRepo' -Value "$RunFromPerformanceRepo" -IsMultiJobVariable $false + +# Helix Arguments +Write-PipelineSetVariable -Name 'Creator' -Value "$Creator" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'Queue' -Value "$Queue" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'HelixSourcePrefix' -Value "$HelixSourcePrefix" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name '_BuildConfig' -Value "$Architecture.$Kind.$Framework" -IsMultiJobVariable $false + +exit 0 \ No newline at end of file diff --git a/eng/common/performance/performance-setup.sh b/eng/common/performance/performance-setup.sh new file mode 100755 index 00000000000..126da5f76d4 --- /dev/null +++ b/eng/common/performance/performance-setup.sh @@ -0,0 +1,176 @@ +#!/usr/bin/env bash + +source_directory=$BUILD_SOURCESDIRECTORY +core_root_directory= +architecture=x64 +framework=netcoreapp3.0 +compilation_mode=tiered +repository=$BUILD_REPOSITORY_NAME +branch=$BUILD_SOURCEBRANCH +commit_sha=$BUILD_SOURCEVERSION +build_number=$BUILD_BUILDNUMBER +internal=false +kind="micro" +run_categories="coreclr corefx" +csproj="src\benchmarks\micro\MicroBenchmarks.csproj" +configurations= +run_from_perf_repo=false +use_core_run=true + +while (($# > 0)); do + lowerI="$(echo $1 | awk '{print tolower($0)}')" + case $lowerI in + --sourcedirectory) + source_directory=$2 + shift 2 + ;; + --corerootdirectory) + core_root_directory=$2 + shift 2 + ;; + --architecture) + architecture=$2 + shift 2 + ;; + --framework) + framework=$2 + shift 2 + ;; + --compilationmode) + compilation_mode=$2 + shift 2 + ;; + --repository) + repository=$2 + shift 2 + ;; + --branch) + branch=$2 + shift 2 + ;; + --commitsha) + commit_sha=$2 + shift 2 + ;; + --buildnumber) + build_number=$2 + shift 2 + ;; + --kind) + kind=$2 + shift 2 + ;; + --runcategories) + run_categories=$2 + shift 2 + ;; + --csproj) + csproj=$2 + shift 2 + ;; + --internal) + internal=true + shift 1 + ;; + --configurations) + configurations=$2 + shift 2 + ;; + --help) + echo "Common settings:" + echo " --corerootdirectory Directory where Core_Root exists, if running perf testing with --corerun" + echo " --architecture Architecture of the testing being run" + echo " --configurations List of key=value pairs that will be passed to perf testing infrastructure." + echo " ex: --configurations \"CompilationMode=Tiered OptimzationLevel=PGO\"" + echo " --help Print help and exit" + echo "" + echo "Advanced settings:" + echo " --framework The framework to run, if not running in master" + echo " --compliationmode The compilation mode if not passing --configurations" + echo " --sourcedirectory The directory of the sources. Defaults to env:BUILD_SOURCESDIRECTORY" + echo " --repository The name of the repository in the / format. Defaults to env:BUILD_REPOSITORY_NAME" + echo " --branch The name of the branch. Defaults to env:BUILD_SOURCEBRANCH" + echo " --commitsha The commit sha1 to run against. Defaults to env:BUILD_SOURCEVERSION" + echo " --buildnumber The build number currently running. Defaults to env:BUILD_BUILDNUMBER" + echo " --csproj The relative path to the benchmark csproj whose tests should be run. Defaults to src\benchmarks\micro\MicroBenchmarks.csproj" + echo " --kind Related to csproj. The kind of benchmarks that should be run. Defaults to micro" + echo " --runcategories Related to csproj. Categories of benchmarks to run. Defaults to \"coreclr corefx\"" + echo " --internal If the benchmarks are running as an official job." + echo "" + exit 0 + ;; + esac +done + +if [[ "$repository" == "dotnet/performance" ]]; then + run_from_perf_repo=true +fi + +if [ -z "$configurations" ]; then + configurations="CompliationMode=$compilation_mode" +fi + +if [ -z "$core_root_directory" ]; then + use_core_run=false +fi + +payload_directory=$source_directory/Payload +performance_directory=$payload_directory/performance +workitem_directory=$source_directory/workitem +extra_benchmark_dotnet_arguments="--iterationCount 1 --warmupCount 0 --invocationCount 1 --unrollFactor 1 --strategy ColdStart --stopOnFirstError true" +perflab_arguments= +queue=Ubuntu.1804.Amd64.Open +creator=$BUILD_DEFINITIONNAME +helix_source_prefix="pr" + +if [[ "$internal" == true ]]; then + perflab_arguments="--upload-to-perflab-container" + helix_source_prefix="official" + creator= + extra_benchmark_dotnet_arguments= + + if [[ "$architecture" = "arm64" ]]; then + queue=Ubuntu.1804.Arm64.Perf + else + queue=Ubuntu.1804.Amd64.Perf + fi +fi + +common_setup_arguments="--frameworks $framework --queue $queue --build-number $build_number --build-configs $configurations" +setup_arguments="--repository https://github.com/$repository --branch $branch --get-perf-hash --commit-sha $commit_sha $common_setup_arguments" + +if [[ "$run_from_perf_repo" = true ]]; then + payload_directory= + workitem_directory=$source_directory + performance_directory=$workitem_directory + setup_arguments="--perf-hash $commit_sha $common_setup_arguments" +else + git clone --branch master --depth 1 --quiet https://github.com/dotnet/performance $performance_directory + + docs_directory=$performance_directory/docs + mv $docs_directory $workitem_directory +fi + +if [[ "$use_core_run" = true ]]; then + new_core_root=$payload_directory/Core_Root + mv $core_root_directory $new_core_root +fi + +# Make sure all of our variables are available for future steps +echo "##vso[task.setvariable variable=UseCoreRun]$use_core_run" +echo "##vso[task.setvariable variable=Architecture]$architecture" +echo "##vso[task.setvariable variable=PayloadDirectory]$payload_directory" +echo "##vso[task.setvariable variable=PerformanceDirectory]$performance_directory" +echo "##vso[task.setvariable variable=WorkItemDirectory]$workitem_directory" +echo "##vso[task.setvariable variable=Queue]$queue" +echo "##vso[task.setvariable variable=SetupArguments]$setup_arguments" +echo "##vso[task.setvariable variable=Python]python3" +echo "##vso[task.setvariable variable=PerfLabArguments]$perflab_arguments" +echo "##vso[task.setvariable variable=ExtraBenchmarkDotNetArguments]$extra_benchmark_dotnet_arguments" +echo "##vso[task.setvariable variable=BDNCategories]$run_categories" +echo "##vso[task.setvariable variable=TargetCsproj]$csproj" +echo "##vso[task.setvariable variable=RunFromPerfRepo]$run_from_perf_repo" +echo "##vso[task.setvariable variable=Creator]$creator" +echo "##vso[task.setvariable variable=HelixSourcePrefix]$helix_source_prefix" +echo "##vso[task.setvariable variable=Kind]$kind" +echo "##vso[task.setvariable variable=_BuildConfig]$architecture.$kind.$framework" \ No newline at end of file diff --git a/eng/common/pipeline-logging-functions.ps1 b/eng/common/pipeline-logging-functions.ps1 index 7b61376f8aa..af5f48aaceb 100644 --- a/eng/common/pipeline-logging-functions.ps1 +++ b/eng/common/pipeline-logging-functions.ps1 @@ -77,13 +77,14 @@ function Write-PipelineTaskError { [string]$Name, [string]$Value, [switch]$Secret, - [switch]$AsOutput) - + [switch]$AsOutput, + [bool]$IsMultiJobVariable=$true) + if($ci) { Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data $Value -Properties @{ 'variable' = $Name 'isSecret' = $Secret - 'isOutput' = 'true' + 'isOutput' = $IsMultiJobVariable } -AsOutput:$AsOutput } } diff --git a/eng/common/pipeline-logging-functions.sh b/eng/common/pipeline-logging-functions.sh old mode 100644 new mode 100755 index 6098f9a5438..1c560a50613 --- a/eng/common/pipeline-logging-functions.sh +++ b/eng/common/pipeline-logging-functions.sh @@ -39,11 +39,11 @@ function Write-PipelineTaskError { return fi - message_type="error" - sourcepath='' - linenumber='' - columnnumber='' - error_code='' + local message_type="error" + local sourcepath='' + local linenumber='' + local columnnumber='' + local error_code='' while [[ $# -gt 0 ]]; do opt="$(echo "${1/#--/-}" | awk '{print tolower($0)}')" @@ -76,7 +76,7 @@ function Write-PipelineTaskError { shift done - message="##vso[task.logissue" + local message="##vso[task.logissue" message="$message type=$message_type" @@ -100,3 +100,73 @@ function Write-PipelineTaskError { echo "$message" } +function Write-PipelineSetVariable { + if [[ "$ci" != true ]]; then + return + fi + + local name='' + local value='' + local secret=false + local as_output=false + local is_multi_job_variable=true + + while [[ $# -gt 0 ]]; do + opt="$(echo "${1/#--/-}" | awk '{print tolower($0)}')" + case "$opt" in + -name|-n) + name=$2 + shift + ;; + -value|-v) + value=$2 + shift + ;; + -secret|-s) + secret=true + ;; + -as_output|-a) + as_output=true + ;; + -is_multi_job_variable|-i) + is_multi_job_variable=$2 + shift + ;; + esac + shift + done + + value=${value/;/%3B} + value=${value/\\r/%0D} + value=${value/\\n/%0A} + value=${value/]/%5D} + + local message="##vso[task.setvariable variable=$name;isSecret=$secret;isOutput=$is_multi_job_variable]$value" + + if [[ "$as_output" == true ]]; then + $message + else + echo "$message" + fi +} + +function Write-PipelinePrependPath { + local prepend_path='' + + while [[ $# -gt 0 ]]; do + opt="$(echo "${1/#--/-}" | awk '{print tolower($0)}')" + case "$opt" in + -path|-p) + prepend_path=$2 + shift + ;; + esac + shift + done + + export PATH="$prepend_path:$PATH" + + if [[ "$ci" == true ]]; then + echo "##vso[task.prependpath]$prepend_path" + fi +} \ No newline at end of file diff --git a/eng/common/post-build/darc-gather-drop.ps1 b/eng/common/post-build/darc-gather-drop.ps1 new file mode 100644 index 00000000000..93a0bd83285 --- /dev/null +++ b/eng/common/post-build/darc-gather-drop.ps1 @@ -0,0 +1,35 @@ +param( + [Parameter(Mandatory=$true)][int] $BarBuildId, # ID of the build which assets should be downloaded + [Parameter(Mandatory=$true)][string] $DropLocation, # Where the assets should be downloaded to + [Parameter(Mandatory=$true)][string] $MaestroApiAccessToken, # Token used to access Maestro API + [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = "https://maestro-prod.westus2.cloudapp.azure.com", # Maestro API URL + [Parameter(Mandatory=$false)][string] $MaestroApiVersion = "2019-01-16" # Version of Maestro API to use +) + +. $PSScriptRoot\post-build-utils.ps1 + +try { + Write-Host "Installing DARC ..." + + . $PSScriptRoot\..\darc-init.ps1 + $exitCode = $LASTEXITCODE + + if ($exitCode -ne 0) { + Write-PipelineTaskError "Something failed while running 'darc-init.ps1'. Check for errors above. Exiting now..." + ExitWithExitCode $exitCode + } + + darc gather-drop --non-shipping ` + --continue-on-error ` + --id $BarBuildId ` + --output-dir $DropLocation ` + --bar-uri $MaestroApiEndpoint ` + --password $MaestroApiAccessToken ` + --latest-location +} +catch { + Write-Host $_ + Write-Host $_.Exception + Write-Host $_.ScriptStackTrace + ExitWithExitCode 1 +} diff --git a/eng/common/post-build/nuget-validation.ps1 b/eng/common/post-build/nuget-validation.ps1 index 1bdced1e307..78ed0d540f5 100644 --- a/eng/common/post-build/nuget-validation.ps1 +++ b/eng/common/post-build/nuget-validation.ps1 @@ -6,10 +6,7 @@ param( [Parameter(Mandatory=$true)][string] $ToolDestinationPath # Where the validation tool should be downloaded to ) -$ErrorActionPreference = "Stop" -Set-StrictMode -Version 2.0 - -. $PSScriptRoot\..\tools.ps1 +. $PSScriptRoot\post-build-utils.ps1 try { $url = "https://raw.githubusercontent.com/NuGet/NuGetGallery/jver-verify/src/VerifyMicrosoftPackage/verify.ps1" diff --git a/eng/common/post-build/post-build-utils.ps1 b/eng/common/post-build/post-build-utils.ps1 new file mode 100644 index 00000000000..551ae113f89 --- /dev/null +++ b/eng/common/post-build/post-build-utils.ps1 @@ -0,0 +1,90 @@ +# Most of the functions in this file require the variables `MaestroApiEndPoint`, +# `MaestroApiVersion` and `MaestroApiAccessToken` to be globally available. + +$ErrorActionPreference = "Stop" +Set-StrictMode -Version 2.0 + +# `tools.ps1` checks $ci to perform some actions. Since the post-build +# scripts don't necessarily execute in the same agent that run the +# build.ps1/sh script this variable isn't automatically set. +$ci = $true +. $PSScriptRoot\..\tools.ps1 + +function Create-MaestroApiRequestHeaders([string]$ContentType = "application/json") { + Validate-MaestroVars + + $headers = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' + $headers.Add('Accept', $ContentType) + $headers.Add('Authorization',"Bearer $MaestroApiAccessToken") + return $headers +} + +function Get-MaestroChannel([int]$ChannelId) { + Validate-MaestroVars + + $apiHeaders = Create-MaestroApiRequestHeaders + $apiEndpoint = "$MaestroApiEndPoint/api/channels/${ChannelId}?api-version=$MaestroApiVersion" + + $result = try { Invoke-WebRequest -Method Get -Uri $apiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } + return $result +} + +function Get-MaestroBuild([int]$BuildId) { + Validate-MaestroVars + + $apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken + $apiEndpoint = "$MaestroApiEndPoint/api/builds/${BuildId}?api-version=$MaestroApiVersion" + + $result = try { return Invoke-WebRequest -Method Get -Uri $apiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } + return $result +} + +function Get-MaestroSubscriptions([string]$SourceRepository, [int]$ChannelId) { + Validate-MaestroVars + + $SourceRepository = [System.Web.HttpUtility]::UrlEncode($SourceRepository) + $apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken + $apiEndpoint = "$MaestroApiEndPoint/api/subscriptions?sourceRepository=$SourceRepository&channelId=$ChannelId&api-version=$MaestroApiVersion" + + $result = try { Invoke-WebRequest -Method Get -Uri $apiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } + return $result +} + +function Trigger-Subscription([string]$SubscriptionId) { + Validate-MaestroVars + + $apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken + $apiEndpoint = "$MaestroApiEndPoint/api/subscriptions/$SubscriptionId/trigger?api-version=$MaestroApiVersion" + Invoke-WebRequest -Uri $apiEndpoint -Headers $apiHeaders -Method Post | Out-Null +} + +function Assign-BuildToChannel([int]$BuildId, [int]$ChannelId) { + Validate-MaestroVars + + $apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken + $apiEndpoint = "$MaestroApiEndPoint/api/channels/${ChannelId}/builds/${BuildId}?api-version=$MaestroApiVersion" + Invoke-WebRequest -Method Post -Uri $apiEndpoint -Headers $apiHeaders | Out-Null +} + +function Validate-MaestroVars { + try { + Get-Variable MaestroApiEndPoint -Scope Global | Out-Null + Get-Variable MaestroApiVersion -Scope Global | Out-Null + Get-Variable MaestroApiAccessToken -Scope Global | Out-Null + + if (!($MaestroApiEndPoint -Match "^http[s]?://maestro-(int|prod).westus2.cloudapp.azure.com$")) { + Write-PipelineTaskError "MaestroApiEndPoint is not a valid Maestro URL. '$MaestroApiEndPoint'" + ExitWithExitCode 1 + } + + if (!($MaestroApiVersion -Match "^[0-9]{4}-[0-9]{2}-[0-9]{2}$")) { + Write-PipelineTaskError "MaestroApiVersion does not match a version string in the format yyyy-MM-DD. '$MaestroApiVersion'" + ExitWithExitCode 1 + } + } + catch { + Write-PipelineTaskError "Error: Variables `MaestroApiEndPoint`, `MaestroApiVersion` and `MaestroApiAccessToken` are required while using this script." + Write-Host $_ + ExitWithExitCode 1 + } +} diff --git a/eng/common/post-build/promote-build.ps1 b/eng/common/post-build/promote-build.ps1 index 84a608fa569..e5ae85f2517 100644 --- a/eng/common/post-build/promote-build.ps1 +++ b/eng/common/post-build/promote-build.ps1 @@ -1,30 +1,25 @@ param( [Parameter(Mandatory=$true)][int] $BuildId, [Parameter(Mandatory=$true)][int] $ChannelId, - [Parameter(Mandatory=$true)][string] $BarToken, - [string] $MaestroEndpoint = "https://maestro-prod.westus2.cloudapp.azure.com", - [string] $ApiVersion = "2019-01-16" + [Parameter(Mandatory=$true)][string] $MaestroApiAccessToken, + [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = "https://maestro-prod.westus2.cloudapp.azure.com", + [Parameter(Mandatory=$false)][string] $MaestroApiVersion = "2019-01-16" ) -$ErrorActionPreference = "Stop" -Set-StrictMode -Version 2.0 - -. $PSScriptRoot\..\tools.ps1 - -function Get-Headers([string]$accept, [string]$barToken) { - $headers = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' - $headers.Add('Accept',$accept) - $headers.Add('Authorization',"Bearer $barToken") - return $headers -} +. $PSScriptRoot\post-build-utils.ps1 try { - $maestroHeaders = Get-Headers 'application/json' $BarToken + # Check that the channel we are going to promote the build to exist + $channelInfo = Get-MaestroChannel -ChannelId $ChannelId - # Get info about which channels the build has already been promoted to - $getBuildApiEndpoint = "$MaestroEndpoint/api/builds/${BuildId}?api-version=$ApiVersion" - $buildInfo = Invoke-WebRequest -Method Get -Uri $getBuildApiEndpoint -Headers $maestroHeaders | ConvertFrom-Json + if (!$channelInfo) { + Write-Host "Channel with BAR ID $ChannelId was not found in BAR!" + ExitWithExitCode 1 + } + # Get info about which channels the build has already been promoted to + $buildInfo = Get-MaestroBuild -BuildId $BuildId + if (!$buildInfo) { Write-Host "Build with BAR ID $BuildId was not found in BAR!" ExitWithExitCode 1 @@ -40,10 +35,10 @@ try { } } - Write-Host "Build not present in channel $ChannelId. Promoting build ... " + Write-Host "Promoting build '$BuildId' to channel '$ChannelId'." + + Assign-BuildToChannel -BuildId $BuildId -ChannelId $ChannelId - $promoteBuildApiEndpoint = "$maestroEndpoint/api/channels/${ChannelId}/builds/${BuildId}?api-version=$ApiVersion" - Invoke-WebRequest -Method Post -Uri $promoteBuildApiEndpoint -Headers $maestroHeaders Write-Host "done." } catch { diff --git a/eng/common/post-build/setup-maestro-vars.ps1 b/eng/common/post-build/setup-maestro-vars.ps1 new file mode 100644 index 00000000000..d7f64dc63cb --- /dev/null +++ b/eng/common/post-build/setup-maestro-vars.ps1 @@ -0,0 +1,26 @@ +param( + [Parameter(Mandatory=$true)][string] $ReleaseConfigsPath # Full path to ReleaseConfigs.txt asset +) + +. $PSScriptRoot\post-build-utils.ps1 + +try { + $Content = Get-Content $ReleaseConfigsPath + + $BarId = $Content | Select -Index 0 + + $Channels = "" + $Content | Select -Index 1 | ForEach-Object { $Channels += "$_ ," } + + $IsStableBuild = $Content | Select -Index 2 + + Write-PipelineSetVariable -Name 'BARBuildId' -Value $BarId + Write-PipelineSetVariable -Name 'InitialChannels' -Value "$Channels" + Write-PipelineSetVariable -Name 'IsStableBuild' -Value $IsStableBuild +} +catch { + Write-Host $_ + Write-Host $_.Exception + Write-Host $_.ScriptStackTrace + ExitWithExitCode 1 +} diff --git a/eng/common/post-build/sourcelink-validation.ps1 b/eng/common/post-build/sourcelink-validation.ps1 index 8abd684e9e5..41e01ae6e67 100644 --- a/eng/common/post-build/sourcelink-validation.ps1 +++ b/eng/common/post-build/sourcelink-validation.ps1 @@ -6,10 +6,7 @@ param( [Parameter(Mandatory=$true)][string] $SourcelinkCliVersion # Version of SourceLink CLI to use ) -$ErrorActionPreference = "Stop" -Set-StrictMode -Version 2.0 - -. $PSScriptRoot\..\tools.ps1 +. $PSScriptRoot\post-build-utils.ps1 # Cache/HashMap (File -> Exist flag) used to consult whether a file exist # in the repository at a specific commit point. This is populated by inserting @@ -200,21 +197,27 @@ function ValidateSourceLinkLinks { } } -function CheckExitCode ([string]$stage) { - $exitCode = $LASTEXITCODE - if ($exitCode -ne 0) { - Write-PipelineTaskError "Something failed while '$stage'. Check for errors above. Exiting now..." - ExitWithExitCode $exitCode +function InstallSourcelinkCli { + $sourcelinkCliPackageName = "sourcelink" + + $dotnetRoot = InitializeDotNetCli -install:$true + $dotnet = "$dotnetRoot\dotnet.exe" + $toolList = & "$dotnet" tool list --global + + if (($toolList -like "*$sourcelinkCliPackageName*") -and ($toolList -like "*$sourcelinkCliVersion*")) { + Write-Host "SourceLink CLI version $sourcelinkCliVersion is already installed." + } + else { + Write-Host "Installing SourceLink CLI version $sourcelinkCliVersion..." + Write-Host "You may need to restart your command window if this is the first dotnet tool you have installed." + & "$dotnet" tool install $sourcelinkCliPackageName --version $sourcelinkCliVersion --verbosity "minimal" --global } } try { - Write-Host "Installing SourceLink CLI..." - Get-Location - . $PSScriptRoot\sourcelink-cli-init.ps1 -sourcelinkCliVersion $SourcelinkCliVersion - CheckExitCode "Running sourcelink-cli-init" + InstallSourcelinkCli - Measure-Command { ValidateSourceLinkLinks } + ValidateSourceLinkLinks } catch { Write-Host $_ diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1 index 69456854e04..d5ec51b150f 100644 --- a/eng/common/post-build/symbols-validation.ps1 +++ b/eng/common/post-build/symbols-validation.ps1 @@ -4,10 +4,7 @@ param( [Parameter(Mandatory=$true)][string] $DotnetSymbolVersion # Version of dotnet symbol to use ) -$ErrorActionPreference = "Stop" -Set-StrictMode -Version 2.0 - -. $PSScriptRoot\..\tools.ps1 +. $PSScriptRoot\post-build-utils.ps1 Add-Type -AssemblyName System.IO.Compression.FileSystem @@ -162,19 +159,25 @@ function CheckSymbolsAvailable { } } -function CheckExitCode ([string]$stage) { - $exitCode = $LASTEXITCODE - if ($exitCode -ne 0) { - Write-PipelineTaskError "Something failed while '$stage'. Check for errors above. Exiting now..." - ExitWithExitCode $exitCode +function Installdotnetsymbol { + $dotnetsymbolPackageName = "dotnet-symbol" + + $dotnetRoot = InitializeDotNetCli -install:$true + $dotnet = "$dotnetRoot\dotnet.exe" + $toolList = & "$dotnet" tool list --global + + if (($toolList -like "*$dotnetsymbolPackageName*") -and ($toolList -like "*$dotnetsymbolVersion*")) { + Write-Host "dotnet-symbol version $dotnetsymbolVersion is already installed." + } + else { + Write-Host "Installing dotnet-symbol version $dotnetsymbolVersion..." + Write-Host "You may need to restart your command window if this is the first dotnet tool you have installed." + & "$dotnet" tool install $dotnetsymbolPackageName --version $dotnetsymbolVersion --verbosity "minimal" --global } } try { - Write-Host "Installing dotnet symbol ..." - Get-Location - . $PSScriptRoot\dotnetsymbol-init.ps1 -dotnetsymbolVersion $DotnetSymbolVersion - CheckExitCode "Running dotnetsymbol-init" + Installdotnetsymbol CheckSymbolsAvailable } diff --git a/eng/common/post-build/trigger-subscriptions.ps1 b/eng/common/post-build/trigger-subscriptions.ps1 index db8a839457a..926d5b45513 100644 --- a/eng/common/post-build/trigger-subscriptions.ps1 +++ b/eng/common/post-build/trigger-subscriptions.ps1 @@ -1,33 +1,20 @@ -param( +param( [Parameter(Mandatory=$true)][string] $SourceRepo, [Parameter(Mandatory=$true)][int] $ChannelId, - [string] $MaestroEndpoint = "https://maestro-prod.westus2.cloudapp.azure.com", - [string] $BarToken, - [string] $ApiVersion = "2019-01-16" + [Parameter(Mandatory=$true)][string] $MaestroApiAccessToken, + [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = "https://maestro-prod.westus2.cloudapp.azure.com", + [Parameter(Mandatory=$false)][string] $MaestroApiVersion = "2019-01-16" ) -$ErrorActionPreference = "Stop" -Set-StrictMode -Version 2.0 - -. $PSScriptRoot\..\tools.ps1 - -function Get-Headers([string]$accept, [string]$barToken) { - $headers = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' - $headers.Add('Accept',$accept) - $headers.Add('Authorization',"Bearer $barToken") - return $headers -} +. $PSScriptRoot\post-build-utils.ps1 # Get all the $SourceRepo subscriptions -$normalizedSurceRepo = $SourceRepo.Replace('dnceng@', '') -$getSubscriptionsApiEndpoint = "$maestroEndpoint/api/subscriptions?sourceRepository=$normalizedSurceRepo&api-version=$apiVersion" -$headers = Get-Headers 'application/json' $barToken - -$subscriptions = Invoke-WebRequest -Uri $getSubscriptionsApiEndpoint -Headers $headers | ConvertFrom-Json +$normalizedSourceRepo = $SourceRepo.Replace('dnceng@', '') +$subscriptions = Get-MaestroSubscriptions -SourceRepository $normalizedSourceRepo -ChannelId $ChannelId if (!$subscriptions) { - Write-Host "No subscriptions found for source repo '$normalizedSurceRepo' in channel '$ChannelId'" - return + Write-Host "No subscriptions found for source repo '$normalizedSourceRepo' in channel '$ChannelId'" + ExitWithExitCode 0 } $subscriptionsToTrigger = New-Object System.Collections.Generic.List[string] @@ -36,21 +23,18 @@ $failedTriggeredSubscription = $false # Get all enabled subscriptions that need dependency flow on 'everyBuild' foreach ($subscription in $subscriptions) { if ($subscription.enabled -and $subscription.policy.updateFrequency -like 'everyBuild' -and $subscription.channel.id -eq $ChannelId) { - Write-Host "$subscription.id" + Write-Host "Should trigger this subscription: $subscription.id" [void]$subscriptionsToTrigger.Add($subscription.id) } } foreach ($subscriptionToTrigger in $subscriptionsToTrigger) { try { - $triggerSubscriptionApiEndpoint = "$maestroEndpoint/api/subscriptions/$subscriptionToTrigger/trigger?api-version=$apiVersion" - $headers = Get-Headers 'application/json' $BarToken - - Write-Host "Triggering subscription '$subscriptionToTrigger'..." + Write-Host "Triggering subscription '$subscriptionToTrigger'." - Invoke-WebRequest -Uri $triggerSubscriptionApiEndpoint -Headers $headers -Method Post + Trigger-Subscription -SubscriptionId $subscriptionToTrigger - Write-Host "Subscription '$subscriptionToTrigger' triggered!" + Write-Host "done." } catch { @@ -61,9 +45,13 @@ foreach ($subscriptionToTrigger in $subscriptionsToTrigger) { } } -if ($failedTriggeredSubscription) { +if ($subscriptionsToTrigger.Count -eq 0) { + Write-Host "No subscription matched source repo '$normalizedSourceRepo' and channel ID '$ChannelId'." +} +elseif ($failedTriggeredSubscription) { Write-Host "At least one subscription failed to be triggered..." ExitWithExitCode 1 } - -Write-Host "All subscriptions were triggered successfully!" +else { + Write-Host "All subscriptions were triggered successfully!" +} diff --git a/eng/common/templates/job/performance.yml b/eng/common/templates/job/performance.yml new file mode 100644 index 00000000000..ef809253d1a --- /dev/null +++ b/eng/common/templates/job/performance.yml @@ -0,0 +1,93 @@ +parameters: + steps: [] # optional -- any additional steps that need to happen before pulling down the performance repo and sending the performance benchmarks to helix (ie building your repo) + variables: [] # optional -- list of additional variables to send to the template + jobName: '' # required -- job name + displayName: '' # optional -- display name for the job. Will use jobName if not passed + pool: '' # required -- name of the Build pool + container: '' # required -- name of the container + extraSetupParameters: '' # optional -- extra arguments to pass to the setup script + frameworks: ['netcoreapp3.0'] # optional -- list of frameworks to run against + continueOnError: 'false' # optional -- determines whether to continue the build if the step errors + dependsOn: '' # optional -- dependencies of the job + timeoutInMinutes: 320 # optional -- timeout for the job + enableTelemetry: false # optional -- enable for telemetry + +jobs: +- template: ../jobs/jobs.yml + parameters: + dependsOn: ${{ parameters.dependsOn }} + enableTelemetry: ${{ parameters.enableTelemetry }} + enablePublishBuildArtifacts: true + continueOnError: ${{ parameters.continueOnError }} + + jobs: + - job: '${{ parameters.jobName }}' + + ${{ if ne(parameters.displayName, '') }}: + displayName: '${{ parameters.displayName }}' + ${{ if eq(parameters.displayName, '') }}: + displayName: '${{ parameters.jobName }}' + + timeoutInMinutes: ${{ parameters.timeoutInMinutes }} + + variables: + + - ${{ each variable in parameters.variables }}: + - ${{ if ne(variable.name, '') }}: + - name: ${{ variable.name }} + value: ${{ variable.value }} + - ${{ if ne(variable.group, '') }}: + - group: ${{ variable.group }} + + - IsInternal: '' + - HelixApiAccessToken: '' + - HelixPreCommand: '' + + - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - ${{ if eq(variables['Agent.Os'], 'Windows_NT') }}: + - HelixPreCommand: 'set "PERFLAB_UPLOAD_TOKEN=$(PerfCommandUploadToken)"' + - IsInternal: -Internal + - ${{ if ne(variables['Agent.Os'], 'Windows_NT') }}: + - HelixPreCommand: 'export PERFLAB_UPLOAD_TOKEN="$(PerfCommandUploadTokenLinux)"' + - IsInternal: --internal + - group: DotNet-HelixApi-Access + - group: dotnet-benchview + + workspace: + clean: all + pool: + ${{ parameters.pool }} + container: ${{ parameters.container }} + strategy: + matrix: + ${{ each framework in parameters.frameworks }}: + ${{ framework }}: + _Framework: ${{ framework }} + steps: + - checkout: self + clean: true + # Run all of the steps to setup repo + - ${{ each step in parameters.steps }}: + - ${{ step }} + - powershell: $(Build.SourcesDirectory)\eng\common\performance\performance-setup.ps1 $(IsInternal) -Framework $(_Framework) ${{ parameters.extraSetupParameters }} + displayName: Performance Setup (Windows) + condition: and(succeeded(), eq(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} + - script: $(Build.SourcesDirectory)/eng/common/performance/performance-setup.sh $(IsInternal) --framework $(_Framework) ${{ parameters.extraSetupParameters }} + displayName: Performance Setup (Unix) + condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} + - script: $(Python) $(PerformanceDirectory)/scripts/ci_setup.py $(SetupArguments) + displayName: Run ci setup script + # Run perf testing in helix + - template: /eng/common/templates/steps/perf-send-to-helix.yml + parameters: + HelixSource: '$(HelixSourcePrefix)/$(Build.Repository.Name)/$(Build.SourceBranch)' # sources must start with pr/, official/, prodcon/, or agent/ + HelixType: 'test/performance/$(Kind)/$(_Framework)/$(Architecture)' + HelixAccessToken: $(HelixApiAccessToken) + HelixTargetQueues: $(Queue) + HelixPreCommands: $(HelixPreCommand) + Creator: $(Creator) + WorkItemTimeout: 4:00 # 4 hours + WorkItemDirectory: '$(WorkItemDirectory)' # WorkItemDirectory can not be empty, so we send it some docs to keep it happy + CorrelationPayloadDirectory: '$(PayloadDirectory)' # it gets checked out to a folder with shorter path than WorkItemDirectory so we can avoid file name too long exceptions \ No newline at end of file diff --git a/eng/common/templates/post-build/channels/internal-servicing.yml b/eng/common/templates/post-build/channels/internal-servicing.yml index 808d46b17f2..12fd2b4653d 100644 --- a/eng/common/templates/post-build/channels/internal-servicing.yml +++ b/eng/common/templates/post-build/channels/internal-servicing.yml @@ -41,7 +41,6 @@ stages: dependsOn: setupMaestroVars variables: - group: DotNet-Blob-Feed - - group: Publish-Build-Assets - group: AzureDevOps-Artifact-Feeds-Pats - name: BARBuildId value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] @@ -81,13 +80,14 @@ stages: /p:IsInternalBuild=$(IsInternalBuild) /p:RepositoryName=$(Build.Repository.Name) /p:CommitSha=$(Build.SourceVersion) + /p:AzureStorageAccountName=$(ProxyBackedFeedsAccountName) + /p:AzureStorageAccountKey=$(dotnetfeed-storage-access-key-1) + /p:AzureDevOpsFeedsBaseUrl=$(dotnetfeed-internal-private-feed-url) + /p:StaticInternalFeed=$(dotnetfeed-internal-nonstable-feed-url) /p:NugetPath=$(Agent.BuildDirectory)\Nuget\NuGet.exe - /p:AzdoTargetFeedPAT='$(dn-bot-dnceng-unviersal-packages-rw)' - /p:TargetFeedPAT='$(dn-bot-dnceng-unviersal-packages-rw)' - /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)' /p:BARBuildId=$(BARBuildId) - /p:MaestroApiEndpoint='https://maestro-prod.westus2.cloudapp.azure.com' - /p:BuildAssetRegistryToken='$(MaestroAccessToken)' + /p:MaestroApiEndpoint='$(MaestroApiEndPoint)' + /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)' /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/' /p:BlobBasePath='$(Build.ArtifactStagingDirectory)\BlobArtifacts' /p:PackageBasePath='$(Build.ArtifactStagingDirectory)\PackageArtifacts' @@ -142,29 +142,6 @@ stages: filePath: $(Build.SourcesDirectory)/eng/common/post-build/symbols-validation.ps1 arguments: -InputPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ -ExtractPath $(Agent.BuildDirectory)/Temp/ -DotnetSymbolVersion $(SymbolToolVersion) - - job: - displayName: Gather Drop - dependsOn: setupMaestroVars - variables: - BARBuildId: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] - condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.InternalServicing_30_Channel_Id) - pool: - vmImage: 'windows-2019' - steps: - - task: PowerShell@2 - displayName: Setup Darc CLI - inputs: - targetType: filePath - filePath: '$(Build.SourcesDirectory)/eng/common/darc-init.ps1' - - - task: PowerShell@2 - displayName: Run Darc gather-drop - inputs: - targetType: inline - script: | - darc gather-drop --non-shipping --continue-on-error --id $(BARBuildId) --output-dir $(Agent.BuildDirectory)/Temp/Drop/ --bar-uri https://maestro-prod.westus2.cloudapp.azure.com/ --password $(MaestroAccessToken) --latest-location - enabled: false - - template: ../promote-build.yml parameters: - ChannelId: ${{ variables.InternalServicing_30_Channel_Id }} \ No newline at end of file + ChannelId: ${{ variables.InternalServicing_30_Channel_Id }} diff --git a/eng/common/templates/post-build/channels/public-dev-release.yml b/eng/common/templates/post-build/channels/public-dev-release.yml index 94a767bb857..afc5d364234 100644 --- a/eng/common/templates/post-build/channels/public-dev-release.yml +++ b/eng/common/templates/post-build/channels/public-dev-release.yml @@ -41,7 +41,6 @@ stages: dependsOn: setupMaestroVars variables: - group: DotNet-Blob-Feed - - group: Publish-Build-Assets - group: AzureDevOps-Artifact-Feeds-Pats - name: BARBuildId value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] @@ -77,6 +76,7 @@ stages: filePath: eng\common\sdk-task.ps1 arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet /p:ChannelId=$(PublicDevRelease_30_Channel_Id) + /p:ArtifactsCategory=$(_DotNetArtifactsCategory) /p:IsStableBuild=$(IsStableBuild) /p:IsInternalBuild=$(IsInternalBuild) /p:RepositoryName=$(Build.Repository.Name) @@ -86,8 +86,8 @@ stages: /p:TargetFeedPAT='$(dn-bot-dnceng-unviersal-packages-rw)' /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)' /p:BARBuildId=$(BARBuildId) - /p:MaestroApiEndpoint='https://maestro-prod.westus2.cloudapp.azure.com' - /p:BuildAssetRegistryToken='$(MaestroAccessToken)' + /p:MaestroApiEndpoint='$(MaestroApiEndPoint)' + /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)' /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/' /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/' /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/' @@ -138,27 +138,9 @@ stages: filePath: $(Build.SourcesDirectory)/eng/common/post-build/symbols-validation.ps1 arguments: -InputPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ -ExtractPath $(Agent.BuildDirectory)/Temp/ -DotnetSymbolVersion $(SymbolToolVersion) - - job: - displayName: Gather Drop - dependsOn: setupMaestroVars - variables: - BARBuildId: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] - condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.PublicDevRelease_30_Channel_Id) - pool: - vmImage: 'windows-2019' - steps: - - task: PowerShell@2 - displayName: Setup Darc CLI - inputs: - targetType: filePath - filePath: '$(Build.SourcesDirectory)/eng/common/darc-init.ps1' - - - task: PowerShell@2 - displayName: Run Darc gather-drop - inputs: - targetType: inline - script: | - darc gather-drop --non-shipping --continue-on-error --id $(BARBuildId) --output-dir $(Agent.BuildDirectory)/Temp/Drop/ --bar-uri https://maestro-prod.westus2.cloudapp.azure.com/ --password $(MaestroAccessToken) --latest-location + - template: ../darc-gather-drop.yml + parameters: + ChannelId: ${{ variables.PublicDevRelease_30_Channel_Id }} - template: ../promote-build.yml parameters: diff --git a/eng/common/templates/post-build/channels/public-release.yml b/eng/common/templates/post-build/channels/public-release.yml index 25923020df8..4c63fb43f0c 100644 --- a/eng/common/templates/post-build/channels/public-release.yml +++ b/eng/common/templates/post-build/channels/public-release.yml @@ -41,7 +41,6 @@ stages: dependsOn: setupMaestroVars variables: - group: DotNet-Blob-Feed - - group: Publish-Build-Assets - group: AzureDevOps-Artifact-Feeds-Pats - name: BARBuildId value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] @@ -81,13 +80,14 @@ stages: /p:IsInternalBuild=$(IsInternalBuild) /p:RepositoryName=$(Build.Repository.Name) /p:CommitSha=$(Build.SourceVersion) - /p:NugetPath=$(Agent.BuildDirectory)/Nuget/NuGet.exe - /p:AzdoTargetFeedPAT='$(dn-bot-dnceng-unviersal-packages-rw)' - /p:TargetFeedPAT='$(dn-bot-dnceng-unviersal-packages-rw)' - /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)' + /p:AzureStorageAccountName=$(ProxyBackedFeedsAccountName) + /p:AzureStorageAccountKey=$(dotnetfeed-storage-access-key-1) + /p:AzureDevOpsFeedsBaseUrl=$(dotnetfeed-internal-private-feed-url) + /p:StaticInternalFeed=$(dotnetfeed-internal-nonstable-feed-url) + /p:NugetPath=$(Agent.BuildDirectory)\Nuget\NuGet.exe /p:BARBuildId=$(BARBuildId) - /p:MaestroApiEndpoint='https://maestro-prod.westus2.cloudapp.azure.com' - /p:BuildAssetRegistryToken='$(MaestroAccessToken)' + /p:MaestroApiEndpoint='$(MaestroApiEndPoint)' + /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)' /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/' /p:BlobBasePath='$(Build.ArtifactStagingDirectory)\BlobArtifacts' /p:PackageBasePath='$(Build.ArtifactStagingDirectory)\PackageArtifacts' @@ -142,29 +142,6 @@ stages: filePath: $(Build.SourcesDirectory)/eng/common/post-build/symbols-validation.ps1 arguments: -InputPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ -ExtractPath $(Agent.BuildDirectory)/Temp/ -DotnetSymbolVersion $(SymbolToolVersion) - - job: - displayName: Gather Drop - dependsOn: setupMaestroVars - variables: - BARBuildId: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] - condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.PublicRelease_30_Channel_Id) - pool: - vmImage: 'windows-2019' - steps: - - task: PowerShell@2 - displayName: Setup Darc CLI - inputs: - targetType: filePath - filePath: '$(Build.SourcesDirectory)/eng/common/darc-init.ps1' - - - task: PowerShell@2 - displayName: Run Darc gather-drop - inputs: - targetType: inline - script: | - darc gather-drop --non-shipping --continue-on-error --id $(BARBuildId) --output-dir $(Agent.BuildDirectory)/Temp/Drop/ --bar-uri https://maestro-prod.westus2.cloudapp.azure.com/ --password $(MaestroAccessToken) --latest-location - enabled: false - - template: ../promote-build.yml parameters: ChannelId: ${{ variables.PublicRelease_30_Channel_Id }} diff --git a/eng/common/templates/post-build/channels/public-validation-release.yml b/eng/common/templates/post-build/channels/public-validation-release.yml index 114477d3adb..1089ac5fa6b 100644 --- a/eng/common/templates/post-build/channels/public-validation-release.yml +++ b/eng/common/templates/post-build/channels/public-validation-release.yml @@ -12,7 +12,6 @@ stages: dependsOn: setupMaestroVars variables: - group: DotNet-Blob-Feed - - group: Publish-Build-Assets - group: AzureDevOps-Artifact-Feeds-Pats - name: BARBuildId value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] @@ -48,6 +47,7 @@ stages: filePath: eng\common\sdk-task.ps1 arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet /p:ChannelId=$(PublicValidationRelease_30_Channel_Id) + /p:ArtifactsCategory=$(_DotNetValidationArtifactsCategory) /p:IsStableBuild=$(IsStableBuild) /p:IsInternalBuild=$(IsInternalBuild) /p:RepositoryName=$(Build.Repository.Name) @@ -57,13 +57,13 @@ stages: /p:TargetFeedPAT='$(dn-bot-dnceng-unviersal-packages-rw)' /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)' /p:BARBuildId=$(BARBuildId) - /p:MaestroApiEndpoint='https://maestro-prod.westus2.cloudapp.azure.com' - /p:BuildAssetRegistryToken='$(MaestroAccessToken)' + /p:MaestroApiEndpoint='$(MaestroApiEndPoint)' + /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)' /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/' /p:BlobBasePath='$(Build.ArtifactStagingDirectory)\BlobArtifacts' /p:PackageBasePath='$(Build.ArtifactStagingDirectory)\PackageArtifacts' /p:Configuration=Release - + - task: NuGetCommand@2 displayName: Publish Packages to AzDO Feed condition: contains(variables['TargetAzDOFeed'], 'pkgs.visualstudio.com') @@ -90,29 +90,9 @@ stages: jobs: - template: ../setup-maestro-vars.yml - - job: - displayName: Gather Drop - dependsOn: setupMaestroVars - condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.PublicValidationRelease_30_Channel_Id) - variables: - - name: BARBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] - - group: Publish-Build-Assets - pool: - vmImage: 'windows-2019' - steps: - - task: PowerShell@2 - displayName: Setup Darc CLI - inputs: - targetType: filePath - filePath: '$(Build.SourcesDirectory)/eng/common/darc-init.ps1' - - - task: PowerShell@2 - displayName: Run Darc gather-drop - inputs: - targetType: inline - script: | - darc gather-drop --non-shipping --continue-on-error --id $(BARBuildId) --output-dir $(Agent.BuildDirectory)/Temp/Drop/ --bar-uri https://maestro-prod.westus2.cloudapp.azure.com --password $(MaestroAccessToken) --latest-location + - template: ../darc-gather-drop.yml + parameters: + ChannelId: ${{ variables.PublicValidationRelease_30_Channel_Id }} - template: ../promote-build.yml parameters: diff --git a/eng/common/templates/post-build/common-variables.yml b/eng/common/templates/post-build/common-variables.yml index 82834673520..bd0bc5e4daa 100644 --- a/eng/common/templates/post-build/common-variables.yml +++ b/eng/common/templates/post-build/common-variables.yml @@ -1,18 +1,39 @@ variables: + - group: Publish-Build-Assets + # .NET Core 3 Dev - PublicDevRelease_30_Channel_Id: 3 + - name: PublicDevRelease_30_Channel_Id + value: 3 # .NET Tools - Validation - PublicValidationRelease_30_Channel_Id: 9 + - name: PublicValidationRelease_30_Channel_Id + value: 9 # .NET Core 3.0 Internal Servicing - InternalServicing_30_Channel_Id: 184 + - name: InternalServicing_30_Channel_Id + value: 184 # .NET Core 3.0 Release - PublicRelease_30_Channel_Id: 19 + - name: PublicRelease_30_Channel_Id + value: 19 # Whether the build is internal or not - IsInternalBuild: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }} + - name: IsInternalBuild + value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }} + + # Storage account name for proxy-backed feeds + - name: ProxyBackedFeedsAccountName + value: dotnetfeed + + # Default Maestro++ API Endpoint and API Version + - name: MaestroApiEndPoint + value: "https://maestro-prod.westus2.cloudapp.azure.com" + - name: MaestroApiAccessToken + value: $(MaestroAccessToken) + - name: MaestroApiVersion + value: "2019-01-16" - SourceLinkCLIVersion: 3.0.0 - SymbolToolVersion: 1.0.1 + - name: SourceLinkCLIVersion + value: 3.0.0 + - name: SymbolToolVersion + value: 1.0.1 diff --git a/eng/common/templates/post-build/darc-gather-drop.yml b/eng/common/templates/post-build/darc-gather-drop.yml new file mode 100644 index 00000000000..f4e3bfcf5cd --- /dev/null +++ b/eng/common/templates/post-build/darc-gather-drop.yml @@ -0,0 +1,23 @@ +parameters: + ChannelId: 0 + +jobs: +- job: gatherDrop + displayName: Gather Drop + dependsOn: setupMaestroVars + condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], ${{ parameters.ChannelId }}) + variables: + - name: BARBuildId + value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] + pool: + vmImage: 'windows-2019' + steps: + - task: PowerShell@2 + displayName: Darc gather-drop + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/post-build/darc-gather-drop.ps1 + arguments: -BarBuildId $(BARBuildId) + -DropLocation $(Agent.BuildDirectory)/Temp/Drop/ + -MaestroApiAccessToken $(MaestroApiAccessToken) + -MaestroApiEndPoint $(MaestroApiEndPoint) + -MaestroApiVersion $(MaestroApiVersion) diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index daa799259c7..0872db4ed94 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -7,9 +7,12 @@ parameters: enable: false params: '' + # Which stages should finish execution before post-build stages start + dependsOn: [build] + stages: - stage: validate - dependsOn: build + dependsOn: ${{ parameters.dependsOn }} displayName: Validate jobs: - ${{ if eq(parameters.enableNugetValidation, 'true') }}: diff --git a/eng/common/templates/post-build/promote-build.yml b/eng/common/templates/post-build/promote-build.yml index af48b0b339e..9387c583b31 100644 --- a/eng/common/templates/post-build/promote-build.yml +++ b/eng/common/templates/post-build/promote-build.yml @@ -11,7 +11,6 @@ jobs: value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ] - name: ChannelId value: ${{ parameters.ChannelId }} - - group: Publish-Build-Assets pool: vmImage: 'windows-2019' steps: @@ -21,4 +20,6 @@ jobs: filePath: $(Build.SourcesDirectory)/eng/common/post-build/promote-build.ps1 arguments: -BuildId $(BARBuildId) -ChannelId $(ChannelId) - -BarToken $(MaestroAccessToken) + -MaestroApiAccessToken $(MaestroApiAccessToken) + -MaestroApiEndPoint $(MaestroApiEndPoint) + -MaestroApiVersion $(MaestroApiVersion) diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml index f6120dc1e1c..56242b068e1 100644 --- a/eng/common/templates/post-build/setup-maestro-vars.yml +++ b/eng/common/templates/post-build/setup-maestro-vars.yml @@ -14,22 +14,5 @@ jobs: name: setReleaseVars displayName: Set Release Configs Vars inputs: - targetType: inline - script: | - # This is needed to make Write-PipelineSetVariable works in this context - $ci = $true - - . "$(Build.SourcesDirectory)/eng/common/tools.ps1" - - $Content = Get-Content "$(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt" - - $BarId = $Content | Select -Index 0 - - $Channels = "" - $Content | Select -Index 1 | ForEach-Object { $Channels += "$_ ," } - - $IsStableBuild = $Content | Select -Index 2 - - Write-PipelineSetVariable -Name 'BARBuildId' -Value $BarId - Write-PipelineSetVariable -Name 'InitialChannels' -Value "$Channels" - Write-PipelineSetVariable -Name 'IsStableBuild' -Value $IsStableBuild + filePath: $(Build.SourcesDirectory)/eng/common/post-build/setup-maestro-vars.ps1 + arguments: -ReleaseConfigsPath '$(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt' diff --git a/eng/common/templates/post-build/trigger-subscription.yml b/eng/common/templates/post-build/trigger-subscription.yml index 65259d4e685..da669030daf 100644 --- a/eng/common/templates/post-build/trigger-subscription.yml +++ b/eng/common/templates/post-build/trigger-subscription.yml @@ -8,4 +8,6 @@ steps: filePath: $(Build.SourcesDirectory)/eng/common/post-build/trigger-subscriptions.ps1 arguments: -SourceRepo $(Build.Repository.Uri) -ChannelId ${{ parameters.ChannelId }} - -BarToken $(MaestroAccessTokenInt) \ No newline at end of file + -MaestroApiAccessToken $(MaestroAccessToken) + -MaestroApiEndPoint $(MaestroApiEndPoint) + -MaestroApiVersion $(MaestroApiVersion) diff --git a/eng/common/templates/steps/perf-send-to-helix.yml b/eng/common/templates/steps/perf-send-to-helix.yml new file mode 100644 index 00000000000..b3ea9acf1f1 --- /dev/null +++ b/eng/common/templates/steps/perf-send-to-helix.yml @@ -0,0 +1,66 @@ +# Please remember to update the documentation if you make changes to these parameters! +parameters: + HelixSource: 'pr/default' # required -- sources must start with pr/, official/, prodcon/, or agent/ + HelixType: 'tests/default/' # required -- Helix telemetry which identifies what type of data this is; should include "test" for clarity and must end in '/' + HelixBuild: $(Build.BuildNumber) # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number + HelixTargetQueues: '' # required -- semicolon delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues + HelixAccessToken: '' # required -- access token to make Helix API requests; should be provided by the appropriate variable group + HelixPreCommands: '' # optional -- commands to run before Helix work item execution + HelixPostCommands: '' # optional -- commands to run after Helix work item execution + WorkItemDirectory: '' # optional -- a payload directory to zip up and send to Helix; requires WorkItemCommand; incompatible with XUnitProjects + CorrelationPayloadDirectory: '' # optional -- a directory to zip up and send to Helix as a correlation payload + IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion + DotNetCliPackageType: '' # optional -- either 'sdk' or 'runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases.json + DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases.json + EnableXUnitReporter: false # optional -- true enables XUnit result reporting to Mission Control + WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget." + Creator: '' # optional -- if the build is external, use this to specify who is sending the job + DisplayNamePrefix: 'Send job to Helix' # optional -- rename the beginning of the displayName of the steps in AzDO + condition: succeeded() # optional -- condition for step to execute; defaults to succeeded() + continueOnError: false # optional -- determines whether to continue the build if the step errors; defaults to false + +steps: + - powershell: $(Build.SourcesDirectory)\eng\common\msbuild.ps1 $(Build.SourcesDirectory)\eng\common\performance\perfhelixpublish.proj /restore /t:Test /bl:$(Build.SourcesDirectory)\artifacts\log\$env:BuildConfig\SendToHelix.binlog + displayName: ${{ parameters.DisplayNamePrefix }} (Windows) + env: + BuildConfig: $(_BuildConfig) + HelixSource: ${{ parameters.HelixSource }} + HelixType: ${{ parameters.HelixType }} + HelixBuild: ${{ parameters.HelixBuild }} + HelixTargetQueues: ${{ parameters.HelixTargetQueues }} + HelixAccessToken: ${{ parameters.HelixAccessToken }} + HelixPreCommands: ${{ parameters.HelixPreCommands }} + HelixPostCommands: ${{ parameters.HelixPostCommands }} + WorkItemDirectory: ${{ parameters.WorkItemDirectory }} + CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} + IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} + DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} + DotNetCliVersion: ${{ parameters.DotNetCliVersion }} + EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }} + WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} + Creator: ${{ parameters.Creator }} + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} + - script: $BUILD_SOURCESDIRECTORY/eng/common/msbuild.sh $BUILD_SOURCESDIRECTORY/eng/common/performance/perfhelixpublish.proj /restore /t:Test /bl:$BUILD_SOURCESDIRECTORY/artifacts/log/$BuildConfig/SendToHelix.binlog + displayName: ${{ parameters.DisplayNamePrefix }} (Unix) + env: + BuildConfig: $(_BuildConfig) + HelixSource: ${{ parameters.HelixSource }} + HelixType: ${{ parameters.HelixType }} + HelixBuild: ${{ parameters.HelixBuild }} + HelixTargetQueues: ${{ parameters.HelixTargetQueues }} + HelixAccessToken: ${{ parameters.HelixAccessToken }} + HelixPreCommands: ${{ parameters.HelixPreCommands }} + HelixPostCommands: ${{ parameters.HelixPostCommands }} + WorkItemDirectory: ${{ parameters.WorkItemDirectory }} + CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} + IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} + DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} + DotNetCliVersion: ${{ parameters.DotNetCliVersion }} + EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }} + WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} + Creator: ${{ parameters.Creator }} + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 60741f03901..8fe2b11ad21 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -84,7 +84,7 @@ function Exec-Process([string]$command, [string]$commandArgs) { return $global:LASTEXITCODE = $process.ExitCode } finally { - # If we didn't finish then an error occured or the user hit ctrl-c. Either + # If we didn't finish then an error occurred or the user hit ctrl-c. Either # way kill the process if (-not $finished) { $process.Kill() @@ -147,7 +147,7 @@ function InitializeDotNetCli([bool]$install) { # It also ensures that VS msbuild will use the downloaded sdk targets. $env:PATH = "$dotnetRoot;$env:PATH" - # Make Sure that our bootstrapped dotnet cli is avaliable in future steps of the Azure Pipelines build + # Make Sure that our bootstrapped dotnet cli is available in future steps of the Azure Pipelines build Write-PipelinePrependPath -Path $dotnetRoot Write-PipelineSetVariable -Name 'DOTNET_MULTILEVEL_LOOKUP' -Value '0' Write-PipelineSetVariable -Name 'DOTNET_SKIP_FIRST_TIME_EXPERIENCE' -Value '1' @@ -169,7 +169,7 @@ function InstallDotNetSdk([string] $dotnetRoot, [string] $version, [string] $arc InstallDotNet $dotnetRoot $version $architecture } -function InstallDotNet([string] $dotnetRoot, [string] $version, [string] $architecture = "", [string] $runtime = "", [bool] $skipNonVersionedFiles = $false) { $installScript = GetDotNetInstallScript $dotnetRoot +function InstallDotNet([string] $dotnetRoot, [string] $version, [string] $architecture = "", [string] $runtime = "", [bool] $skipNonVersionedFiles = $false) { $installScript = GetDotNetInstallScript $dotnetRoot $installParameters = @{ Version = $version diff --git a/eng/common/tools.sh b/eng/common/tools.sh old mode 100644 new mode 100755 index c2f18a2a142..913b048420d --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -77,7 +77,7 @@ function ReadGlobalVersion { local pattern="\"$key\" *: *\"(.*)\"" if [[ ! $line =~ $pattern ]]; then - Write-PipelineTelemetryError -category 'InitializeTools' "Error: Cannot find \"$key\" in $global_json_file" + Write-PipelineTelemetryError -category 'InitializeToolset' "Error: Cannot find \"$key\" in $global_json_file" ExitWithExitCode 1 fi @@ -146,14 +146,10 @@ function InitializeDotNetCli { # Add dotnet to PATH. This prevents any bare invocation of dotnet in custom # build steps from using anything other than what we've downloaded. - export PATH="$dotnet_root:$PATH" + Write-PipelinePrependPath -path "$dotnet_root" - if [[ $ci == true ]]; then - # Make Sure that our bootstrapped dotnet cli is available in future steps of the Azure Pipelines build - echo "##vso[task.prependpath]$dotnet_root" - echo "##vso[task.setvariable variable=DOTNET_MULTILEVEL_LOOKUP]0" - echo "##vso[task.setvariable variable=DOTNET_SKIP_FIRST_TIME_EXPERIENCE]1" - fi + Write-PipelineSetVariable -name "DOTNET_MULTILEVEL_LOOKUP" -value "0" + Write-PipelineSetVariable -name "DOTNET_SKIP_FIRST_TIME_EXPERIENCE" -value "1" # return value _InitializeDotNetCli="$dotnet_root" @@ -249,7 +245,7 @@ function InitializeNativeTools() { then local nativeArgs="" if [[ "$ci" == true ]]; then - nativeArgs="-InstallDirectory $tools_dir" + nativeArgs="--installDirectory $tools_dir" fi "$_script_dir/init-tools-native.sh" $nativeArgs fi @@ -389,7 +385,8 @@ mkdir -p "$toolset_dir" mkdir -p "$temp_dir" mkdir -p "$log_dir" -if [[ $ci == true ]]; then - export TEMP="$temp_dir" - export TMP="$temp_dir" -fi +Write-PipelineSetVariable -name "Artifacts" -value "$artifacts_dir" +Write-PipelineSetVariable -name "Artifacts.Toolset" -value "$toolset_dir" +Write-PipelineSetVariable -name "Artifacts.Log" -value "$log_dir" +Write-PipelineSetVariable -name "Temp" -value "$temp_dir" +Write-PipelineSetVariable -name "TMP" -value "$temp_dir" diff --git a/global.json b/global.json index 4c66387e58e..fe2ea05490f 100644 --- a/global.json +++ b/global.json @@ -10,7 +10,7 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19359.6", + "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19378.1", "Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19069.2" } } diff --git a/src/absil/ilwrite.fs b/src/absil/ilwrite.fs index 38f9fcfe39f..d8f62707d0f 100644 --- a/src/absil/ilwrite.fs +++ b/src/absil/ilwrite.fs @@ -3025,7 +3025,8 @@ let generateIL requiredDataFixups (desiredMetadataVersion, generatePdb, ilg : IL //===================================================================== // TABLES+BLOBS --> PHYSICAL METADATA+BLOBS //===================================================================== -let chunk sz next = ({addr=next; size=sz}, next + sz) +let chunk sz next = ({addr=next; size=sz}, next + sz) +let emptychunk next = ({addr=next; size=0}, next) let nochunk next = ({addr= 0x0;size= 0x0; }, next) let count f arr = @@ -3513,7 +3514,7 @@ let writeBytes (os: BinaryWriter) (chunk: byte[]) = os.Write(chunk, 0, chunk.Len let writeBinaryAndReportMappings (outfile, ilg: ILGlobals, pdbfile: string option, signer: ILStrongNameSigner option, portablePDB, embeddedPDB, - embedAllSource, embedSourceList, sourceLink, emitTailcalls, deterministic, showTimes, dumpDebugInfo, pathMap) + embedAllSource, embedSourceList, sourceLink, checksumAlgorithm, emitTailcalls, deterministic, showTimes, dumpDebugInfo, pathMap) modul normalizeAssemblyRefs = // Store the public key from the signer into the manifest. This means it will be written // to the binary and also acts as an indicator to leave space for delay sign @@ -3562,7 +3563,7 @@ let writeBinaryAndReportMappings (outfile, with e -> failwith ("Could not open file for writing (binary mode): " + outfile) - let pdbData, pdbOpt, debugDirectoryChunk, debugDataChunk, debugEmbeddedPdbChunk, textV2P, mappings = + let pdbData, pdbOpt, debugDirectoryChunk, debugDataChunk, debugChecksumPdbChunk, debugEmbeddedPdbChunk, debugDeterministicPdbChunk, textV2P, mappings = try let imageBaseReal = modul.ImageBase // FIXED CHOICE @@ -3667,42 +3668,61 @@ let writeBinaryAndReportMappings (outfile, let pdbOpt = match portablePDB with | true -> - let (uncompressedLength, contentId, stream) as pdbStream = - generatePortablePdb embedAllSource embedSourceList sourceLink showTimes pdbData deterministic pathMap + let (uncompressedLength, contentId, stream, algorithmName, checkSum) as pdbStream = + generatePortablePdb embedAllSource embedSourceList sourceLink checksumAlgorithm showTimes pdbData pathMap - if embeddedPDB then Some (compressPortablePdbStream uncompressedLength contentId stream) + if embeddedPDB then + let uncompressedLength, contentId, stream = compressPortablePdbStream uncompressedLength contentId stream + Some (uncompressedLength, contentId, stream, algorithmName, checkSum) else Some pdbStream | _ -> None - let debugDirectoryChunk, next = - chunk (if pdbfile = None then - 0x0 - else if embeddedPDB && portablePDB then - sizeof_IMAGE_DEBUG_DIRECTORY * 2 + let debugDirectoryChunk, next = + chunk (if pdbfile = None then + 0x0 else - sizeof_IMAGE_DEBUG_DIRECTORY + sizeof_IMAGE_DEBUG_DIRECTORY * 2 + + (if embeddedPDB then sizeof_IMAGE_DEBUG_DIRECTORY else 0) + + (if deterministic then sizeof_IMAGE_DEBUG_DIRECTORY else 0) ) next + // The debug data is given to us by the PDB writer and appears to // typically be the type of the data plus the PDB file name. We fill // this in after we've written the binary. We approximate the size according // to what PDB writers seem to require and leave extra space just in case... let debugDataJustInCase = 40 - let debugDataChunk, next = + let debugDataChunk, next = chunk (align 0x4 (match pdbfile with | None -> 0 | Some f -> (24 + System.Text.Encoding.Unicode.GetByteCount f // See bug 748444 + debugDataJustInCase))) next - let debugEmbeddedPdbChunk, next = - let streamLength = - match pdbOpt with - | Some (_, _, stream) -> int stream.Length - | None -> 0 - chunk (align 0x4 (match embeddedPDB with - | true -> 8 + streamLength - | _ -> 0 )) next + let debugChecksumPdbChunk, next = + chunk (align 0x4 (match pdbOpt with + | Some (_, _, _, algorithmName, checkSum) -> + let alg = System.Text.Encoding.UTF8.GetBytes(algorithmName) + let size = alg.Length + 1 + checkSum.Length + size + | None -> 0)) next + + let debugEmbeddedPdbChunk, next = + if embeddedPDB then + let streamLength = + match pdbOpt with + | Some (_, _, stream, _, _) -> int stream.Length + | None -> 0 + chunk (align 0x4 (match embeddedPDB with + | true -> 8 + streamLength + | _ -> 0 )) next + else + nochunk next + + let debugDeterministicPdbChunk, next = + if deterministic then emptychunk next + else nochunk next + let textSectionSize = next - textSectionAddr let nextPhys = align alignPhys (textSectionPhysLoc + textSectionSize) @@ -3801,35 +3821,39 @@ let writeBinaryAndReportMappings (outfile, if pCurrent <> pExpected then failwith ("warning: "+chunkName+" not where expected, pCurrent = "+string pCurrent+", p.addr = "+string pExpected) writeBytes os chunk - + let writePadding (os: BinaryWriter) _comment sz = if sz < 0 then failwith "writePadding: size < 0" for i = 0 to sz - 1 do os.Write 0uy - + // Now we've computed all the offsets, write the image - + write (Some msdosHeaderChunk.addr) os "msdos header" msdosHeader - + write (Some peSignatureChunk.addr) os "pe signature" [| |] - + writeInt32 os 0x4550 - + write (Some peFileHeaderChunk.addr) os "pe file header" [| |] - + if (modul.Platform = Some AMD64) then writeInt32AsUInt16 os 0x8664 // Machine - IMAGE_FILE_MACHINE_AMD64 elif isItanium then writeInt32AsUInt16 os 0x200 else writeInt32AsUInt16 os 0x014c // Machine - IMAGE_FILE_MACHINE_I386 - + writeInt32AsUInt16 os numSections - let pdbData = + let pdbData = + // Hash code, data and metadata if deterministic then - // Hash code, data and metadata - use sha = System.Security.Cryptography.SHA1.Create() // IncrementalHash is core only + use sha = + match checksumAlgorithm with + | HashAlgorithm.Sha1 -> System.Security.Cryptography.SHA1.Create() :> System.Security.Cryptography.HashAlgorithm + | HashAlgorithm.Sha256 -> System.Security.Cryptography.SHA256.Create() :> System.Security.Cryptography.HashAlgorithm + let hCode = sha.ComputeHash code let hData = sha.ComputeHash data let hMeta = sha.ComputeHash metadata @@ -3845,6 +3869,7 @@ let writeBinaryAndReportMappings (outfile, // Use last 4 bytes for timestamp - High bit set, to stop tool chains becoming confused let timestamp = int final.[16] ||| (int final.[17] <<< 8) ||| (int final.[18] <<< 16) ||| (int (final.[19] ||| 128uy) <<< 24) writeInt32 os timestamp + // Update pdbData with new guid and timestamp. Portable and embedded PDBs don't need the ModuleID // Full and PdbOnly aren't supported under deterministic builds currently, they rely on non-determinsitic Windows native code { pdbData with ModuleID = final.[0..15] ; Timestamp = timestamp } @@ -4130,10 +4155,14 @@ let writeBinaryAndReportMappings (outfile, if pdbfile.IsSome then write (Some (textV2P debugDirectoryChunk.addr)) os "debug directory" (Array.create debugDirectoryChunk.size 0x0uy) write (Some (textV2P debugDataChunk.addr)) os "debug data" (Array.create debugDataChunk.size 0x0uy) + write (Some (textV2P debugChecksumPdbChunk.addr)) os "debug checksum" (Array.create debugChecksumPdbChunk.size 0x0uy) if embeddedPDB then write (Some (textV2P debugEmbeddedPdbChunk.addr)) os "debug data" (Array.create debugEmbeddedPdbChunk.size 0x0uy) + if deterministic then + write (Some (textV2P debugDeterministicPdbChunk.addr)) os "debug deterministic" Array.empty + writePadding os "end of .text" (dataSectionPhysLoc - textSectionPhysLoc - textSectionSize) // DATA SECTION @@ -4179,7 +4208,7 @@ let writeBinaryAndReportMappings (outfile, FileSystemUtilites.setExecutablePermission outfile with _ -> () - pdbData, pdbOpt, debugDirectoryChunk, debugDataChunk, debugEmbeddedPdbChunk, textV2P, mappings + pdbData, pdbOpt, debugDirectoryChunk, debugDataChunk, debugChecksumPdbChunk, debugEmbeddedPdbChunk, debugDeterministicPdbChunk, textV2P, mappings // Looks like a finally with e -> @@ -4204,11 +4233,11 @@ let writeBinaryAndReportMappings (outfile, try let idd = match pdbOpt with - | Some (originalLength, contentId, stream) -> + | Some (originalLength, contentId, stream, algorithmName, checkSum) -> if embeddedPDB then - embedPortablePdbInfo originalLength contentId stream showTimes fpdb debugDataChunk debugEmbeddedPdbChunk + embedPortablePdbInfo originalLength contentId stream showTimes fpdb debugDataChunk debugEmbeddedPdbChunk debugDeterministicPdbChunk debugChecksumPdbChunk algorithmName checkSum embeddedPDB deterministic else - writePortablePdbInfo contentId stream showTimes fpdb pathMap debugDataChunk + writePortablePdbInfo contentId stream showTimes fpdb pathMap debugDataChunk debugDeterministicPdbChunk debugChecksumPdbChunk algorithmName checkSum embeddedPDB deterministic | None -> #if FX_NO_PDB_WRITER Array.empty @@ -4229,16 +4258,17 @@ let writeBinaryAndReportMappings (outfile, writeInt32AsUInt16 os2 i.iddMajorVersion writeInt32AsUInt16 os2 i.iddMinorVersion writeInt32 os2 i.iddType - writeInt32 os2 i.iddData.Length // IMAGE_DEBUG_DIRECTORY.SizeOfData - writeInt32 os2 i.iddChunk.addr // IMAGE_DEBUG_DIRECTORY.AddressOfRawData - writeInt32 os2 (textV2P i.iddChunk.addr) // IMAGE_DEBUG_DIRECTORY.PointerToRawData + writeInt32 os2 i.iddData.Length // IMAGE_DEBUG_DIRECTORY.SizeOfData + writeInt32 os2 i.iddChunk.addr // IMAGE_DEBUG_DIRECTORY.AddressOfRawData + writeInt32 os2 (textV2P i.iddChunk.addr) // IMAGE_DEBUG_DIRECTORY.PointerToRawData // Write the Debug Data for i in idd do - // write the debug raw data as given us by the PDB writer - os2.BaseStream.Seek (int64 (textV2P i.iddChunk.addr), SeekOrigin.Begin) |> ignore - if i.iddChunk.size < i.iddData.Length then failwith "Debug data area is not big enough. Debug info may not be usable" - writeBytes os2 i.iddData + if i.iddChunk.size <> 0 then + // write the debug raw data as given us by the PDB writer + os2.BaseStream.Seek (int64 (textV2P i.iddChunk.addr), SeekOrigin.Begin) |> ignore + if i.iddChunk.size < i.iddData.Length then failwith "Debug data area is not big enough. Debug info may not be usable" + writeBytes os2 i.iddData os2.Dispose() with e -> failwith ("Error while writing debug directory entry: "+e.Message) @@ -4247,9 +4277,7 @@ let writeBinaryAndReportMappings (outfile, with e -> reraise() - end - ignore debugDataChunk - ignore debugEmbeddedPdbChunk + end reportTime showTimes "Finalize PDB" /// Sign the binary. No further changes to binary allowed past this point! @@ -4277,9 +4305,10 @@ type options = embedAllSource: bool embedSourceList: string list sourceLink: string + checksumAlgorithm: HashAlgorithm signer: ILStrongNameSigner option - emitTailcalls : bool - deterministic : bool + emitTailcalls: bool + deterministic: bool showTimes: bool dumpDebugInfo: bool pathMap: PathMap } @@ -4287,5 +4316,5 @@ type options = let WriteILBinary (outfile, (args: options), modul, normalizeAssemblyRefs) = writeBinaryAndReportMappings (outfile, args.ilg, args.pdbfile, args.signer, args.portablePDB, args.embeddedPDB, args.embedAllSource, - args.embedSourceList, args.sourceLink, args.emitTailcalls, args.deterministic, args.showTimes, args.dumpDebugInfo, args.pathMap) modul normalizeAssemblyRefs + args.embedSourceList, args.sourceLink, args.checksumAlgorithm, args.emitTailcalls, args.deterministic, args.showTimes, args.dumpDebugInfo, args.pathMap) modul normalizeAssemblyRefs |> ignore diff --git a/src/absil/ilwrite.fsi b/src/absil/ilwrite.fsi index f1955f82a20..9dba89c9b6c 100644 --- a/src/absil/ilwrite.fsi +++ b/src/absil/ilwrite.fsi @@ -1,12 +1,13 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. /// The IL Binary writer. -module internal FSharp.Compiler.AbstractIL.ILBinaryWriter +module internal FSharp.Compiler.AbstractIL.ILBinaryWriter open Internal.Utilities -open FSharp.Compiler.AbstractIL -open FSharp.Compiler.AbstractIL.Internal -open FSharp.Compiler.AbstractIL.IL +open FSharp.Compiler.AbstractIL +open FSharp.Compiler.AbstractIL.Internal +open FSharp.Compiler.AbstractIL.IL +open FSharp.Compiler.AbstractIL.ILPdbWriter [] type ILStrongNameSigner = @@ -24,6 +25,7 @@ type options = embedAllSource: bool embedSourceList: string list sourceLink: string + checksumAlgorithm: HashAlgorithm signer : ILStrongNameSigner option emitTailcalls: bool deterministic: bool diff --git a/src/absil/ilwritepdb.fs b/src/absil/ilwritepdb.fs index 260ccbe238e..86b7ee9224f 100644 --- a/src/absil/ilwritepdb.fs +++ b/src/absil/ilwritepdb.fs @@ -11,8 +11,9 @@ open System.Reflection open System.Reflection.Metadata open System.Reflection.Metadata.Ecma335 open System.Reflection.PortableExecutable +open System.Text open Internal.Utilities -open FSharp.Compiler.AbstractIL.IL +open FSharp.Compiler.AbstractIL.IL open FSharp.Compiler.AbstractIL.Diagnostics open FSharp.Compiler.AbstractIL.Internal.Support open FSharp.Compiler.AbstractIL.Internal.Library @@ -125,6 +126,27 @@ type idd = iddData: byte[] iddChunk: BinaryChunk } +/// The specified Hash algorithm to use on portable pdb files. +type HashAlgorithm = + | Sha1 + | Sha256 + +// Document checksum algorithms +let guidSha1 = Guid("ff1816ec-aa5e-4d10-87f7-6f4963833460") +let guidSha2 = Guid("8829d00f-11b8-4213-878b-770e8597ac16") + +let checkSum (url: string) (checksumAlgorithm: HashAlgorithm) = + try + use file = FileSystem.FileStreamReadShim url + let guid, alg = + match checksumAlgorithm with + | HashAlgorithm.Sha1 -> guidSha1, System.Security.Cryptography.SHA1.Create() :> System.Security.Cryptography.HashAlgorithm + | HashAlgorithm.Sha256 -> guidSha2, System.Security.Cryptography.SHA256.Create() :> System.Security.Cryptography.HashAlgorithm + + let checkSum = alg.ComputeHash file + Some (guid, checkSum) + with _ -> None + //--------------------------------------------------------------------- // Portable PDB Writer //--------------------------------------------------------------------- @@ -153,7 +175,7 @@ let pdbGetCvDebugInfo (mvid: byte[]) (timestamp: int32) (filepath: string) (cvCh } let pdbMagicNumber= 0x4244504dL -let pdbGetPdbDebugInfo (embeddedPDBChunk: BinaryChunk) (uncompressedLength: int64) (stream: MemoryStream) = +let pdbGetEmbeddedPdbDebugInfo (embeddedPdbChunk: BinaryChunk) (uncompressedLength: int64) (stream: MemoryStream) = let iddPdbBuffer = let buffer = Array.zeroCreate (sizeof + sizeof + int(stream.Length)) let (offset, size) = (0, sizeof) // Magic Number dword: 0x4244504dL @@ -164,33 +186,57 @@ let pdbGetPdbDebugInfo (embeddedPDBChunk: BinaryChunk) (uncompressedLength: int6 Buffer.BlockCopy(stream.ToArray(), 0, buffer, offset, size) buffer { iddCharacteristics = 0 // Reserved - iddMajorVersion = 0 // VersionMajor should be 0 + iddMajorVersion = 0x0100 // VersionMajor should be 0x0100 iddMinorVersion = 0x0100 // VersionMinor should be 0x0100 iddType = 17 // IMAGE_DEBUG_TYPE_EMBEDDEDPDB iddTimestamp = 0 iddData = iddPdbBuffer // Path name to the pdb file when built - iddChunk = embeddedPDBChunk + iddChunk = embeddedPdbChunk } -let pdbGetDebugInfo (mvid: byte[]) (timestamp: int32) (filepath: string) (cvChunk: BinaryChunk) (embeddedPDBChunk: BinaryChunk option) (uncompressedLength: int64) (stream: MemoryStream option) = - match stream, embeddedPDBChunk with - | None, _ | _, None -> [| pdbGetCvDebugInfo mvid timestamp filepath cvChunk |] - | Some s, Some chunk -> [| pdbGetCvDebugInfo mvid timestamp filepath cvChunk; pdbGetPdbDebugInfo chunk uncompressedLength s |] +let pdbChecksumDebugInfo timestamp (checksumPdbChunk: BinaryChunk) (algorithmName:string) (checksum: byte[]) = + let iddBuffer = + let alg = Encoding.UTF8.GetBytes(algorithmName) + let buffer = Array.zeroCreate (alg.Length + 1 + checksum.Length) + Buffer.BlockCopy(alg, 0, buffer, 0, alg.Length) + Buffer.BlockCopy(checksum, 0, buffer, alg.Length + 1, checksum.Length) + buffer + { iddCharacteristics = 0 // Reserved + iddMajorVersion = 1 // VersionMajor should be 1 + iddMinorVersion = 0x0100 // VersionMinor should be 0x0100 + iddType = 19 // IMAGE_DEBUG_TYPE_CHECKSUMPDB + iddTimestamp = timestamp + iddData = iddBuffer // Path name to the pdb file when built + iddChunk = checksumPdbChunk + } -// Document checksum algorithms -let guidSourceHashMD5 = System.Guid(0x406ea660u, 0x64cfus, 0x4c82us, 0xb6uy, 0xf0uy, 0x42uy, 0xd4uy, 0x81uy, 0x72uy, 0xa7uy, 0x99uy) //406ea660-64cf-4c82-b6f0-42d48172a799 -let hashSizeOfMD5 = 16 +let pdbGetPdbDebugDeterministicInfo (deterministicPdbChunk: BinaryChunk) = + { iddCharacteristics = 0 // Reserved + iddMajorVersion = 0 // VersionMajor should be 0 + iddMinorVersion = 0 // VersionMinor should be 00 + iddType = 16 // IMAGE_DEBUG_TYPE_DETERMINISTIC + iddTimestamp = 0 + iddData = Array.empty // No DATA + iddChunk = deterministicPdbChunk + } -// If the FIPS algorithm policy is enabled on the computer (e.g., for US government employees and contractors) -// then obtaining the MD5 implementation in BCL will throw. -// In this case, catch the failure, and not set a checksum. -let checkSum (url: string) = - try - use file = FileSystem.FileStreamReadShim url - use md5 = System.Security.Cryptography.MD5.Create() - let checkSum = md5.ComputeHash file - Some (guidSourceHashMD5, checkSum) - with _ -> None +let pdbGetDebugInfo (contentId: byte[]) (timestamp: int32) (filepath: string) + (cvChunk: BinaryChunk) + (embeddedPdbChunk: BinaryChunk option) + (deterministicPdbChunk: BinaryChunk) + (checksumPdbChunk: BinaryChunk) (algorithmName:string) (checksum: byte []) + (uncompressedLength: int64) (stream: MemoryStream option) + (embeddedPdb: bool) (deterministic: bool) = + [| yield pdbGetCvDebugInfo contentId timestamp filepath cvChunk + yield pdbChecksumDebugInfo timestamp checksumPdbChunk algorithmName checksum + if embeddedPdb then + match stream, embeddedPdbChunk with + | None, _ | _, None -> () + | Some s, Some chunk -> + yield pdbGetEmbeddedPdbDebugInfo chunk uncompressedLength s + if deterministic then + yield pdbGetPdbDebugDeterministicInfo deterministicPdbChunk + |] //------------------------------------------------------------------------------ // PDB Writer. The function [WritePdbInfo] abstracts the @@ -219,7 +265,7 @@ let getRowCounts tableRowCounts = tableRowCounts |> Seq.iter(fun x -> builder.Add x) builder.MoveToImmutable() -let generatePortablePdb (embedAllSource: bool) (embedSourceList: string list) (sourceLink: string) showTimes (info: PdbData) isDeterministic (pathMap: PathMap) = +let generatePortablePdb (embedAllSource: bool) (embedSourceList: string list) (sourceLink: string) checksumAlgorithm showTimes (info: PdbData) (pathMap: PathMap) = sortMethods showTimes info let externalRowCounts = getRowCounts info.TableRowCounts let docs = @@ -286,7 +332,7 @@ let generatePortablePdb (embedAllSource: bool) (embedSourceList: string list) (s metadata.SetCapacity(TableIndex.Document, docLength) for doc in docs do let handle = - match checkSum doc.File with + match checkSum doc.File checksumAlgorithm with | Some (hashAlg, checkSum) -> let dbgInfo = (serializeDocumentName doc.File, @@ -403,12 +449,17 @@ let generatePortablePdb (embedAllSource: bool) (embedSourceList: string list) (s if i < 1 || offsetDelta > 0 then builder.WriteCompressedInteger offsetDelta - // Hidden-sequence-point-record - if startLine = 0xfeefee || endLine = 0xfeefee || (startColumn = 0 && endColumn = 0) + // Check for hidden-sequence-point-record + if startLine = 0xfeefee || + endLine = 0xfeefee || + (startColumn = 0 && endColumn = 0) || + ((endLine - startLine) = 0 && (endColumn - startColumn) = 0) then + // Hidden-sequence-point-record builder.WriteCompressedInteger 0 builder.WriteCompressedInteger 0 - else // Non-hidden-sequence-point-record + else + // Non-hidden-sequence-point-record let deltaLines = endLine - startLine // lines builder.WriteCompressedInteger deltaLines @@ -476,25 +527,28 @@ let generatePortablePdb (embedAllSource: bool) (embedSourceList: string list) (s | None -> MetadataTokens.MethodDefinitionHandle 0 | Some x -> MetadataTokens.MethodDefinitionHandle x - let deterministicIdProvider isDeterministic : System.Func, BlobContentId> = - match isDeterministic with - | false -> null - | true -> - let convert (content: IEnumerable) = - use sha = System.Security.Cryptography.SHA1.Create() // IncrementalHash is core only - let hash = content - |> Seq.collect (fun c -> c.GetBytes().Array |> sha.ComputeHash) - |> Array.ofSeq |> sha.ComputeHash - BlobContentId.FromHash hash - System.Func, BlobContentId>( convert ) - - let serializer = PortablePdbBuilder(metadata, externalRowCounts, entryPoint, deterministicIdProvider isDeterministic) + // Compute the contentId for the pdb. Always do it deterministically, since we have to compute the anyway. + // The contentId is the hash of the ID using whichever algorithm has been specified to the compiler + let mutable contentHash = Array.empty + + let algorithmName, hashAlgorithm = + match checksumAlgorithm with + | HashAlgorithm.Sha1 -> "SHA1", System.Security.Cryptography.SHA1.Create() :> System.Security.Cryptography.HashAlgorithm + | HashAlgorithm.Sha256 -> "SHA256", System.Security.Cryptography.SHA256.Create() :> System.Security.Cryptography.HashAlgorithm + let idProvider: System.Func, BlobContentId> = + let convert (content: IEnumerable) = + let contentBytes = content |> Seq.collect (fun c -> c.GetBytes()) |> Array.ofSeq + contentHash <- contentBytes |> hashAlgorithm.ComputeHash + BlobContentId.FromHash contentHash + System.Func, BlobContentId>(convert) + + let serializer = PortablePdbBuilder(metadata, externalRowCounts, entryPoint, idProvider) let blobBuilder = new BlobBuilder() let contentId= serializer.Serialize blobBuilder let portablePdbStream = new MemoryStream() blobBuilder.WriteContentTo portablePdbStream reportTime showTimes "PDB: Created" - (portablePdbStream.Length, contentId, portablePdbStream) + (portablePdbStream.Length, contentId, portablePdbStream, algorithmName, contentHash) let compressPortablePdbStream (uncompressedLength: int64) (contentId: BlobContentId) (stream: MemoryStream) = let compressedStream = new MemoryStream() @@ -502,17 +556,17 @@ let compressPortablePdbStream (uncompressedLength: int64) (contentId: BlobConten stream.WriteTo compressionStream (uncompressedLength, contentId, compressedStream) -let writePortablePdbInfo (contentId: BlobContentId) (stream: MemoryStream) showTimes fpdb pathMap cvChunk = +let writePortablePdbInfo (contentId: BlobContentId) (stream: MemoryStream) showTimes fpdb pathMap cvChunk deterministicPdbChunk checksumPdbChunk algName checksum embeddedPdb deterministicPdb = try FileSystem.FileDelete fpdb with _ -> () use pdbFile = new FileStream(fpdb, FileMode.Create, FileAccess.ReadWrite) stream.WriteTo pdbFile reportTime showTimes "PDB: Closed" - pdbGetDebugInfo (contentId.Guid.ToByteArray()) (int32 (contentId.Stamp)) (PathMap.apply pathMap fpdb) cvChunk None 0L None + pdbGetDebugInfo (contentId.Guid.ToByteArray()) (int32 (contentId.Stamp)) (PathMap.apply pathMap fpdb) cvChunk None deterministicPdbChunk checksumPdbChunk algName checksum 0L None embeddedPdb deterministicPdb -let embedPortablePdbInfo (uncompressedLength: int64) (contentId: BlobContentId) (stream: MemoryStream) showTimes fpdb cvChunk pdbChunk = +let embedPortablePdbInfo (uncompressedLength: int64) (contentId: BlobContentId) (stream: MemoryStream) showTimes fpdb cvChunk pdbChunk deterministicPdbChunk checksumPdbChunk algName checksum embeddedPdb deterministicPdb = reportTime showTimes "PDB: Closed" let fn = Path.GetFileName fpdb - pdbGetDebugInfo (contentId.Guid.ToByteArray()) (int32 (contentId.Stamp)) fn cvChunk (Some pdbChunk) uncompressedLength (Some stream) + pdbGetDebugInfo (contentId.Guid.ToByteArray()) (int32 (contentId.Stamp)) fn cvChunk (Some pdbChunk) deterministicPdbChunk checksumPdbChunk algName checksum uncompressedLength (Some stream) embeddedPdb deterministicPdb #if !FX_NO_PDB_WRITER //--------------------------------------------------------------------- diff --git a/src/absil/ilwritepdb.fsi b/src/absil/ilwritepdb.fsi index 2713d9769b2..748e178a461 100644 --- a/src/absil/ilwritepdb.fsi +++ b/src/absil/ilwritepdb.fsi @@ -4,7 +4,7 @@ module internal FSharp.Compiler.AbstractIL.ILPdbWriter open Internal.Utilities -open FSharp.Compiler.AbstractIL.IL +open FSharp.Compiler.AbstractIL.IL open FSharp.Compiler.ErrorLogger open FSharp.Compiler.Range open System.Collections.Generic @@ -83,10 +83,14 @@ type idd = iddData: byte[]; iddChunk: BinaryChunk } -val generatePortablePdb : embedAllSource:bool -> embedSourceList:string list -> sourceLink: string -> showTimes:bool -> info:PdbData -> isDeterministic:bool -> pathMap:PathMap -> (int64 * BlobContentId * MemoryStream) +type HashAlgorithm = + | Sha1 + | Sha256 + +val generatePortablePdb : embedAllSource: bool -> embedSourceList: string list -> sourceLink: string -> checksumAlgorithm: HashAlgorithm -> showTimes: bool -> info: PdbData -> pathMap:PathMap -> (int64 * BlobContentId * MemoryStream * string * byte[]) val compressPortablePdbStream : uncompressedLength:int64 -> contentId:BlobContentId -> stream:MemoryStream -> (int64 * BlobContentId * MemoryStream) -val embedPortablePdbInfo : uncompressedLength:int64 -> contentId:BlobContentId -> stream:MemoryStream -> showTimes:bool -> fpdb:string -> cvChunk:BinaryChunk -> pdbChunk:BinaryChunk -> idd[] -val writePortablePdbInfo : contentId:BlobContentId -> stream:MemoryStream -> showTimes:bool -> fpdb:string -> pathMap:PathMap -> cvChunk:BinaryChunk -> idd[] +val embedPortablePdbInfo: uncompressedLength: int64 -> contentId: BlobContentId -> stream: MemoryStream -> showTimes: bool -> fpdb: string -> cvChunk: BinaryChunk -> pdbChunk: BinaryChunk -> deterministicPdbChunk: BinaryChunk -> checksumPdbChunk: BinaryChunk -> algorithmName: string -> checksum: byte[] -> embeddedPDB: bool -> deterministic: bool -> idd[] +val writePortablePdbInfo: contentId: BlobContentId -> stream: MemoryStream -> showTimes: bool -> fpdb: string -> pathMap: PathMap -> cvChunk: BinaryChunk -> deterministicPdbChunk: BinaryChunk -> checksumPdbChunk: BinaryChunk -> algorithmName: string -> checksum: byte[] -> embeddedPDB: bool -> deterministic: bool -> idd[] #if !FX_NO_PDB_WRITER val writePdbInfo : showTimes:bool -> f:string -> fpdb:string -> info:PdbData -> cvChunk:BinaryChunk -> idd[] diff --git a/scripts/AssemblyVersionCheck.fsx b/src/buildtools/AssemblyCheck/AssemblyCheck.fs similarity index 51% rename from scripts/AssemblyVersionCheck.fsx rename to src/buildtools/AssemblyCheck/AssemblyCheck.fs index 0f3816a2e6c..c6bd035a673 100644 --- a/scripts/AssemblyVersionCheck.fsx +++ b/src/buildtools/AssemblyCheck/AssemblyCheck.fs @@ -1,22 +1,50 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. open System open System.Diagnostics open System.IO open System.Reflection +open System.Reflection.PortableExecutable open System.Text.RegularExpressions -module AssemblyVersionCheck = +module AssemblyCheck = let private versionZero = Version(0, 0, 0, 0) let private versionOne = Version(1, 0, 0, 0) let private commitHashPattern = new Regex(@"Commit Hash: ()|([0-9a-fA-F]{40})", RegexOptions.Compiled) let private devVersionPattern = new Regex(@"-(ci|dev)", RegexOptions.Compiled) - let verifyAssemblyVersions (binariesPath:string) = + let verifyEmbeddedPdb (filename:string) = + use fileStream = File.OpenRead(filename) + let reader = new PEReader(fileStream) + let mutable hasEmbeddedPdb = false + + try + for entry in reader.ReadDebugDirectory() do + match entry.Type with + | DebugDirectoryEntryType.CodeView -> + let _ = reader.ReadCodeViewDebugDirectoryData(entry) + () + + | DebugDirectoryEntryType.EmbeddedPortablePdb -> + let _ = reader.ReadEmbeddedPortablePdbDebugDirectoryData(entry) + hasEmbeddedPdb <- true + () + + | DebugDirectoryEntryType.PdbChecksum -> + let _ = reader.ReadPdbChecksumDebugDirectoryData(entry) + () + + | _ -> () + with | e -> printfn "Error validating assembly %s\nMessage: %s" filename (e.ToString()) + hasEmbeddedPdb + + let verifyAssemblies (binariesPath:string) = + let excludedAssemblies = [ "FSharp.Data.TypeProviders.dll" ] |> Set.ofList + let fsharpAssemblies = [ "FSharp*.dll" "fsc.exe" @@ -28,12 +56,17 @@ module AssemblyVersionCheck = |> List.ofSeq |> List.filter (fun p -> (Set.contains (Path.GetFileName(p)) excludedAssemblies) |> not) + let fsharpExecutingWithEmbeddedPdbs = + fsharpAssemblies + |> List.filter (fun p -> not (p.Contains(@"\Proto\") || p.Contains(@"\Bootstrap\") || p.Contains(@".resources.") || p.Contains(@"\FSharpSdk\") || p.Contains(@"\tmp\") || p.Contains(@"\obj\"))) + // verify that all assemblies have a version number other than 0.0.0.0 or 1.0.0.0 let failedVersionCheck = fsharpAssemblies |> List.filter (fun a -> let assemblyVersion = AssemblyName.GetAssemblyName(a).Version assemblyVersion = versionZero || assemblyVersion = versionOne) + if failedVersionCheck.Length > 0 then printfn "The following assemblies had a version of %A or %A" versionZero versionOne printfn "%s\r\n" <| String.Join("\r\n", failedVersionCheck) @@ -43,27 +76,36 @@ module AssemblyVersionCheck = // verify that all assemblies have a commit hash let failedCommitHash = fsharpAssemblies + |> List.filter (fun p -> not (p.Contains(@"\FSharpSdk\"))) |> List.filter (fun a -> let fileProductVersion = FileVersionInfo.GetVersionInfo(a).ProductVersion not (commitHashPattern.IsMatch(fileProductVersion) || devVersionPattern.IsMatch(fileProductVersion))) + if failedCommitHash.Length > 0 then printfn "The following assemblies don't have a commit hash set" printfn "%s\r\n" <| String.Join("\r\n", failedCommitHash) else printfn "All shipping assemblies had an appropriate commit hash." + // verify that all assemblies have an embedded pdb + let failedVerifyEmbeddedPdb = + fsharpExecutingWithEmbeddedPdbs + |> List.filter (fun a -> not (verifyEmbeddedPdb a)) + + if failedVerifyEmbeddedPdb.Length > 0 then + printfn "The following assemblies don't have an embedded pdb" + printfn "%s\r\n" <| String.Join("\r\n", failedVerifyEmbeddedPdb) + else + printfn "All shipping assemblies had an embedded PDB." + // return code is the number of failures - failedVersionCheck.Length + failedCommitHash.Length + failedVersionCheck.Length + failedCommitHash.Length + failedVerifyEmbeddedPdb.Length + +[] let main (argv:string array) = if argv.Length <> 1 then - printfn "Usage: fsi.exe AssemblyVersionCheck.fsx -- path/to/binaries" + printfn "Usage: dotnet AssemblyCheck.dll -- path/to/binaries" 1 else - AssemblyVersionCheck.verifyAssemblyVersions argv.[0] - -Environment.GetCommandLineArgs() -|> Seq.skipWhile ((<>) "--") -|> Seq.skip 1 -|> Array.ofSeq -|> main + AssemblyCheck.verifyAssemblies argv.[0] diff --git a/src/buildtools/AssemblyCheck/AssemblyCheck.fsproj b/src/buildtools/AssemblyCheck/AssemblyCheck.fsproj new file mode 100644 index 00000000000..72f79d02f93 --- /dev/null +++ b/src/buildtools/AssemblyCheck/AssemblyCheck.fsproj @@ -0,0 +1,17 @@ + + + + Exe + netcoreapp2.1 + true + + + + + + + + + + + diff --git a/src/buildtools/buildtools.proj b/src/buildtools/buildtools.proj index 630bb678561..7ac48ba2a37 100644 --- a/src/buildtools/buildtools.proj +++ b/src/buildtools/buildtools.proj @@ -8,6 +8,7 @@ + diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index b33917c2255..0548fd1269e 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -17,6 +17,7 @@ open Internal.Utilities.Text open FSharp.Compiler.AbstractIL open FSharp.Compiler.AbstractIL.IL open FSharp.Compiler.AbstractIL.ILBinaryReader +open FSharp.Compiler.AbstractIL.ILPdbWriter open FSharp.Compiler.AbstractIL.Internal open FSharp.Compiler.AbstractIL.Internal.Library open FSharp.Compiler.AbstractIL.Extensions.ILX @@ -2101,6 +2102,7 @@ type TcConfigBuilder = mutable maxErrors: int mutable abortOnError: bool (* intended for fsi scripts that should exit on first error *) mutable baseAddress: int32 option + mutable checksumAlgorithm: HashAlgorithm #if DEBUG mutable showOptimizationData: bool #endif @@ -2234,6 +2236,7 @@ type TcConfigBuilder = maxErrors = 100 abortOnError = false baseAddress = None + checksumAlgorithm = HashAlgorithm.Sha256 delaysign = false publicsign = false @@ -2744,6 +2747,7 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member x.flatErrors = data.flatErrors member x.maxErrors = data.maxErrors member x.baseAddress = data.baseAddress + member x.checksumAlgorithm = data.checksumAlgorithm #if DEBUG member x.showOptimizationData = data.showOptimizationData #endif diff --git a/src/fsharp/CompileOps.fsi b/src/fsharp/CompileOps.fsi index 51bcc2dc2a6..0b5f9cb0839 100644 --- a/src/fsharp/CompileOps.fsi +++ b/src/fsharp/CompileOps.fsi @@ -10,6 +10,7 @@ open Internal.Utilities open FSharp.Compiler.AbstractIL open FSharp.Compiler.AbstractIL.IL open FSharp.Compiler.AbstractIL.ILBinaryReader +open FSharp.Compiler.AbstractIL.ILPdbWriter open FSharp.Compiler.AbstractIL.Internal.Library open FSharp.Compiler open FSharp.Compiler.TypeChecker @@ -338,6 +339,7 @@ type TcConfigBuilder = mutable maxErrors: int mutable abortOnError: bool mutable baseAddress: int32 option + mutable checksumAlgorithm: HashAlgorithm #if DEBUG mutable showOptimizationData: bool #endif @@ -500,6 +502,7 @@ type TcConfig = member maxErrors: int member baseAddress: int32 option + member checksumAlgorithm: HashAlgorithm #if DEBUG member showOptimizationData: bool #endif @@ -549,6 +552,7 @@ type TcConfig = member copyFSharpCore: CopyFSharpCoreFlag member shadowCopyReferences: bool member useSdkRefs: bool + member langVersion: LanguageVersion static member Create: TcConfigBuilder * validate: bool -> TcConfig diff --git a/src/fsharp/CompileOptions.fs b/src/fsharp/CompileOptions.fs index d107c3f3949..67e7b8568d4 100644 --- a/src/fsharp/CompileOptions.fs +++ b/src/fsharp/CompileOptions.fs @@ -9,6 +9,7 @@ open System open FSharp.Compiler open FSharp.Compiler.AbstractIL open FSharp.Compiler.AbstractIL.IL +open FSharp.Compiler.AbstractIL.ILPdbWriter open FSharp.Compiler.AbstractIL.Internal.Library open FSharp.Compiler.AbstractIL.Extensions.ILX open FSharp.Compiler.AbstractIL.Diagnostics @@ -523,6 +524,7 @@ let tagFullPDBOnlyPortable = "{full|pdbonly|portable|embedded}" let tagWarnList = "" let tagSymbolList = "" let tagAddress = "
" +let tagAlgorithm = "{SHA1|SHA256}" let tagInt = "" let tagPathMap = "" let tagNone = "" @@ -948,6 +950,16 @@ let advancedFlagsFsc tcConfigB = OptionString (fun s -> tcConfigB.baseAddress <- Some(int32 s)), None, Some (FSComp.SR.optsBaseaddress())) + yield CompilerOption + ("checksumalgorithm", tagAlgorithm, + OptionString (fun s -> + tcConfigB.checksumAlgorithm <- + match s.ToUpperInvariant() with + | "SHA1" -> HashAlgorithm.Sha1 + | "SHA256" -> HashAlgorithm.Sha256 + | _ -> error(Error(FSComp.SR.optsUnknownChecksumAlgorithm s, rangeCmdArgs))), None, + Some (FSComp.SR.optsChecksumAlgorithm())) + yield noFrameworkFlag true tcConfigB yield CompilerOption diff --git a/src/fsharp/ConstraintSolver.fs b/src/fsharp/ConstraintSolver.fs index 1176c8dea81..bff25d0979a 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -1931,7 +1931,7 @@ and SolveTypeIsNonNullableValueType (csenv: ConstraintSolverEnv) ndeep m2 trace | _ -> let underlyingTy = stripTyEqnsAndMeasureEqns g ty if isStructTy g underlyingTy then - if isAppTy g underlyingTy && tyconRefEq g g.system_Nullable_tcref (tcrefOfAppTy g underlyingTy) then + if isNullableTy g underlyingTy then return! ErrorD (ConstraintSolverError(FSComp.SR.csTypeParameterCannotBeNullable(), m, m)) else return! ErrorD (ConstraintSolverError(FSComp.SR.csGenericConstructRequiresStructType(NicePrint.minimalStringOfType denv ty), m, m2)) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 4b5f756f06d..92262b1f429 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -880,6 +880,7 @@ optsUtf8output,"Output messages in UTF-8 encoding" optsFullpaths,"Output messages with fully qualified paths" optsLib,"Specify a directory for the include path which is used to resolve source files and assemblies (Short form: -I)" optsBaseaddress,"Base address for the library to be built" +optsChecksumAlgorithm,"Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default)" optsNoframework,"Do not reference the default CLI assemblies by default" optsStandalone,"Statically link the F# library and all referenced DLLs that depend on it into the assembly being generated" optsStaticlink,"Statically link the given assembly and all referenced DLLs that depend on this assembly. Use an assembly name e.g. mylib, not a DLL name." @@ -902,6 +903,7 @@ optsHelpBannerLanguage,"- LANGUAGE -" optsHelpBannerErrsAndWarns,"- ERRORS AND WARNINGS -" 1063,optsUnknownArgumentToTheTestSwitch,"Unknown --test argument: '%s'" 1064,optsUnknownPlatform,"Unrecognized platform '%s', valid values are 'x86', 'x64', 'Itanium', 'anycpu32bitpreferred', and 'anycpu'" +1065,optsUnknownChecksumAlgorithm,"Algorithm '%s' is not supported" optsInternalNoDescription,"The command-line option '%s' is for test purposes only" optsDCLONoDescription,"The command-line option '%s' has been deprecated" optsDCLODeprecatedSuggestAlternative,"The command-line option '%s' has been deprecated. Use '%s' instead." diff --git a/src/fsharp/FSharp.Build/Fsc.fs b/src/fsharp/FSharp.Build/Fsc.fs index 4f1a702d5a5..25bdfa38d3a 100644 --- a/src/fsharp/FSharp.Build/Fsc.fs +++ b/src/fsharp/FSharp.Build/Fsc.fs @@ -24,6 +24,7 @@ type public Fsc () as this = let mutable baseAddress : string = null let mutable capturedArguments : string list = [] // list of individual args, to pass to HostObject Compile() let mutable capturedFilenames : string list = [] // list of individual source filenames, to pass to HostObject Compile() + let mutable checksumAlgorithm: string = null let mutable codePage : string = null let mutable commandLineArgs : ITaskItem list = [] let mutable debugSymbols = false @@ -135,7 +136,7 @@ type public Fsc () as this = builder.AppendSwitch("--tailcalls-") // PdbFile builder.AppendSwitchIfNotNull("--pdb:", pdbFile) - // Platform +// Platform builder.AppendSwitchIfNotNull("--platform:", let ToUpperInvariant (s:string) = if s = null then null else s.ToUpperInvariant() match ToUpperInvariant(platform), prefer32bit, ToUpperInvariant(targetType) with @@ -145,6 +146,13 @@ type public Fsc () as this = | "X86", _, _ -> "x86" | "X64", _, _ -> "x64" | _ -> null) + // checksumAlgorithm + builder.AppendSwitchIfNotNull("--checksumalgorithm:", + let ToUpperInvariant (s:string) = if s = null then null else s.ToUpperInvariant() + match ToUpperInvariant(checksumAlgorithm) with + | "SHA1" -> "Sha1" + | "SHA256" -> "Sha256" + | _ -> null) // Resources if resources <> null then for item in resources do @@ -258,6 +266,11 @@ type public Fsc () as this = with get() = baseAddress and set(s) = baseAddress <- s + // --checksumalgorithm + member fsc.ChecksumAlgorithm + with get() = checksumAlgorithm + and set(s) = checksumAlgorithm <- s + // --codepage : Specify the codepage to use when opening source files member fsc.CodePage with get() = codePage diff --git a/src/fsharp/FSharp.Build/Microsoft.FSharp.Targets b/src/fsharp/FSharp.Build/Microsoft.FSharp.Targets index c10d3fb3055..ced8a931e97 100644 --- a/src/fsharp/FSharp.Build/Microsoft.FSharp.Targets +++ b/src/fsharp/FSharp.Build/Microsoft.FSharp.Targets @@ -283,6 +283,7 @@ this file. AbsIL\ilread.fs - - AbsIL\ilwrite.fsi - AbsIL\ilwritepdb.fsi AbsIL\ilwritepdb.fs + + AbsIL\ilwrite.fsi + AbsIL\ilwrite.fs diff --git a/src/fsharp/FSharp.Compiler.nuget/Microsoft.FSharp.Compiler.nuspec b/src/fsharp/FSharp.Compiler.nuget/Microsoft.FSharp.Compiler.nuspec index 4a07b917ab8..dd9293cd88c 100644 --- a/src/fsharp/FSharp.Compiler.nuget/Microsoft.FSharp.Compiler.nuspec +++ b/src/fsharp/FSharp.Compiler.nuget/Microsoft.FSharp.Compiler.nuspec @@ -49,15 +49,7 @@ - - - - - - - + target="lib\netcoreapp2.1" /> @@ -69,9 +61,9 @@ + target="lib\netcoreapp2.1" /> + target="lib\netcoreapp2.1" /> diff --git a/src/fsharp/IlxGen.fs b/src/fsharp/IlxGen.fs index 290030d34e7..df72c2c3015 100644 --- a/src/fsharp/IlxGen.fs +++ b/src/fsharp/IlxGen.fs @@ -2540,7 +2540,8 @@ and GenAllocUnionCase cenv cgbuf eenv (c,tyargs,args,m) sequel = GenSequel cenv eenv.cloc cgbuf sequel and GenLinearExpr cenv cgbuf eenv sp expr sequel canProcessSequencePoint (contf: FakeUnit -> FakeUnit) = - match stripExpr expr with + let expr = stripExpr expr + match expr with | LinearOpExpr (TOp.UnionCase c, tyargs, argsFront, argLast, m) -> GenExprs cenv cgbuf eenv argsFront GenLinearExpr cenv cgbuf eenv SPSuppress argLast Continue (* canProcessSequencePoint *) true (contf << (fun Fake -> diff --git a/src/fsharp/LanguageFeatures.fs b/src/fsharp/LanguageFeatures.fs index 8894fb1fc17..c4c46e4b666 100644 --- a/src/fsharp/LanguageFeatures.fs +++ b/src/fsharp/LanguageFeatures.fs @@ -93,3 +93,6 @@ type LanguageVersion (specifiedVersion) = let label = if v = defaultVersion then " (Default)" else "" yield sprintf "%M%s" v label |] + + /// Get the specified LanguageVersion + member __.SpecifiedVerson = specified diff --git a/src/fsharp/LanguageFeatures.fsi b/src/fsharp/LanguageFeatures.fsi index bda44fe171e..d1d190d3f96 100644 --- a/src/fsharp/LanguageFeatures.fsi +++ b/src/fsharp/LanguageFeatures.fsi @@ -34,3 +34,6 @@ type LanguageVersion = /// Get the list of valid options member ValidOptions: string array + + /// Get the specified LanguageVersion + member SpecifiedVerson: decimal diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index 5a8d66c875b..895f2d1f729 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -20,6 +20,7 @@ open FSharp.Compiler.Tastops.DebugPrint open FSharp.Compiler.TcGlobals open FSharp.Compiler.TypeRelations open FSharp.Compiler.AttributeChecking +open Internal.Utilities #if !NO_EXTENSIONTYPING open FSharp.Compiler.ExtensionTyping @@ -151,7 +152,9 @@ let AdjustCalledArgType (infoReader: InfoReader) isConstraint (calledArg: Called mkRefCellTy g (destByrefTy g calledArgTy) else - // If the called method argument is a delegate type, then the caller may provide a function + // If the called method argument is a delegate type, and the caller is known to be a function type, then the caller may provide a function + // If the called method argument is an Expression type, and the caller is known to be a function type, then the caller may provide a T + // If the called method argument is an [] Quotations.Expr, and the caller is not known to be a quoted expression type, then the caller may provide a T let calledArgTy = let adjustDelegateTy calledTy = let (SigOfFunctionForDelegate(_, delArgTys, _, fty)) = GetSigOfFunctionForDelegate infoReader calledTy m AccessibleFromSomewhere @@ -178,14 +181,18 @@ let AdjustCalledArgType (infoReader: InfoReader) isConstraint (calledArg: Called else calledArgTy // Adjust the called argument type to take into account whether the caller's argument is M(?arg=Some(3)) or M(arg=1) - // If the called method argument is optional with type Option, then the caller may provide a T, unless their argument is propagating-optional (i.e. isOptCallerArg) + // If the called method argument is Callee-side optional with type Option, and the caller argument is not explicitly optional (callerArg.IsOptional), then the caller may provide a T + // If the called method argument is Caller-side optional with type Nullable, and the caller argument is not explicitly optional (callerArg.IsOptional), then the caller may provide a T let calledArgTy = match calledArg.OptArgInfo with - | NotOptional -> calledArgTy + | NotOptional -> calledArgTy | CalleeSide when not callerArg.IsOptional && isOptionTy g calledArgTy -> destOptionTy g calledArgTy - | CalleeSide | CallerSide _ -> calledArgTy - calledArgTy - + // This will be added in https://github.com/dotnet/fsharp/pull/7276 + //| CallerSide _ when not callerArg.IsOptional && isNullableTy g calledArgTy -> destNullableTy g calledArgTy + | CalleeSide + | CallerSide _ -> calledArgTy + + calledArgTy //------------------------------------------------------------------------- // CalledMeth @@ -540,6 +547,351 @@ let ExamineMethodForLambdaPropagation (x: CalledMeth) = else None +//------------------------------------------------------------------------- +// Adjust caller arguments as part of building a method call +//------------------------------------------------------------------------- + +/// Build a call to the System.Object constructor taking no arguments, +let BuildObjCtorCall (g: TcGlobals) m = + let ilMethRef = (mkILCtorMethSpecForTy(g.ilg.typ_Object, [])).MethodRef + Expr.Op (TOp.ILCall (false, false, false, false, CtorValUsedAsSuperInit, false, true, ilMethRef, [], [], [g.obj_ty]), [], [], m) + +/// Implements the elaborated form of adhoc conversions from functions to delegates at member callsites +let BuildNewDelegateExpr (eventInfoOpt: EventInfo option, g, amap, delegateTy, invokeMethInfo: MethInfo, delArgTys, f, fty, m) = + let slotsig = invokeMethInfo.GetSlotSig(amap, m) + let delArgVals, expr = + let topValInfo = ValReprInfo([], List.replicate (max 1 (List.length delArgTys)) ValReprInfo.unnamedTopArg, ValReprInfo.unnamedRetVal) + + // Try to pull apart an explicit lambda and use it directly + // Don't do this in the case where we're adjusting the arguments of a function used to build a .NET-compatible event handler + let lambdaContents = + if Option.isSome eventInfoOpt then + None + else + tryDestTopLambda g amap topValInfo (f, fty) + + match lambdaContents with + | None -> + + if List.exists (isByrefTy g) delArgTys then + error(Error(FSComp.SR.tcFunctionRequiresExplicitLambda(List.length delArgTys), m)) + + let delArgVals = delArgTys |> List.mapi (fun i argty -> fst (mkCompGenLocal m ("delegateArg" + string i) argty)) + let expr = + let args = + match eventInfoOpt with + | Some einfo -> + match delArgVals with + | [] -> error(nonStandardEventError einfo.EventName m) + | h :: _ when not (isObjTy g h.Type) -> error(nonStandardEventError einfo.EventName m) + | h :: t -> [exprForVal m h; mkRefTupledVars g m t] + | None -> + if isNil delArgTys then [mkUnit g m] else List.map (exprForVal m) delArgVals + mkApps g ((f, fty), [], args, m) + delArgVals, expr + + | Some _ -> + let _, _, _, vsl, body, _ = IteratedAdjustArityOfLambda g amap topValInfo f + List.concat vsl, body + + let meth = TObjExprMethod(slotsig, [], [], [delArgVals], expr, m) + mkObjExpr(delegateTy, None, BuildObjCtorCall g m, [meth], [], m) + +let CoerceFromFSharpFuncToDelegate g amap infoReader ad callerArgTy m callerArgExpr delegateTy = + let (SigOfFunctionForDelegate(invokeMethInfo, delArgTys, _, _)) = GetSigOfFunctionForDelegate infoReader delegateTy m ad + BuildNewDelegateExpr (None, g, amap, delegateTy, invokeMethInfo, delArgTys, callerArgExpr, callerArgTy, m) + +// Handle adhoc argument conversions +let AdjustCallerArgExprForCoercions (g: TcGlobals) amap infoReader ad isOutArg calledArgTy (reflArgInfo: ReflectedArgInfo) callerArgTy m callerArgExpr = + + if isByrefTy g calledArgTy && isRefCellTy g callerArgTy then + None, Expr.Op (TOp.RefAddrGet false, [destRefCellTy g callerArgTy], [callerArgExpr], m) + +#if IMPLICIT_ADDRESS_OF + elif isInByrefTy g calledArgTy && not (isByrefTy g callerArgTy) then + let wrap, callerArgExprAddress, _readonly, _writeonly = mkExprAddrOfExpr g true false NeverMutates callerArgExpr None m + Some wrap, callerArgExprAddress +#endif + + elif isDelegateTy g calledArgTy && isFunTy g callerArgTy then + None, CoerceFromFSharpFuncToDelegate g amap infoReader ad callerArgTy m callerArgExpr calledArgTy + + elif isLinqExpressionTy g calledArgTy && isDelegateTy g (destLinqExpressionTy g calledArgTy) && isFunTy g callerArgTy then + let delegateTy = destLinqExpressionTy g calledArgTy + let expr = CoerceFromFSharpFuncToDelegate g amap infoReader ad callerArgTy m callerArgExpr delegateTy + None, mkCallQuoteToLinqLambdaExpression g m delegateTy (Expr.Quote (expr, ref None, false, m, mkQuotedExprTy g delegateTy)) + + // auto conversions to quotations (to match auto conversions to LINQ expressions) + elif reflArgInfo.AutoQuote && isQuotedExprTy g calledArgTy && not (isQuotedExprTy g callerArgTy) then + match reflArgInfo with + | ReflectedArgInfo.Quote true -> + None, mkCallLiftValueWithDefn g m calledArgTy callerArgExpr + | ReflectedArgInfo.Quote false -> + None, Expr.Quote (callerArgExpr, ref None, false, m, calledArgTy) + | ReflectedArgInfo.None -> failwith "unreachable" // unreachable due to reflArgInfo.AutoQuote condition + + // Note: out args do not need to be coerced + elif isOutArg then + None, callerArgExpr + + // Note: not all these casts are reported in quotations + else + None, mkCoerceIfNeeded g calledArgTy callerArgTy callerArgExpr + +// Handle CallerSide optional arguments. +// +// CallerSide optional arguments are largely for COM interop, e.g. to PIA assemblies for Word etc. +// As a result we follow the VB and C# behavior here. +// +// "1. If the parameter is statically typed as System.Object and does not have a value, then there are four cases: +// a. The parameter is marked with MarshalAs(IUnknown), MarshalAs(Interface), or MarshalAs(IDispatch). In this case we pass null. +// b. Else if the parameter is marked with IUnknownConstantAttribute. In this case we pass new System.Runtime.InteropServices.UnknownWrapper(null) +// c. Else if the parameter is marked with IDispatchConstantAttribute. In this case we pass new System.Runtime.InteropServices.DispatchWrapper(null) +// d. Else, we will pass Missing.Value. +// 2. Otherwise, if there is a value attribute, then emit the default value. +// 3. Otherwise, we emit default(T). +// 4. Finally, we apply conversions from the value to the parameter type. This is where the nullable conversions take place for VB. +// - VB allows you to mark ref parameters as optional. The semantics of this is that we create a temporary +// with type = type of parameter, load the optional value to it, and call the method. +// - VB also allows you to mark arrays with Nothing as the optional value. +// - VB also allows you to pass intrinsic values as optional values to parameters +// typed as Object. What we do in this case is we box the intrinsic value." +// +let AdjustOptionalCallerArgExprs tcFieldInit eCallerMemberName g (calledMeth: CalledMeth<_>) mItem mMethExpr = + + let assignedNamedArgs = calledMeth.ArgSets |> List.collect (fun argSet -> argSet.AssignedNamedArgs) + let unnamedCalledArgs = calledMeth.ArgSets |> List.collect (fun argSet -> argSet.UnnamedCalledArgs) + let unnamedCallerArgs = calledMeth.ArgSets |> List.collect (fun argSet -> argSet.UnnamedCallerArgs) + let unnamedArgs = + (unnamedCalledArgs, unnamedCallerArgs) ||> List.map2 (fun called caller -> + { NamedArgIdOpt = None; CalledArg=called; CallerArg=caller }) + + let emptyPreBinder (e: Expr) = e + + // Adjust all the optional arguments that require a default value to be inserted into the call + let optArgs, optArgPreBinder = + (emptyPreBinder, calledMeth.UnnamedCalledOptArgs) ||> List.mapFold (fun wrapper calledArg -> + let calledArgTy = calledArg.CalledArgumentType + let wrapper2, expr = + match calledArg.OptArgInfo with + | NotOptional -> + error(InternalError("Unexpected NotOptional", mItem)) + + | CallerSide dfltVal -> + + let rec build currCalledArgTy currDfltVal = + match currDfltVal with + | MissingValue -> + // Add an I_nop if this is an initonly field to make sure we never recognize it as an lvalue. See mkExprAddrOfExpr. + emptyPreBinder, mkAsmExpr ([ mkNormalLdsfld (fspec_Missing_Value g); AI_nop ], [], [], [currCalledArgTy], mMethExpr) + + | DefaultValue -> + emptyPreBinder, mkDefault(mMethExpr, currCalledArgTy) + + | Constant fieldInit -> + match currCalledArgTy with + | NullableTy g inst when fieldInit <> ILFieldInit.Null -> + let nullableTy = mkILNonGenericBoxedTy(g.FindSysILTypeRef "System.Nullable`1") + let ctor = mkILCtorMethSpecForTy(nullableTy, [ILType.TypeVar 0us]).MethodRef + let ctorArgs = [Expr.Const (tcFieldInit mMethExpr fieldInit, mMethExpr, inst)] + emptyPreBinder, Expr.Op (TOp.ILCall (false, false, true, true, NormalValUse, false, false, ctor, [inst], [], [currCalledArgTy]), [], ctorArgs, mMethExpr) + | ByrefTy g inst -> + build inst (PassByRef(inst, currDfltVal)) + | _ -> + match calledArg.CallerInfo, eCallerMemberName with + | CallerLineNumber, _ when typeEquiv g currCalledArgTy g.int_ty -> + emptyPreBinder, Expr.Const (Const.Int32(mMethExpr.StartLine), mMethExpr, currCalledArgTy) + | CallerFilePath, _ when typeEquiv g currCalledArgTy g.string_ty -> + let fileName = mMethExpr.FileName |> FileSystem.GetFullPathShim |> PathMap.apply g.pathMap + emptyPreBinder, Expr.Const (Const.String fileName, mMethExpr, currCalledArgTy) + | CallerMemberName, Some callerName when (typeEquiv g currCalledArgTy g.string_ty) -> + emptyPreBinder, Expr.Const (Const.String callerName, mMethExpr, currCalledArgTy) + | _ -> + emptyPreBinder, Expr.Const (tcFieldInit mMethExpr fieldInit, mMethExpr, currCalledArgTy) + + | WrapperForIDispatch -> + match g.TryFindSysILTypeRef "System.Runtime.InteropServices.DispatchWrapper" with + | None -> error(Error(FSComp.SR.fscSystemRuntimeInteropServicesIsRequired(), mMethExpr)) + | Some tref -> + let ty = mkILNonGenericBoxedTy tref + let mref = mkILCtorMethSpecForTy(ty, [g.ilg.typ_Object]).MethodRef + let expr = Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [g.obj_ty]), [], [mkDefault(mMethExpr, currCalledArgTy)], mMethExpr) + emptyPreBinder, expr + + | WrapperForIUnknown -> + match g.TryFindSysILTypeRef "System.Runtime.InteropServices.UnknownWrapper" with + | None -> error(Error(FSComp.SR.fscSystemRuntimeInteropServicesIsRequired(), mMethExpr)) + | Some tref -> + let ty = mkILNonGenericBoxedTy tref + let mref = mkILCtorMethSpecForTy(ty, [g.ilg.typ_Object]).MethodRef + let expr = Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [g.obj_ty]), [], [mkDefault(mMethExpr, currCalledArgTy)], mMethExpr) + emptyPreBinder, expr + + | PassByRef (ty, dfltVal2) -> + let v, _ = mkCompGenLocal mMethExpr "defaultByrefArg" ty + let wrapper2, rhs = build currCalledArgTy dfltVal2 + (wrapper2 >> mkCompGenLet mMethExpr v rhs), mkValAddr mMethExpr false (mkLocalValRef v) + build calledArgTy dfltVal + + | CalleeSide -> + let calledNonOptTy = + if isOptionTy g calledArgTy then + destOptionTy g calledArgTy + else + calledArgTy // should be unreachable + + match calledArg.CallerInfo, eCallerMemberName with + | CallerLineNumber, _ when typeEquiv g calledNonOptTy g.int_ty -> + let lineExpr = Expr.Const(Const.Int32 mMethExpr.StartLine, mMethExpr, calledNonOptTy) + emptyPreBinder, mkSome g calledNonOptTy lineExpr mMethExpr + | CallerFilePath, _ when typeEquiv g calledNonOptTy g.string_ty -> + let fileName = mMethExpr.FileName |> FileSystem.GetFullPathShim |> PathMap.apply g.pathMap + let filePathExpr = Expr.Const (Const.String(fileName), mMethExpr, calledNonOptTy) + emptyPreBinder, mkSome g calledNonOptTy filePathExpr mMethExpr + | CallerMemberName, Some(callerName) when typeEquiv g calledNonOptTy g.string_ty -> + let memberNameExpr = Expr.Const (Const.String callerName, mMethExpr, calledNonOptTy) + emptyPreBinder, mkSome g calledNonOptTy memberNameExpr mMethExpr + | _ -> + emptyPreBinder, mkNone g calledNonOptTy mMethExpr + + // Combine the variable allocators (if any) + let wrapper = (wrapper >> wrapper2) + let callerArg = CallerArg(calledArgTy, mMethExpr, false, expr) + { NamedArgIdOpt = None; CalledArg = calledArg; CallerArg = callerArg }, wrapper) + + // Adjust all the optional arguments + let wrapOptionalArg (assignedArg: AssignedCalledArg<_>) = + let (CallerArg(callerArgTy, m, isOptCallerArg, callerArgExpr)) = assignedArg.CallerArg + match assignedArg.CalledArg.OptArgInfo with + | NotOptional -> + if isOptCallerArg then errorR(Error(FSComp.SR.tcFormalArgumentIsNotOptional(), m)) + assignedArg + | _ -> + let callerArgExpr2 = + match assignedArg.CalledArg.OptArgInfo with + | CallerSide _ -> + if isOptCallerArg then + // M(?x=bopt) when M(A) --> M(?x=bopt.Value) for caller-side + // STRUCT OPTIONS: if we allow struct options as optional arguments then we should take + // the address correctly. + mkUnionCaseFieldGetUnprovenViaExprAddr (callerArgExpr, mkSomeCase g, [destOptionTy g callerArgTy], 0, m) + else + // M(x=b) when M(A) --> M(?x=b) for caller-side + callerArgExpr + + | CalleeSide -> + if isOptCallerArg then + // M(?x=bopt) when M(A) --> M(?x=Some(bopt.Value)) + callerArgExpr + else + // M(x=b) when M(A) --> M(?x=Some(b :> A)) + let calledArgTy = assignedArg.CalledArg.CalledArgumentType + if isOptionTy g calledArgTy then + let calledNonOptTy = destOptionTy g calledArgTy + mkSome g calledNonOptTy (mkCoerceIfNeeded g calledNonOptTy callerArgTy callerArgExpr) m + else + callerArgExpr // should be unreachable + + | _ -> failwith "Unreachable" + { assignedArg with CallerArg=CallerArg(tyOfExpr g callerArgExpr2, m, isOptCallerArg, callerArgExpr2) } + + let adjustedNormalUnnamedArgs = List.map wrapOptionalArg unnamedArgs + let adjustedAssignedNamedArgs = List.map wrapOptionalArg assignedNamedArgs + + optArgs, optArgPreBinder, adjustedNormalUnnamedArgs, adjustedAssignedNamedArgs + +/// Adjust any 'out' arguments, passing in the address of a mutable local +let AdjustOutCallerArgExprs g (calledMeth: CalledMeth<_>) mMethExpr = + calledMeth.UnnamedCalledOutArgs |> List.map (fun calledArg -> + let calledArgTy = calledArg.CalledArgumentType + let outArgTy = destByrefTy g calledArgTy + let outv, outArgExpr = mkMutableCompGenLocal mMethExpr PrettyNaming.outArgCompilerGeneratedName outArgTy // mutable! + let expr = mkDefault (mMethExpr, outArgTy) + let callerArg = CallerArg (calledArgTy, mMethExpr, false, mkValAddr mMethExpr false (mkLocalValRef outv)) + let outArg = { NamedArgIdOpt=None;CalledArg=calledArg;CallerArg=callerArg } + outArg, outArgExpr, mkCompGenBind outv expr) + |> List.unzip3 + +let AdjustParamArrayCallerArgExprs g amap infoReader ad (calledMeth: CalledMeth<_>) mMethExpr = + let argSets = calledMeth.ArgSets + + let paramArrayCallerArgs = argSets |> List.collect (fun argSet -> argSet.ParamArrayCallerArgs) + match calledMeth.ParamArrayCalledArgOpt with + | None -> + [], [] + | Some paramArrayCalledArg -> + let paramArrayCalledArgElementType = destArrayTy g paramArrayCalledArg.CalledArgumentType + + let paramArrayPreBinders, es = + paramArrayCallerArgs + |> List.map (fun callerArg -> + let (CallerArg(callerArgTy, m, isOutArg, callerArgExpr)) = callerArg + AdjustCallerArgExprForCoercions g amap infoReader ad isOutArg paramArrayCalledArgElementType paramArrayCalledArg.ReflArgInfo callerArgTy m callerArgExpr) + |> List.unzip + + let arg = + [ { NamedArgIdOpt = None + CalledArg=paramArrayCalledArg + CallerArg=CallerArg(paramArrayCalledArg.CalledArgumentType, mMethExpr, false, Expr.Op (TOp.Array, [paramArrayCalledArgElementType], es, mMethExpr)) } ] + paramArrayPreBinders, arg + +/// Build the argument list for a method call. Adjust for param array, optional arguments, byref arguments and coercions. +/// For example, if you pass an F# reference cell to a byref then we must get the address of the +/// contents of the ref. Likewise lots of adjustments are made for optional arguments etc. +let AdjustCallerArgExprs tcFieldInit eCallerMemberName g amap infoReader ad (calledMeth: CalledMeth<_>) objArgs lambdaVars mItem mMethExpr = + let calledMethInfo = calledMeth.Method + + // Some of the code below must allocate temporary variables or bind other variables to particular values. + // As usual we represent variable allocators by expr -> expr functions + // which we then use to wrap the whole expression. These will either do nothing or pre-bind a variable. It doesn't + // matter what order they are applied in as long as they are all composed together. + let emptyPreBinder (e: Expr) = e + + // For unapplied 'e.M' we first evaluate 'e' outside the lambda, i.e. 'let v = e in (fun arg -> v.M(arg))' + let objArgPreBinder, objArgs = + match objArgs, lambdaVars with + | [objArg], Some _ -> + if calledMethInfo.IsExtensionMember && calledMethInfo.ObjArgNeedsAddress(amap, mMethExpr) then + error(Error(FSComp.SR.tcCannotPartiallyApplyExtensionMethodForByref(calledMethInfo.DisplayName), mMethExpr)) + let objArgTy = tyOfExpr g objArg + let v, ve = mkCompGenLocal mMethExpr "objectArg" objArgTy + (fun body -> mkCompGenLet mMethExpr v objArg body), [ve] + | _ -> + emptyPreBinder, objArgs + + // Handle param array and optional arguments + let paramArrayPreBinders, paramArrayArgs = + AdjustParamArrayCallerArgExprs g amap infoReader ad calledMeth mMethExpr + + let optArgs, optArgPreBinder, adjustedNormalUnnamedArgs, adjustedFinalAssignedNamedArgs = + AdjustOptionalCallerArgExprs tcFieldInit eCallerMemberName g calledMeth mItem mMethExpr + + let outArgs, outArgExprs, outArgTmpBinds = + AdjustOutCallerArgExprs g calledMeth mMethExpr + + let allArgs = + adjustedNormalUnnamedArgs @ + adjustedFinalAssignedNamedArgs @ + paramArrayArgs @ + optArgs @ + outArgs + + let allArgs = + allArgs |> List.sortBy (fun x -> x.Position) + + let allArgsPreBinders, allArgsCoerced = + allArgs + |> List.map (fun assignedArg -> + let isOutArg = assignedArg.CalledArg.IsOutArg + let reflArgInfo = assignedArg.CalledArg.ReflArgInfo + let calledArgTy = assignedArg.CalledArg.CalledArgumentType + let (CallerArg(callerArgTy, m, _, e)) = assignedArg.CallerArg + + AdjustCallerArgExprForCoercions g amap infoReader ad isOutArg calledArgTy reflArgInfo callerArgTy m e) + |> List.unzip + + objArgPreBinder, objArgs, allArgsPreBinders, allArgs, allArgsCoerced, optArgPreBinder, paramArrayPreBinders, outArgExprs, outArgTmpBinds + //------------------------------------------------------------------------- // Additional helpers for building method calls and doing TAST generation //------------------------------------------------------------------------- @@ -573,27 +925,30 @@ let ComputeConstrainedCallInfo g amap m (objArgs, minfo: MethInfo) = | _ -> None - /// Adjust the 'this' pointer before making a call /// Take the address of a struct, and coerce to an interface/base/constraint type if necessary let TakeObjAddrForMethodCall g amap (minfo: MethInfo) isMutable m objArgs f = let ccallInfo = ComputeConstrainedCallInfo g amap m (objArgs, minfo) let wrap, objArgs = + match objArgs with | [objArgExpr] -> + let hasCallInfo = ccallInfo.IsSome let mustTakeAddress = hasCallInfo || minfo.ObjArgNeedsAddress(amap, m) let objArgTy = tyOfExpr g objArgExpr - let wrap, objArgExpr', isReadOnly, _isWriteOnly = mkExprAddrOfExpr g mustTakeAddress hasCallInfo isMutable objArgExpr None m + + let wrap, objArgExprAddr, isReadOnly, _isWriteOnly = + mkExprAddrOfExpr g mustTakeAddress hasCallInfo isMutable objArgExpr None m // Extension members and calls to class constraints may need a coercion for their object argument - let objArgExpr' = + let objArgExprCoerced = if not hasCallInfo && not (TypeDefinitelySubsumesTypeNoCoercion 0 g amap m minfo.ApparentEnclosingType objArgTy) then - mkCoerceExpr(objArgExpr', minfo.ApparentEnclosingType, m, objArgTy) + mkCoerceExpr(objArgExprAddr, minfo.ApparentEnclosingType, m, objArgTy) else - objArgExpr' + objArgExprAddr // Check to see if the extension member uses the extending type as a byref. // If so, make sure we don't allow readonly/immutable values to be passed byref from an extension member. @@ -605,7 +960,7 @@ let TakeObjAddrForMethodCall g amap (minfo: MethInfo) isMutable m objArgs f = errorR(Error(FSComp.SR.tcCannotCallExtensionMethodInrefToByref(minfo.DisplayName), m))) - wrap, [objArgExpr'] + wrap, [objArgExprCoerced] | _ -> id, objArgs @@ -616,11 +971,6 @@ let TakeObjAddrForMethodCall g amap (minfo: MethInfo) isMutable m objArgs f = // Build method calls. //------------------------------------------------------------------------- -//------------------------------------------------------------------------- -// Build calls -//------------------------------------------------------------------------- - - /// Build an expression node that is a call to a .NET method. let BuildILMethInfoCall g amap m isProp (minfo: ILMethInfo) valUseFlags minst direct args = let valu = isStructTy g minfo.ApparentEnclosingType @@ -638,11 +988,6 @@ let BuildILMethInfoCall g amap m isProp (minfo: ILMethInfo) valUseFlags minst di Expr.Op (TOp.ILCall (useCallvirt, isProtected, valu, newobj, valUseFlags, isProp, isDllImport, ilMethRef, minfo.DeclaringTypeInst, minst, retTy), [], args, m), exprTy -/// Build a call to the System.Object constructor taking no arguments, -let BuildObjCtorCall (g: TcGlobals) m = - let ilMethRef = (mkILCtorMethSpecForTy(g.ilg.typ_Object, [])).MethodRef - Expr.Op (TOp.ILCall (false, false, false, false, CtorValUsedAsSuperInit, false, true, ilMethRef, [], [], [g.obj_ty]), [], [], m) - /// Build a call to an F# method. /// @@ -825,55 +1170,6 @@ let BuildMethodCall tcVal g amap isMutable m isProp minfo valUseFlags minst objA errorR(Error(FSComp.SR.tcDefaultStructConstructorCall(), m)) mkDefault (m, ty), ty) -//------------------------------------------------------------------------- -// Build delegate constructions (lambdas/functions to delegates) -//------------------------------------------------------------------------- - -/// Implements the elaborated form of adhoc conversions from functions to delegates at member callsites -let BuildNewDelegateExpr (eventInfoOpt: EventInfo option, g, amap, delegateTy, invokeMethInfo: MethInfo, delArgTys, f, fty, m) = - let slotsig = invokeMethInfo.GetSlotSig(amap, m) - let delArgVals, expr = - let topValInfo = ValReprInfo([], List.replicate (max 1 (List.length delArgTys)) ValReprInfo.unnamedTopArg, ValReprInfo.unnamedRetVal) - - // Try to pull apart an explicit lambda and use it directly - // Don't do this in the case where we're adjusting the arguments of a function used to build a .NET-compatible event handler - let lambdaContents = - if Option.isSome eventInfoOpt then - None - else - tryDestTopLambda g amap topValInfo (f, fty) - - match lambdaContents with - | None -> - - if List.exists (isByrefTy g) delArgTys then - error(Error(FSComp.SR.tcFunctionRequiresExplicitLambda(List.length delArgTys), m)) - - let delArgVals = delArgTys |> List.mapi (fun i argty -> fst (mkCompGenLocal m ("delegateArg" + string i) argty)) - let expr = - let args = - match eventInfoOpt with - | Some einfo -> - match delArgVals with - | [] -> error(nonStandardEventError einfo.EventName m) - | h :: _ when not (isObjTy g h.Type) -> error(nonStandardEventError einfo.EventName m) - | h :: t -> [exprForVal m h; mkRefTupledVars g m t] - | None -> - if isNil delArgTys then [mkUnit g m] else List.map (exprForVal m) delArgVals - mkApps g ((f, fty), [], args, m) - delArgVals, expr - - | Some _ -> - let _, _, _, vsl, body, _ = IteratedAdjustArityOfLambda g amap topValInfo f - List.concat vsl, body - - let meth = TObjExprMethod(slotsig, [], [], [delArgVals], expr, m) - mkObjExpr(delegateTy, None, BuildObjCtorCall g m, [meth], [], m) - -let CoerceFromFSharpFuncToDelegate g amap infoReader ad callerArgTy m callerArgExpr delegateTy = - let (SigOfFunctionForDelegate(invokeMethInfo, delArgTys, _, _)) = GetSigOfFunctionForDelegate infoReader delegateTy m ad - BuildNewDelegateExpr (None, g, amap, delegateTy, invokeMethInfo, delArgTys, callerArgExpr, callerArgTy, m) - //------------------------------------------------------------------------- // Import provided expressions @@ -972,11 +1268,14 @@ module ProvidedMethodCalls = st loop inputType - let convertProvidedExpressionToExprAndWitness tcVal (thisArg: Expr option, - allArgs: Exprs, - paramVars: Tainted[], - g, amap, mut, isProp, isSuperInit, m, - expr: Tainted) = + let convertProvidedExpressionToExprAndWitness + tcVal + (thisArg: Expr option, + allArgs: Exprs, + paramVars: Tainted[], + g, amap, mut, isProp, isSuperInit, m, + expr: Tainted) = + let varConv = // note: using paramVars.Length as assumed initial size, but this might not // be the optimal value; this wasn't checked before obsoleting Dictionary.ofList diff --git a/src/fsharp/NicePrint.fs b/src/fsharp/NicePrint.fs index 5d56543e992..2d9ea197db4 100644 --- a/src/fsharp/NicePrint.fs +++ b/src/fsharp/NicePrint.fs @@ -32,8 +32,8 @@ module internal PrintUtilities = let bracketIfL x lyt = if x then bracketL lyt else lyt let squareAngleL x = LeftL.leftBracketAngle ^^ x ^^ RightL.rightBracketAngle let angleL x = sepL Literals.leftAngle ^^ x ^^ rightL Literals.rightAngle - let braceL x = leftL Literals.leftBrace ^^ x ^^ rightL Literals.rightBrace - let braceBarL x = leftL Literals.leftBraceBar ^^ x ^^ rightL Literals.rightBraceBar + let braceL x = wordL Literals.leftBrace ^^ x ^^ wordL Literals.rightBrace + let braceBarL x = wordL Literals.leftBraceBar ^^ x ^^ wordL Literals.rightBraceBar let comment str = wordL (tagText (sprintf "(* %s *)" str)) @@ -942,7 +942,7 @@ module private PrintTypes = // Layout a tuple type | TType_anon (anonInfo, tys) -> - let core = sepListL (wordL (tagPunctuation ";")) (List.map2 (fun nm ty -> wordL (tagField nm) ^^ wordL (tagPunctuation ":") ^^ layoutTypeWithInfoAndPrec denv env prec ty) (Array.toList anonInfo.SortedNames) tys) + let core = sepListL (rightL (tagPunctuation ";")) (List.map2 (fun nm ty -> wordL (tagField nm) ^^ rightL (tagPunctuation ":") ^^ layoutTypeWithInfoAndPrec denv env prec ty) (Array.toList anonInfo.SortedNames) tys) if evalAnonInfoIsStruct anonInfo then WordL.keywordStruct --- braceBarL core else @@ -1457,7 +1457,7 @@ module private TastDefinitionPrinting = let lhs = tagRecordField fld.Name |> mkNav fld.DefinitionRange - |> wordL + |> wordL let lhs = (if addAccess then layoutAccessibility denv fld.Accessibility lhs else lhs) let lhs = if fld.IsMutable then wordL (tagKeyword "mutable") --- lhs else lhs (lhs ^^ RightL.colon) --- layoutType denv fld.FormalType @@ -1738,8 +1738,15 @@ module private TastDefinitionPrinting = let denv = denv.AddAccessibility tycon.TypeReprAccessibility match repr with | TRecdRepr _ -> - let recdFieldRefL fld = layoutRecdField false denv fld ^^ rightL (tagPunctuation ";") - let recdL = tycon.TrueFieldsAsList |> List.map recdFieldRefL |> applyMaxMembers denv.maxMembers |> aboveListL |> braceL + let recdFieldRefL fld = layoutRecdField false denv fld + + let recdL = + tycon.TrueFieldsAsList + |> List.map recdFieldRefL + |> applyMaxMembers denv.maxMembers + |> aboveListL + |> braceL + Some (addMembersAsWithEnd (addReprAccessL recdL)) | TFSharpObjectRepr r -> @@ -1771,8 +1778,7 @@ module private TastDefinitionPrinting = | _ -> [] let vsprs = tycon.MembersOfFSharpTyconSorted - |> List.filter (fun v -> isNil (Option.get v.MemberInfo).ImplementedSlotSigs) - |> List.filter (fun v -> v.IsDispatchSlot) + |> List.filter (fun v -> isNil (Option.get v.MemberInfo).ImplementedSlotSigs && v.IsDispatchSlot) |> List.map (fun vref -> PrintTastMemberOrVals.prettyLayoutOfValOrMemberNoInst denv vref.Deref) let staticValsLs = tycon.TrueFieldsAsList diff --git a/src/fsharp/TastOps.fs b/src/fsharp/TastOps.fs index 11c5d5e8a1c..18894044784 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -840,16 +840,6 @@ let tryNiceEntityRefOfTyOption ty = | TType_app (tcref, _) -> Some tcref | TType_measure (Measure.Con tcref) -> Some tcref | _ -> None - -let (|NullableTy|_|) g ty = - match tryAppTy g ty with - | ValueSome (tcref, [tyarg]) when tyconRefEq g tcref g.system_Nullable_tcref -> Some tyarg - | _ -> None - -let (|StripNullableTy|) g ty = - match tryAppTy g ty with - | ValueSome (tcref, [tyarg]) when tyconRefEq g tcref g.system_Nullable_tcref -> tyarg - | _ -> ty let mkInstForAppTy g ty = match tryAppTy g ty with @@ -3126,6 +3116,31 @@ let destOptionTy g ty = | ValueSome ty -> ty | ValueNone -> failwith "destOptionTy: not an option type" +let isNullableTy (g: TcGlobals) ty = + match tryDestAppTy g ty with + | ValueNone -> false + | ValueSome tcref -> tyconRefEq g g.system_Nullable_tcref tcref + +let tryDestNullableTy g ty = + match argsOfAppTy g ty with + | [ty1] when isNullableTy g ty -> ValueSome ty1 + | _ -> ValueNone + +let destNullableTy g ty = + match tryDestNullableTy g ty with + | ValueSome ty -> ty + | ValueNone -> failwith "destNullableTy: not a Nullable type" + +let (|NullableTy|_|) g ty = + match tryAppTy g ty with + | ValueSome (tcref, [tyarg]) when tyconRefEq g tcref g.system_Nullable_tcref -> Some tyarg + | _ -> None + +let (|StripNullableTy|) g ty = + match tryDestNullableTy g ty with + | ValueSome tyarg -> tyarg + | _ -> ty + let isLinqExpressionTy g ty = match tryDestAppTy g ty with | ValueNone -> false diff --git a/src/fsharp/TastOps.fsi b/src/fsharp/TastOps.fsi index 01e2070c419..1da22742300 100755 --- a/src/fsharp/TastOps.fsi +++ b/src/fsharp/TastOps.fsi @@ -1388,7 +1388,7 @@ val mkVoidPtrTy : TcGlobals -> TType /// Build a single-dimensional array type val mkArrayType : TcGlobals -> TType -> TType -/// Determine is a type is an option type +/// Determine if a type is an option type val isOptionTy : TcGlobals -> TType -> bool /// Take apart an option type @@ -1397,6 +1397,15 @@ val destOptionTy : TcGlobals -> TType -> TType /// Try to take apart an option type val tryDestOptionTy : TcGlobals -> TType -> ValueOption +/// Determine is a type is a System.Nullable type +val isNullableTy : TcGlobals -> TType -> bool + +/// Try to take apart a System.Nullable type +val tryDestNullableTy: TcGlobals -> TType -> ValueOption + +/// Take apart a System.Nullable type +val destNullableTy: TcGlobals -> TType -> TType + /// Determine if a type is a System.Linq.Expression type val isLinqExpressionTy : TcGlobals -> TType -> bool diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 604d113fc7f..bf70c63a178 100644 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -9841,75 +9841,74 @@ and TcMethodApplication // In one case (the second "single named item" rule) we delay the application of a // argument until we've produced a lambda that detuples an input tuple let curriedCallerArgsOpt, unnamedDelayedCallerArgExprOpt, exprTy = - match curriedCallerArgs with - | [] -> - None, None, exprTy - | _ -> - let unnamedCurriedCallerArgs, namedCurriedCallerArgs = curriedCallerArgs |> List.map GetMethodArgs |> List.unzip + match curriedCallerArgs with + | [] -> + None, None, exprTy + | _ -> + let unnamedCurriedCallerArgs, namedCurriedCallerArgs = curriedCallerArgs |> List.map GetMethodArgs |> List.unzip - // There is an mismatch when _uses_ of indexed property setters in the tc.fs code that calls this function. - // The arguments are passed as if they are curried with arity [numberOfIndexParameters;1], however in the TAST, indexed property setters - // are uncurried and have arity [numberOfIndexParameters+1]. - // - // Here we work around this mismatch by crunching all property argument lists to uncirred form. - // Ideally the problem needs to be solved at its root cause at the callsites to this function - let unnamedCurriedCallerArgs, namedCurriedCallerArgs = - if isProp then - [List.concat unnamedCurriedCallerArgs], [List.concat namedCurriedCallerArgs] - else - unnamedCurriedCallerArgs, namedCurriedCallerArgs + // There is an mismatch when _uses_ of indexed property setters in the tc.fs code that calls this function. + // The arguments are passed as if they are curried with arity [numberOfIndexParameters;1], however in the TAST, indexed property setters + // are uncurried and have arity [numberOfIndexParameters+1]. + // + // Here we work around this mismatch by crunching all property argument lists to uncirred form. + // Ideally the problem needs to be solved at its root cause at the callsites to this function + let unnamedCurriedCallerArgs, namedCurriedCallerArgs = + if isProp then + [List.concat unnamedCurriedCallerArgs], [List.concat namedCurriedCallerArgs] + else + unnamedCurriedCallerArgs, namedCurriedCallerArgs - let MakeUnnamedCallerArgInfo x = (x, GetNewInferenceTypeForMethodArg cenv env tpenv x, x.Range) - - // "single named item" rule. This is where we have a single accessible method - // member x.M(arg1) - // being used with - // x.M (x, y) - // Without this rule this requires - // x.M ((x, y)) - match candidates with - | [calledMeth] - when (namedCurriedCallerArgs |> List.forall isNil && - let curriedCalledArgs = calledMeth.GetParamAttribs(cenv.amap, mItem) - curriedCalledArgs.Length = 1 && - curriedCalledArgs.Head.Length = 1 && - curriedCalledArgs.Head.Head |> isSimpleFormalArg) -> - let unnamedCurriedCallerArgs = curriedCallerArgs |> List.map (MakeUnnamedCallerArgInfo >> List.singleton) - let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.map (fun _ -> []) - (Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), None, exprTy) - - // "single named item" rule. This is where we have a single accessible method - // member x.M(arg1, arg2) - // being used with - // x.M p - // We typecheck this as if it has been written "(fun (v1, v2) -> x.M(v1, v2)) p" - // Without this rule this requires - // x.M (fst p, snd p) - | [calledMeth] - when (namedCurriedCallerArgs |> List.forall isNil && - unnamedCurriedCallerArgs.Length = 1 && - unnamedCurriedCallerArgs.Head.Length = 1 && - let curriedCalledArgs = calledMeth.GetParamAttribs(cenv.amap, mItem) - curriedCalledArgs.Length = 1 && - curriedCalledArgs.Head.Length > 1 && - curriedCalledArgs.Head |> List.forall isSimpleFormalArg) -> - - // The call lambda has function type - let exprTy = mkFunTy (NewInferenceType ()) exprTy + let MakeUnnamedCallerArgInfo x = (x, GetNewInferenceTypeForMethodArg cenv env tpenv x, x.Range) + + // "single named item" rule. This is where we have a single accessible method + // member x.M(arg1) + // being used with + // x.M (x, y) + // Without this rule this requires + // x.M ((x, y)) + match candidates with + | [calledMeth] + when (namedCurriedCallerArgs |> List.forall isNil && + let curriedCalledArgs = calledMeth.GetParamAttribs(cenv.amap, mItem) + curriedCalledArgs.Length = 1 && + curriedCalledArgs.Head.Length = 1 && + curriedCalledArgs.Head.Head |> isSimpleFormalArg) -> + let unnamedCurriedCallerArgs = curriedCallerArgs |> List.map (MakeUnnamedCallerArgInfo >> List.singleton) + let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.map (fun _ -> []) + (Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), None, exprTy) + + // "single named item" rule. This is where we have a single accessible method + // member x.M(arg1, arg2) + // being used with + // x.M p + // We typecheck this as if it has been written "(fun (v1, v2) -> x.M(v1, v2)) p" + // Without this rule this requires + // x.M (fst p, snd p) + | [calledMeth] + when (namedCurriedCallerArgs |> List.forall isNil && + unnamedCurriedCallerArgs.Length = 1 && + unnamedCurriedCallerArgs.Head.Length = 1 && + let curriedCalledArgs = calledMeth.GetParamAttribs(cenv.amap, mItem) + curriedCalledArgs.Length = 1 && + curriedCalledArgs.Head.Length > 1 && + curriedCalledArgs.Head |> List.forall isSimpleFormalArg) -> + + // The call lambda has function type + let exprTy = mkFunTy (NewInferenceType ()) exprTy - (None, Some unnamedCurriedCallerArgs.Head.Head, exprTy) + (None, Some unnamedCurriedCallerArgs.Head.Head, exprTy) - | _ -> - let unnamedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.mapSquared MakeUnnamedCallerArgInfo - let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.mapSquared (fun (isOpt, nm, x) -> - let ty = GetNewInferenceTypeForMethodArg cenv env tpenv x - // #435263: compiler crash with .net optional parameters and F# optional syntax - // named optional arguments should always have option type - let ty = if isOpt then mkOptionTy denv.g ty else ty - nm, isOpt, x, ty, x.Range - ) - - (Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), None, exprTy) + | _ -> + let unnamedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.mapSquared MakeUnnamedCallerArgInfo + let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.mapSquared (fun (isOpt, nm, x) -> + let ty = GetNewInferenceTypeForMethodArg cenv env tpenv x + // #435263: compiler crash with .net optional parameters and F# optional syntax + // named optional arguments should always have option type + let ty = if isOpt then mkOptionTy denv.g ty else ty + nm, isOpt, x, ty, x.Range) + + (Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), None, exprTy) let CalledMethHasSingleArgumentGroupOfThisLength n (calledMeth: MethInfo) = @@ -10153,21 +10152,12 @@ and TcMethodApplication let finalCalledMethInfo = finalCalledMeth.Method let finalCalledMethInst = finalCalledMeth.CalledTyArgs - let finalArgSets = finalCalledMeth.ArgSets let finalAssignedItemSetters = finalCalledMeth.AssignedItemSetters - let finalCalledPropInfoOpt = finalCalledMeth.AssociatedPropertyInfo let finalAttributeAssignedNamedItems = finalCalledMeth.AttributeAssignedNamedArgs - let finalUnnamedCalledOptArgs = finalCalledMeth.UnnamedCalledOptArgs - let finalUnnamedCalledOutArgs = finalCalledMeth.UnnamedCalledOutArgs - let finalAssignedNamedArgs = finalArgSets |> List.collect (fun argSet -> argSet.AssignedNamedArgs) - let finalParamArrayCallerArgs = finalArgSets |> List.collect (fun argSet -> argSet.ParamArrayCallerArgs) - let finalUnnamedCalledArgs = finalArgSets |> List.collect (fun argSet -> argSet.UnnamedCalledArgs) - let finalUnnamedCallerArgs = finalArgSets |> List.collect (fun argSet -> argSet.UnnamedCallerArgs) - // STEP 4. Check the attributes on the method and the corresponding event/property, if any - finalCalledPropInfoOpt |> Option.iter (fun pinfo -> CheckPropInfoAttributes pinfo mItem |> CommitOperationResult) + finalCalledMeth.AssociatedPropertyInfo |> Option.iter (fun pinfo -> CheckPropInfoAttributes pinfo mItem |> CommitOperationResult) let isInstance = not (isNil objArgs) MethInfoChecks cenv.g cenv.amap isInstance tyargsOpt objArgs ad mItem finalCalledMethInfo @@ -10196,266 +10186,13 @@ and TcMethodApplication | _ -> () end - if (finalArgSets |> List.existsi (fun i argSet -> argSet.UnnamedCalledArgs |> List.existsi (fun j ca -> ca.Position <> (i, j)))) then + if (finalCalledMeth.ArgSets |> List.existsi (fun i argSet -> argSet.UnnamedCalledArgs |> List.existsi (fun j ca -> ca.Position <> (i, j)))) then errorR(Deprecated(FSComp.SR.tcUnnamedArgumentsDoNotFormPrefix(), mMethExpr)) + /// STEP 5. Build the argument list. Adjust for optional arguments, byref arguments and coercions. - // STEP 5. Build the argument list. Adjust for optional arguments, byref arguments and coercions. - // For example, if you pass an F# reference cell to a byref then we must get the address of the - // contents of the ref. Likewise lots of adjustments are made for optional arguments etc. - - // Some of the code below must allocate temporary variables or bind other variables to particular values. - // As usual we represent variable allocators by expr -> expr functions - // which we then use to wrap the whole expression. These will either do nothing or pre-bind a variable. It doesn't - // matter what order they are applied in as long as they are all composed together. - let emptyPreBinder (e: Expr) = e - - // For unapplied 'e.M' we first evaluate 'e' outside the lambda, i.e. 'let v = e in (fun arg -> v.M(arg))' - let objArgPreBinder, objArgs = - match objArgs, lambdaVars with - | [objArg], Some _ -> - if finalCalledMethInfo.IsExtensionMember && finalCalledMethInfo.ObjArgNeedsAddress(cenv.amap, mMethExpr) then - error(Error(FSComp.SR.tcCannotPartiallyApplyExtensionMethodForByref(finalCalledMethInfo.DisplayName), mMethExpr)) - let objArgTy = tyOfExpr cenv.g objArg - let v, ve = mkCompGenLocal mMethExpr "objectArg" objArgTy - (fun body -> mkCompGenLet mMethExpr v objArg body), [ve] - | _ -> - emptyPreBinder, objArgs - - // Handle adhoc argument conversions - let coerceExpr isOutArg calledArgTy (reflArgInfo: ReflectedArgInfo) callerArgTy m callerArgExpr = - let g = cenv.g - - if isByrefTy g calledArgTy && isRefCellTy g callerArgTy then - None, Expr.Op (TOp.RefAddrGet false, [destRefCellTy g callerArgTy], [callerArgExpr], m) - -#if IMPLICIT_ADDRESS_OF - elif isInByrefTy g calledArgTy && not (isByrefTy cenv.g callerArgTy) then - let wrap, callerArgExprAddress, _readonly, _writeonly = mkExprAddrOfExpr g true false NeverMutates callerArgExpr None m - Some wrap, callerArgExprAddress -#endif - - elif isDelegateTy cenv.g calledArgTy && isFunTy cenv.g callerArgTy then - None, CoerceFromFSharpFuncToDelegate cenv.g cenv.amap cenv.infoReader ad callerArgTy m callerArgExpr calledArgTy - - elif isLinqExpressionTy cenv.g calledArgTy && isDelegateTy cenv.g (destLinqExpressionTy cenv.g calledArgTy) && isFunTy cenv.g callerArgTy then - let delegateTy = destLinqExpressionTy cenv.g calledArgTy - let expr = CoerceFromFSharpFuncToDelegate cenv.g cenv.amap cenv.infoReader ad callerArgTy m callerArgExpr delegateTy - None, mkCallQuoteToLinqLambdaExpression cenv.g m delegateTy (Expr.Quote (expr, ref None, false, m, mkQuotedExprTy cenv.g delegateTy)) - - // auto conversions to quotations (to match auto conversions to LINQ expressions) - elif reflArgInfo.AutoQuote && isQuotedExprTy cenv.g calledArgTy && not (isQuotedExprTy cenv.g callerArgTy) then - match reflArgInfo with - | ReflectedArgInfo.Quote true -> - None, mkCallLiftValueWithDefn cenv.g m calledArgTy callerArgExpr - | ReflectedArgInfo.Quote false -> - None, Expr.Quote (callerArgExpr, ref None, false, m, calledArgTy) - | ReflectedArgInfo.None -> failwith "unreachable" // unreachable due to reflArgInfo.AutoQuote condition - - // Note: out args do not need to be coerced - elif isOutArg then - None, callerArgExpr - - // Note: not all these casts are reported in quotations - else - None, mkCoerceIfNeeded cenv.g calledArgTy callerArgTy callerArgExpr - - // Handle param array and optional arguments - let optArgPreBinder, paramArrayPreBinders, allArgs, outArgExprs, outArgTmpBinds = - - let normalUnnamedArgs = - (finalUnnamedCalledArgs, finalUnnamedCallerArgs) ||> List.map2 (fun called caller -> { NamedArgIdOpt = None; CalledArg=called; CallerArg=caller }) - - let paramArrayPreBinders, paramArrayArgs = - match finalCalledMeth.ParamArrayCalledArgOpt with - | None -> - [], [] - | Some paramArrayCalledArg -> - let paramArrayCalledArgElementType = destArrayTy cenv.g paramArrayCalledArg.CalledArgumentType - - let paramArrayPreBinders, es = - finalParamArrayCallerArgs - |> List.map (fun callerArg -> - let (CallerArg(callerArgTy, m, isOutArg, callerArgExpr)) = callerArg - coerceExpr isOutArg paramArrayCalledArgElementType paramArrayCalledArg.ReflArgInfo callerArgTy m callerArgExpr) - |> List.unzip - - let arg = - [ { NamedArgIdOpt = None - CalledArg=paramArrayCalledArg - CallerArg=CallerArg(paramArrayCalledArg.CalledArgumentType, mMethExpr, false, Expr.Op (TOp.Array, [paramArrayCalledArgElementType], es, mMethExpr)) } ] - paramArrayPreBinders, arg - - // CLEANUP: Move all this code into some isolated file, e.g. "optional.fs" - // - // Handle CallerSide optional arguments. - // - // CallerSide optional arguments are largely for COM interop, e.g. to PIA assemblies for Word etc. - // As a result we follow the VB and C# behavior here. - // - // "1. If the parameter is statically typed as System.Object and does not have a value, then there are four cases: - // a. The parameter is marked with MarshalAs(IUnknown), MarshalAs(Interface), or MarshalAs(IDispatch). In this case we pass null. - // b. Else if the parameter is marked with IUnknownConstantAttribute. In this case we pass new System.Runtime.InteropServices.UnknownWrapper(null) - // c. Else if the parameter is marked with IDispatchConstantAttribute. In this case we pass new System.Runtime.InteropServices.DispatchWrapper(null) - // d. Else, we will pass Missing.Value. - // 2. Otherwise, if there is a value attribute, then emit the default value. - // 3. Otherwise, we emit default(T). - // 4. Finally, we apply conversions from the value to the parameter type. This is where the nullable conversions take place for VB. - // - VB allows you to mark ref parameters as optional. The semantics of this is that we create a temporary - // with type = type of parameter, load the optional value to it, and call the method. - // - VB also allows you to mark arrays with Nothing as the optional value. - // - VB also allows you to pass intrinsic values as optional values to parameters - // typed as Object. What we do in this case is we box the intrinsic value." - // - let optArgs, optArgPreBinder = - (emptyPreBinder, finalUnnamedCalledOptArgs) ||> List.mapFold (fun wrapper calledArg -> - let calledArgTy = calledArg.CalledArgumentType - let wrapper2, expr = - match calledArg.OptArgInfo with - | NotOptional -> - error(InternalError("Unexpected NotOptional", mItem)) - | CallerSide dfltVal -> - let rec build currCalledArgTy currDfltVal = - match currDfltVal with - | MissingValue -> - // Add an I_nop if this is an initonly field to make sure we never recognize it as an lvalue. See mkExprAddrOfExpr. - emptyPreBinder, mkAsmExpr ([ mkNormalLdsfld (fspec_Missing_Value cenv.g); AI_nop ], [], [], [currCalledArgTy], mMethExpr) - | DefaultValue -> - emptyPreBinder, mkDefault(mMethExpr, currCalledArgTy) - | Constant fieldInit -> - match currCalledArgTy with - | NullableTy cenv.g inst when fieldInit <> ILFieldInit.Null -> - let nullableTy = mkILNonGenericBoxedTy(cenv.g.FindSysILTypeRef "System.Nullable`1") - let ctor = mkILCtorMethSpecForTy(nullableTy, [ILType.TypeVar 0us]).MethodRef - let ctorArgs = [Expr.Const (TcFieldInit mMethExpr fieldInit, mMethExpr, inst)] - emptyPreBinder, Expr.Op (TOp.ILCall (false, false, true, true, NormalValUse, false, false, ctor, [inst], [], [currCalledArgTy]), [], ctorArgs, mMethExpr) - | ByrefTy cenv.g inst -> - build inst (PassByRef(inst, currDfltVal)) - | _ -> - match calledArg.CallerInfo, env.eCallerMemberName with - | CallerLineNumber, _ when typeEquiv cenv.g currCalledArgTy cenv.g.int_ty -> - emptyPreBinder, Expr.Const (Const.Int32(mMethExpr.StartLine), mMethExpr, currCalledArgTy) - | CallerFilePath, _ when typeEquiv cenv.g currCalledArgTy cenv.g.string_ty -> - let fileName = mMethExpr.FileName |> FileSystem.GetFullPathShim |> PathMap.apply cenv.g.pathMap - emptyPreBinder, Expr.Const (Const.String fileName, mMethExpr, currCalledArgTy) - | CallerMemberName, Some callerName when (typeEquiv cenv.g currCalledArgTy cenv.g.string_ty) -> - emptyPreBinder, Expr.Const (Const.String callerName, mMethExpr, currCalledArgTy) - | _ -> - emptyPreBinder, Expr.Const (TcFieldInit mMethExpr fieldInit, mMethExpr, currCalledArgTy) - - | WrapperForIDispatch -> - match cenv.g.TryFindSysILTypeRef "System.Runtime.InteropServices.DispatchWrapper" with - | None -> error(Error(FSComp.SR.fscSystemRuntimeInteropServicesIsRequired(), mMethExpr)) - | Some tref -> - let ty = mkILNonGenericBoxedTy tref - let mref = mkILCtorMethSpecForTy(ty, [cenv.g.ilg.typ_Object]).MethodRef - let expr = Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [cenv.g.obj_ty]), [], [mkDefault(mMethExpr, currCalledArgTy)], mMethExpr) - emptyPreBinder, expr - | WrapperForIUnknown -> - match cenv.g.TryFindSysILTypeRef "System.Runtime.InteropServices.UnknownWrapper" with - | None -> error(Error(FSComp.SR.fscSystemRuntimeInteropServicesIsRequired(), mMethExpr)) - | Some tref -> - let ty = mkILNonGenericBoxedTy tref - let mref = mkILCtorMethSpecForTy(ty, [cenv.g.ilg.typ_Object]).MethodRef - let expr = Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [cenv.g.obj_ty]), [], [mkDefault(mMethExpr, currCalledArgTy)], mMethExpr) - emptyPreBinder, expr - | PassByRef (ty, dfltVal2) -> - let v, _ = mkCompGenLocal mMethExpr "defaultByrefArg" ty - let wrapper2, rhs = build currCalledArgTy dfltVal2 - (wrapper2 >> mkCompGenLet mMethExpr v rhs), mkValAddr mMethExpr false (mkLocalValRef v) - build calledArgTy dfltVal - | CalleeSide -> - let calledNonOptTy = - if isOptionTy cenv.g calledArgTy then - destOptionTy cenv.g calledArgTy - else - calledArgTy // should be unreachable - - match calledArg.CallerInfo, env.eCallerMemberName with - | CallerLineNumber, _ when typeEquiv cenv.g calledNonOptTy cenv.g.int_ty -> - let lineExpr = Expr.Const(Const.Int32 mMethExpr.StartLine, mMethExpr, calledNonOptTy) - emptyPreBinder, mkSome cenv.g calledNonOptTy lineExpr mMethExpr - | CallerFilePath, _ when typeEquiv cenv.g calledNonOptTy cenv.g.string_ty -> - let fileName = mMethExpr.FileName |> FileSystem.GetFullPathShim |> PathMap.apply cenv.g.pathMap - let filePathExpr = Expr.Const (Const.String(fileName), mMethExpr, calledNonOptTy) - emptyPreBinder, mkSome cenv.g calledNonOptTy filePathExpr mMethExpr - | CallerMemberName, Some(callerName) when typeEquiv cenv.g calledNonOptTy cenv.g.string_ty -> - let memberNameExpr = Expr.Const (Const.String callerName, mMethExpr, calledNonOptTy) - emptyPreBinder, mkSome cenv.g calledNonOptTy memberNameExpr mMethExpr - | _ -> - emptyPreBinder, mkNone cenv.g calledNonOptTy mMethExpr - - // Combine the variable allocators (if any) - let wrapper = (wrapper >> wrapper2) - let callerArg = CallerArg(calledArgTy, mMethExpr, false, expr) - { NamedArgIdOpt = None; CalledArg = calledArg; CallerArg = callerArg }, wrapper) - - - // Handle optional arguments - let wrapOptionalArg (assignedArg: AssignedCalledArg<_>) = - let (CallerArg(callerArgTy, m, isOptCallerArg, expr)) = assignedArg.CallerArg - match assignedArg.CalledArg.OptArgInfo with - | NotOptional -> - if isOptCallerArg then errorR(Error(FSComp.SR.tcFormalArgumentIsNotOptional(), m)) - assignedArg - | _ -> - let expr = - match assignedArg.CalledArg.OptArgInfo with - | CallerSide _ -> - if isOptCallerArg then - // STRUCT OPTIONS: if we allow struct options as optional arguments then we should take - // the address correctly. - mkUnionCaseFieldGetUnprovenViaExprAddr (expr, mkSomeCase cenv.g, [destOptionTy cenv.g callerArgTy], 0, m) - else - expr - | CalleeSide -> - if isOptCallerArg then - // M(?x=bopt) when M(A) --> M(?x=Some(b.Value)) - expr - else - // M(x=b) when M(A) --> M(?x=Some(b :> A)) - let calledArgTy = assignedArg.CalledArg.CalledArgumentType - if isOptionTy cenv.g calledArgTy then - let calledNonOptTy = destOptionTy cenv.g calledArgTy - mkSome cenv.g calledNonOptTy (mkCoerceIfNeeded cenv.g calledNonOptTy callerArgTy expr) m - else - expr // should be unreachable - - | _ -> failwith "Unreachable" - { assignedArg with CallerArg=CallerArg((tyOfExpr cenv.g expr), m, isOptCallerArg, expr) } - - let outArgsAndExprs, outArgTmpBinds = - finalUnnamedCalledOutArgs |> List.map (fun calledArg -> - let calledArgTy = calledArg.CalledArgumentType - let outArgTy = destByrefTy cenv.g calledArgTy - let outv, outArgExpr = mkMutableCompGenLocal mMethExpr PrettyNaming.outArgCompilerGeneratedName outArgTy // mutable! - let expr = mkDefault(mMethExpr, outArgTy) - let callerArg = CallerArg(calledArgTy, mMethExpr, false, mkValAddr mMethExpr false (mkLocalValRef outv)) - let outArg = { NamedArgIdOpt=None;CalledArg=calledArg;CallerArg=callerArg } - (outArg, outArgExpr), mkCompGenBind outv expr) - |> List.unzip - - let outArgs, outArgExprs = List.unzip outArgsAndExprs - - let allArgs = - List.map wrapOptionalArg normalUnnamedArgs @ - List.map wrapOptionalArg finalAssignedNamedArgs @ - paramArrayArgs @ - optArgs @ - outArgs - - let allArgs = - allArgs |> List.sortBy (fun x -> x.Position) - - optArgPreBinder, paramArrayPreBinders, allArgs, outArgExprs, outArgTmpBinds - - let coerce (assignedArg: AssignedCalledArg<_>) = - let isOutArg = assignedArg.CalledArg.IsOutArg - let reflArgInfo = assignedArg.CalledArg.ReflArgInfo - let calledArgTy = assignedArg.CalledArg.CalledArgumentType - let (CallerArg(callerArgTy, m, _, e)) = assignedArg.CallerArg - - coerceExpr isOutArg calledArgTy reflArgInfo callerArgTy m e + let objArgPreBinder, objArgs, allArgsPreBinders, allArgs, allArgsCoerced, optArgPreBinder, paramArrayPreBinders, outArgExprs, outArgTmpBinds = + AdjustCallerArgExprs TcFieldInit env.eCallerMemberName cenv.g cenv.amap cenv.infoReader ad finalCalledMeth objArgs lambdaVars mItem mMethExpr // Record the resolution of the named argument for the Language Service allArgs |> List.iter (fun assignedArg -> @@ -10465,84 +10202,61 @@ and TcMethodApplication let item = Item.ArgName (defaultArg assignedArg.CalledArg.NameOpt id, assignedArg.CalledArg.CalledArgumentType, Some(ArgumentContainer.Method finalCalledMethInfo)) CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, item, emptyTyparInst, ItemOccurence.Use, env.DisplayEnv, ad)) - let allArgsPreBinders, allArgsCoerced = List.map coerce allArgs |> List.unzip - // Make the call expression - let expr, exprty = + /// STEP 6. Build the call expression, then adjust for byref-returns, out-parameters-as-tuples, post-hoc property assignments, methods-as-first-class-value, + /// + + let callExpr0, exprty = BuildPossiblyConditionalMethodCall cenv env mut mMethExpr isProp finalCalledMethInfo isSuperInit finalCalledMethInst objArgs allArgsCoerced // Handle byref returns - let expr = + let callExpr1 = // byref-typed returns get implicitly dereferenced - let vty = tyOfExpr cenv.g expr + let vty = tyOfExpr cenv.g callExpr0 if isByrefTy cenv.g vty then let v, _ = mkCompGenLocal mMethExpr "byrefReturn" vty - mkCompGenLet mMethExpr v expr (mkAddrGet mMethExpr (mkLocalValRef v)) + mkCompGenLet mMethExpr v callExpr0 (mkAddrGet mMethExpr (mkLocalValRef v)) else - expr + callExpr0 // Bind "out" parameters as part of the result tuple - let expr, exprty = + let callExpr2, exprty = + let expr = callExpr1 if isNil outArgTmpBinds then expr, exprty else let outArgTys = outArgExprs |> List.map (tyOfExpr cenv.g) - let expr = if isUnitTy cenv.g exprty then mkCompGenSequential mMethExpr expr (mkRefTupled cenv.g mMethExpr outArgExprs outArgTys) - else mkRefTupled cenv.g mMethExpr (expr :: outArgExprs) (exprty :: outArgTys) + let expr = + if isUnitTy cenv.g exprty then + mkCompGenSequential mMethExpr expr (mkRefTupled cenv.g mMethExpr outArgExprs outArgTys) + else + mkRefTupled cenv.g mMethExpr (expr :: outArgExprs) (exprty :: outArgTys) let expr = mkLetsBind mMethExpr outArgTmpBinds expr expr, tyOfExpr cenv.g expr // Handle post-hoc property assignments - let setterExprPrebinders, expr = - if isCheckingAttributeCall then - [], expr - elif isNil finalAssignedItemSetters then - [], expr - else - // This holds the result of the call - let objv, objExpr = mkMutableCompGenLocal mMethExpr "returnVal" exprty // mutable in case it's a struct - // This expression mutates the properties on the result of the call - let setterExprPrebinders, propSetExpr = - (mkUnit cenv.g mMethExpr, finalAssignedItemSetters) ||> List.mapFold (fun acc (AssignedItemSetter(id, setter, CallerArg(callerArgTy, m, isOptCallerArg, argExpr))) -> - if isOptCallerArg then error(Error(FSComp.SR.tcInvalidOptionalAssignmentToPropertyOrField(), m)) - - let argExprPrebinder, action, defnItem = - match setter with - | AssignedPropSetter (pinfo, pminfo, pminst) -> - MethInfoChecks cenv.g cenv.amap true None [objExpr] ad m pminfo - let calledArgTy = List.head (List.head (pminfo.GetParamTypes(cenv.amap, m, pminst))) - let argExprPrebinder, argExpr = coerceExpr false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr - let mut = (if isStructTy cenv.g (tyOfExpr cenv.g objExpr) then DefinitelyMutates else PossiblyMutates) - let action = BuildPossiblyConditionalMethodCall cenv env mut m true pminfo NormalValUse pminst [objExpr] [argExpr] |> fst - argExprPrebinder, action, Item.Property (pinfo.PropertyName, [pinfo]) - - | AssignedILFieldSetter finfo -> - // Get or set instance IL field - ILFieldInstanceChecks cenv.g cenv.amap ad m finfo - let calledArgTy = finfo.FieldType (cenv.amap, m) - let argExprPrebinder, argExpr = coerceExpr false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr - let action = BuildILFieldSet cenv.g m objExpr finfo argExpr - argExprPrebinder, action, Item.ILField finfo - - | AssignedRecdFieldSetter rfinfo -> - RecdFieldInstanceChecks cenv.g cenv.amap ad m rfinfo - let calledArgTy = rfinfo.FieldType - CheckRecdFieldMutation m denv rfinfo - let argExprPrebinder, argExpr = coerceExpr false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr - let action = BuildRecdFieldSet cenv.g m objExpr rfinfo argExpr - argExprPrebinder, action, Item.RecdField rfinfo - - // Record the resolution for the Language Service - let item = Item.SetterArg (id, defnItem) - CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, item, emptyTyparInst, ItemOccurence.Use, env.DisplayEnv, ad) - - argExprPrebinder, mkCompGenSequential m acc action) - - // now put them together - let expr = mkCompGenLet mMethExpr objv expr (mkCompGenSequential mMethExpr propSetExpr objExpr) - setterExprPrebinders, expr - - // Build the lambda expression if any - let expr = + let setterExprPrebinders, callExpr3 = + let expr = callExpr2 + if isCheckingAttributeCall then + [], expr + elif isNil finalAssignedItemSetters then + [], expr + else + // This holds the result of the call + let objv, objExpr = mkMutableCompGenLocal mMethExpr "returnVal" exprty // mutable in case it's a struct + + // Build the expression that mutates the properties on the result of the call + let setterExprPrebinders, propSetExpr = + (mkUnit cenv.g mMethExpr, finalAssignedItemSetters) ||> List.mapFold (fun acc assignedItemSetter -> + let argExprPrebinder, action, m = TcSetterArgExpr cenv env denv objExpr ad assignedItemSetter + argExprPrebinder, mkCompGenSequential m acc action) + + // now put them together + let expr = mkCompGenLet mMethExpr objv expr (mkCompGenSequential mMethExpr propSetExpr objExpr) + setterExprPrebinders, expr + + // Build the lambda expression if any, if the method is used as a first-class value + let callExpr4 = + let expr = callExpr3 match lambdaVars with | None -> expr | Some curriedLambdaVars -> @@ -10552,7 +10266,8 @@ and TcMethodApplication | _ -> mkMultiLambda mMethExpr vs (expr, tyOfExpr cenv.g expr) List.foldBack mkLambda curriedLambdaVars expr - let expr, tpenv = + let callExpr5, tpenv = + let expr = callExpr4 match unnamedDelayedCallerArgExprOpt with | Some synArgExpr -> match lambdaVars with @@ -10565,15 +10280,53 @@ and TcMethodApplication expr, tpenv // Apply the PreBinders, if any - let expr = (expr, setterExprPrebinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr) - let expr = (expr, paramArrayPreBinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr) - let expr = (expr, allArgsPreBinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr) + let callExpr6 = + let expr = callExpr5 + let expr = (expr, setterExprPrebinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr) + let expr = (expr, paramArrayPreBinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr) + let expr = (expr, allArgsPreBinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr) - let expr = optArgPreBinder expr - let expr = objArgPreBinder expr + let expr = optArgPreBinder expr + let expr = objArgPreBinder expr + expr - (expr, finalAttributeAssignedNamedItems, delayed), tpenv + (callExpr6, finalAttributeAssignedNamedItems, delayed), tpenv +and TcSetterArgExpr cenv env denv objExpr ad (AssignedItemSetter(id, setter, CallerArg(callerArgTy, m, isOptCallerArg, argExpr))) = + if isOptCallerArg then error(Error(FSComp.SR.tcInvalidOptionalAssignmentToPropertyOrField(), m)) + + let argExprPrebinder, action, defnItem = + match setter with + | AssignedPropSetter (pinfo, pminfo, pminst) -> + MethInfoChecks cenv.g cenv.amap true None [objExpr] ad m pminfo + let calledArgTy = List.head (List.head (pminfo.GetParamTypes(cenv.amap, m, pminst))) + let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr + let mut = (if isStructTy cenv.g (tyOfExpr cenv.g objExpr) then DefinitelyMutates else PossiblyMutates) + let action = BuildPossiblyConditionalMethodCall cenv env mut m true pminfo NormalValUse pminst [objExpr] [argExpr] |> fst + argExprPrebinder, action, Item.Property (pinfo.PropertyName, [pinfo]) + + | AssignedILFieldSetter finfo -> + // Get or set instance IL field + ILFieldInstanceChecks cenv.g cenv.amap ad m finfo + let calledArgTy = finfo.FieldType (cenv.amap, m) + let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr + let action = BuildILFieldSet cenv.g m objExpr finfo argExpr + argExprPrebinder, action, Item.ILField finfo + + | AssignedRecdFieldSetter rfinfo -> + RecdFieldInstanceChecks cenv.g cenv.amap ad m rfinfo + let calledArgTy = rfinfo.FieldType + CheckRecdFieldMutation m denv rfinfo + let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr + let action = BuildRecdFieldSet cenv.g m objExpr rfinfo argExpr + argExprPrebinder, action, Item.RecdField rfinfo + + // Record the resolution for the Language Service + let item = Item.SetterArg (id, defnItem) + CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, item, emptyTyparInst, ItemOccurence.Use, env.DisplayEnv, ad) + + argExprPrebinder, action, m + and TcUnnamedMethodArgs cenv env lambdaPropagationInfo tpenv args = List.mapiFoldSquared (TcUnnamedMethodArg cenv env) (lambdaPropagationInfo, tpenv) args diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 1d13fca5ebb..11d93f64ebb 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -2138,6 +2138,7 @@ let main4 dynamicAssemblyCreator (Args (ctok, tcConfig, tcImports: TcImports, t embedAllSource = tcConfig.embedAllSource embedSourceList = tcConfig.embedSourceList sourceLink = tcConfig.sourceLink + checksumAlgorithm = tcConfig.checksumAlgorithm signer = GetStrongNameSigner signingInfo dumpDebugInfo = tcConfig.dumpDebugInfo pathMap = tcConfig.pathMap }, diff --git a/src/fsharp/lexhelp.fs b/src/fsharp/lexhelp.fs index e966678486e..fb66ac5f85a 100644 --- a/src/fsharp/lexhelp.fs +++ b/src/fsharp/lexhelp.fs @@ -60,7 +60,8 @@ type lexargs = applyLineDirectives: bool pathMap: PathMap } -/// possible results of lexing a long unicode escape sequence in a string literal, e.g. "\UDEADBEEF" +/// possible results of lexing a long Unicode escape sequence in a string literal, e.g. "\U0001F47D", +/// "\U000000E7", or "\UDEADBEEF" returning SurrogatePair, SingleChar, or Invalid, respectively type LongUnicodeLexResult = | SurrogatePair of uint16 * uint16 | SingleChar of uint16 @@ -169,7 +170,9 @@ let unicodeGraphLong (s:string) = if high = 0 then SingleChar(uint16 low) // invalid encoding elif high > 0x10 then Invalid - // valid surrogate pair - see http://www.unicode.org/unicode/uni2book/ch03.pdf, section 3.7 *) + // valid supplementary character: code points U+10000 to U+10FFFF + // valid surrogate pair: see http://www.unicode.org/versions/latest/ch03.pdf , "Surrogates" section + // high-surrogate code point (U+D800 to U+DBFF) followed by low-surrogate code point (U+DC00 to U+DFFF) else let codepoint = high * 0x10000 + low let hiSurr = uint16 (0xD800 + ((codepoint - 0x10000) / 0x400)) diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs index 4099b59c803..96e81e32147 100755 --- a/src/fsharp/service/IncrementalBuild.fs +++ b/src/fsharp/service/IncrementalBuild.fs @@ -1052,7 +1052,7 @@ type TypeCheckAccumulator = /// Global service state -type FrameworkImportsCacheKey = (*resolvedpath*)string list * string * (*TargetFrameworkDirectories*)string list* (*fsharpBinaries*)string +type FrameworkImportsCacheKey = (*resolvedpath*)string list * string * (*TargetFrameworkDirectories*)string list * (*fsharpBinaries*)string * (*langVersion*)decimal /// Represents a cache of 'framework' references that can be shared betweeen multiple incremental builds type FrameworkImportsCache(keepStrongly) = @@ -1083,12 +1083,13 @@ type FrameworkImportsCache(keepStrongly) = // The data elements in this key are very important. There should be nothing else in the TcConfig that logically affects // the import of a set of framework DLLs into F# CCUs. That is, the F# CCUs that result from a set of DLLs (including // FSharp.Core.dll and mscorlib.dll) must be logically invariant of all the other compiler configuration parameters. - let key = (frameworkDLLsKey, - tcConfig.primaryAssembly.Name, - tcConfig.GetTargetFrameworkDirectories(), - tcConfig.fsharpBinariesDir) + let key = (frameworkDLLsKey, + tcConfig.primaryAssembly.Name, + tcConfig.GetTargetFrameworkDirectories(), + tcConfig.fsharpBinariesDir, + tcConfig.langVersion.SpecifiedVerson) - match frameworkTcImportsCache.TryGet (ctok, key) with + match frameworkTcImportsCache.TryGet (ctok, key) with | Some res -> return res | None -> let tcConfigP = TcConfigProvider.Constant tcConfig diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 7c1b38a4b5f..de68f97439a 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. Není definovaný obor názvů {0}. diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index 33a03002ea8..d81bf821cf7 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. Der Namespace "{0}" ist nicht definiert. diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 07a6a376d6c..72534507d49 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. El espacio de nombres "{0}" no está definido. diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index db443013ccc..454795901dd 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. L'espace de noms '{0}' n'est pas défini. diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 27d3af91a0e..4f4b4d03320 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. Lo spazio dei nomi '{0}' non è definito. diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 47430c5e72b..7e3a8fb8326 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. 名前空間 '{0}' が定義されていません。 diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index 2f3708ed03f..84768df5bfc 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. '{0}' 네임스페이스가 정의되지 않았습니다. diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index 4b92b5b6a51..002003ee57e 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. Nie zdefiniowano przestrzeni nazw „{0}”. diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index d679c9502a5..181f64a8c5c 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. O namespace '{0}' não está definido. diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index 3fc4173787b..71d53bd57c6 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. Пространство имен "{0}" не определено. diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index a04bc7ada54..64935d65b6c 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. '{0}' ad alanı tanımlı değil. diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index 38918ceec9f..a61c36af5c7 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. 未定义命名空间“{0}”。 diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 1a02de7e416..56af5fad549 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -27,6 +27,16 @@ Unexpected symbol '.' in member definition. Expected 'with', '=' or other token. + + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + Specify algorithm for calculating source file checksum stored in PDB. Supported values are: SHA1 or SHA256 (default) + + + + Algorithm '{0}' is not supported + Algorithm '{0}' is not supported + + The namespace '{0}' is not defined. 未定義命名空間 '{0}'。 diff --git a/src/utils/sformat.fs b/src/utils/sformat.fs index 0c8cc5fc2f4..42cb18fa8d0 100644 --- a/src/utils/sformat.fs +++ b/src/utils/sformat.fs @@ -718,18 +718,14 @@ namespace Microsoft.FSharp.Text.StructuredPrintfImpl // pprinter: attributes // -------------------------------------------------------------------- - let makeRecordVerticalL nameXs = - let itemL (name,xL) = let labelL = wordL name in ((labelL ^^ wordL Literals.equals)) -- (xL ^^ (rightL Literals.semicolon)) - let braceL xs = (leftL Literals.leftBrace) ^^ xs ^^ (rightL Literals.rightBrace) - braceL (aboveListL (List.map itemL nameXs)) - - // This is a more compact rendering of records - and is more like tuples - let makeRecordHorizontalL nameXs = - let itemL (name,xL) = let labelL = wordL name in ((labelL ^^ wordL Literals.equals)) -- xL - let braceL xs = (leftL Literals.leftBrace) ^^ xs ^^ (rightL Literals.rightBrace) - braceL (sepListL (rightL Literals.semicolon) (List.map itemL nameXs)) - - let makeRecordL nameXs = makeRecordVerticalL nameXs + let makeRecordL nameXs = + let itemL (name,xL) = wordL name ^^ wordL Literals.equals -- xL + let braceL xs = (wordL Literals.leftBrace) ^^ xs ^^ (wordL Literals.rightBrace) + + nameXs + |> List.map itemL + |> aboveListL + |> braceL let makePropertiesL nameXs = let itemL (name,v) = diff --git a/tests/EndToEndBuildTests/ProvidedTypes/ProvidedTypes.fs b/tests/EndToEndBuildTests/ProvidedTypes/ProvidedTypes.fs index e7a924bcfaa..be1521a56ac 100644 --- a/tests/EndToEndBuildTests/ProvidedTypes/ProvidedTypes.fs +++ b/tests/EndToEndBuildTests/ProvidedTypes/ProvidedTypes.fs @@ -12495,7 +12495,7 @@ namespace ProviderImplementation.ProvidedTypes let pdbOpt = match portablePDB with | true -> - let (uncompressedLength, contentId, stream) as pdbStream = generatePortablePdb embedAllSource embedSourceList sourceLink showTimes pdbData deterministic + let (uncompressedLength, contentId, stream) as pdbStream = generatePortablePdb embedAllSource embedSourceList sourceLink showTimes pdbData if embeddedPDB then Some (compressPortablePdbStream uncompressedLength contentId stream) else Some (pdbStream) | _ -> None diff --git a/tests/fsharp/.gitignore b/tests/fsharp/.gitignore index 0493c881790..ea4771517da 100644 --- a/tests/fsharp/.gitignore +++ b/tests/fsharp/.gitignore @@ -13,4 +13,5 @@ Library1.dll cd.tmp - +*.err +*.vserr diff --git a/tests/fsharp/Compiler/CompilerAssert.fs b/tests/fsharp/Compiler/CompilerAssert.fs index 332ad59b8ae..89bc15f5f2f 100644 --- a/tests/fsharp/Compiler/CompilerAssert.fs +++ b/tests/fsharp/Compiler/CompilerAssert.fs @@ -32,6 +32,76 @@ module CompilerAssert = let checker = FSharpChecker.Create() let private config = TestFramework.initializeSuite () + +// Do a one time dotnet sdk build to compute the proper set of reference assemblies to pass to the compiler +#if !NETCOREAPP +#else + let projectFile = """ + + + + Exe + netcoreapp2.1 + + + + + + + + +""" + + let programFs = """ +open System + +[] +let main argv = 0""" + + let getNetCoreAppReferences = + let mutable output = "" + let mutable errors = "" + let mutable cleanUp = true + let projectDirectory = Path.Combine(Path.GetTempPath(), "netcoreapp2.1", Path.GetRandomFileName()) + try + try + Directory.CreateDirectory(projectDirectory) |> ignore + let projectFileName = Path.Combine(projectDirectory, "ProjectFile.fsproj") + let programFsFileName = Path.Combine(projectDirectory, "Program.fs") + let frameworkReferencesFileName = Path.Combine(projectDirectory, "FrameworkReferences.txt") + + File.WriteAllText(projectFileName, projectFile) + File.WriteAllText(programFsFileName, programFs) + + let pInfo = ProcessStartInfo () + + pInfo.FileName <- config.DotNetExe + pInfo.Arguments <- "build" + pInfo.WorkingDirectory <- projectDirectory + pInfo.RedirectStandardOutput <- true + pInfo.RedirectStandardError <- true + pInfo.UseShellExecute <- false + + let p = Process.Start(pInfo) + p.WaitForExit() + + output <- p.StandardOutput.ReadToEnd () + errors <- p.StandardError.ReadToEnd () + if not (String.IsNullOrWhiteSpace errors) then Assert.Fail errors + + if p.ExitCode <> 0 then Assert.Fail(sprintf "Program exited with exit code %d" p.ExitCode) + + File.ReadLines(frameworkReferencesFileName) |> Seq.toArray + with | e -> + cleanUp <- false + printfn "%s" output + printfn "%s" errors + raise (new Exception (sprintf "An error occured getting netcoreapp references: %A" e)) + finally + if cleanUp then + try Directory.Delete(projectDirectory) with | _ -> () +#endif + let private defaultProjectOptions = { ProjectFileName = "Z:\\test.fsproj" @@ -41,14 +111,7 @@ module CompilerAssert = OtherOptions = [|"--preferreduilang:en-US";|] #else OtherOptions = - // Hack: Currently a hack to get the runtime assemblies for netcore in order to compile. - let assemblies = - typeof.Assembly.Location - |> Path.GetDirectoryName - |> Directory.EnumerateFiles - |> Seq.toArray - |> Array.filter (fun x -> x.ToLowerInvariant().Contains("system.") || x.ToLowerInvariant().EndsWith("netstandard.dll")) - |> Array.map (fun x -> sprintf "-r:%s" x) + let assemblies = getNetCoreAppReferences |> Array.map (fun x -> sprintf "-r:%s" x) Array.append [|"--preferreduilang:en-US"; "--targetprofile:netcore"; "--noframework"|] assemblies #endif ReferencedProjects = [||] @@ -60,6 +123,7 @@ module CompilerAssert = ExtraProjectInfo = None Stamp = None } + let private gate = obj () let private compile isExe source f = @@ -109,10 +173,15 @@ module CompilerAssert = Assert.IsEmpty(typeCheckResults.Errors, sprintf "Type Check errors: %A" typeCheckResults.Errors) - - let TypeCheckSingleError (source: string) (expectedErrorNumber: int) (expectedErrorRange: int * int * int * int) (expectedErrorMsg: string) = + let TypeCheckWithErrorsAndOptions options (source: string) expectedTypeErrors = lock gate <| fun () -> - let parseResults, fileAnswer = checker.ParseAndCheckFileInProject("test.fs", 0, SourceText.ofString source, defaultProjectOptions) |> Async.RunSynchronously + let parseResults, fileAnswer = + checker.ParseAndCheckFileInProject( + "test.fs", + 0, + SourceText.ofString source, + { defaultProjectOptions with OtherOptions = Array.append options defaultProjectOptions.OtherOptions}) + |> Async.RunSynchronously Assert.IsEmpty(parseResults.Errors, sprintf "Parse errors: %A" parseResults.Errors) @@ -120,17 +189,32 @@ module CompilerAssert = | FSharpCheckFileAnswer.Aborted _ -> Assert.Fail("Type Checker Aborted") | FSharpCheckFileAnswer.Succeeded(typeCheckResults) -> - Assert.AreEqual(1, typeCheckResults.Errors.Length, sprintf "Expected one type check error: %A" typeCheckResults.Errors) - typeCheckResults.Errors - |> Array.iter (fun info -> - Assert.AreEqual(FSharpErrorSeverity.Error, info.Severity) + let errors = + typeCheckResults.Errors + |> Array.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) + + Assert.AreEqual(Array.length expectedTypeErrors, errors.Length, sprintf "Type check errors: %A" typeCheckResults.Errors) + + Array.zip errors expectedTypeErrors + |> Array.iter (fun (info, expectedError) -> + let (expectedServerity: FSharpErrorSeverity, expectedErrorNumber: int, expectedErrorRange: int * int * int * int, expectedErrorMsg: string) = expectedError + Assert.AreEqual(expectedServerity, info.Severity) Assert.AreEqual(expectedErrorNumber, info.ErrorNumber, "expectedErrorNumber") - Assert.AreEqual(expectedErrorRange, (info.StartLineAlternate, info.StartColumn, info.EndLineAlternate, info.EndColumn), "expectedErrorRange") + Assert.AreEqual(expectedErrorRange, (info.StartLineAlternate, info.StartColumn + 1, info.EndLineAlternate, info.EndColumn + 1), "expectedErrorRange") Assert.AreEqual(expectedErrorMsg, info.Message, "expectedErrorMsg") ) + let TypeCheckWithErrors (source: string) expectedTypeErrors = + TypeCheckWithErrorsAndOptions [||] source expectedTypeErrors + + let TypeCheckSingleErrorWithOptions options (source: string) (expectedServerity: FSharpErrorSeverity) (expectedErrorNumber: int) (expectedErrorRange: int * int * int * int) (expectedErrorMsg: string) = + TypeCheckWithErrorsAndOptions options source [| expectedServerity, expectedErrorNumber, expectedErrorRange, expectedErrorMsg |] + + let TypeCheckSingleError (source: string) (expectedServerity: FSharpErrorSeverity) (expectedErrorNumber: int) (expectedErrorRange: int * int * int * int) (expectedErrorMsg: string) = + TypeCheckWithErrors source [| expectedServerity, expectedErrorNumber, expectedErrorRange, expectedErrorMsg |] + let CompileExe (source: string) = - compile true source (fun (errors, _) -> + compile true source (fun (errors, _) -> if errors.Length > 0 then Assert.Fail (sprintf "Compile had warnings and/or errors: %A" errors)) @@ -157,6 +241,9 @@ module CompilerAssert = let errors = p.StandardError.ReadToEnd () if not (String.IsNullOrWhiteSpace errors) then Assert.Fail errors + + if p.ExitCode <> 0 then + Assert.Fail(sprintf "Program exited with exit code %d" p.ExitCode) ) let CompileLibraryAndVerifyIL (source: string) (f: ILVerifier -> unit) = @@ -202,3 +289,25 @@ module CompilerAssert = ||> Seq.iter2 (fun expectedErrorMessage errorMessage -> Assert.AreEqual(expectedErrorMessage, errorMessage) ) + + let ParseWithErrors (source: string) expectedParseErrors = + let sourceFileName = "test.fs" + let parsingOptions = { FSharpParsingOptions.Default with SourceFiles = [| sourceFileName |] } + let parseResults = checker.ParseFile(sourceFileName, SourceText.ofString source, parsingOptions) |> Async.RunSynchronously + + Assert.True(parseResults.ParseHadErrors) + + let errors = + parseResults.Errors + |> Array.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) + + Assert.AreEqual(Array.length expectedParseErrors, errors.Length, sprintf "Type check errors: %A" parseResults.Errors) + + Array.zip errors expectedParseErrors + |> Array.iter (fun (info, expectedError) -> + let (expectedServerity: FSharpErrorSeverity, expectedErrorNumber: int, expectedErrorRange: int * int * int * int, expectedErrorMsg: string) = expectedError + Assert.AreEqual(expectedServerity, info.Severity) + Assert.AreEqual(expectedErrorNumber, info.ErrorNumber, "expectedErrorNumber") + Assert.AreEqual(expectedErrorRange, (info.StartLineAlternate, info.StartColumn + 1, info.EndLineAlternate, info.EndColumn + 1), "expectedErrorRange") + Assert.AreEqual(expectedErrorMsg, info.Message, "expectedErrorMsg") + ) diff --git a/tests/fsharp/Compiler/Conformance/BasicGrammarElements/BasicConstants.fs b/tests/fsharp/Compiler/Conformance/BasicGrammarElements/BasicConstants.fs new file mode 100644 index 00000000000..9bae4946568 --- /dev/null +++ b/tests/fsharp/Compiler/Conformance/BasicGrammarElements/BasicConstants.fs @@ -0,0 +1,177 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Basic Grammar Element Constants`` = + + [] + let `` Basic constants compile `` () = + CompilerAssert.Pass + """ +let sbyteConst = 1y +let int16Const = 1us +let int32Const = 1ul +let int64Const = 1UL + +let byteConst = 1uy +let uint16Const = 1us +let uint32Const = 1ul +let uint64Const = 1uL + +let ieee32Const1 = 1.0f +let ieee32Const2 = 1.0F +let ieee32Const3 = 0x0000000000000001lf + +let ieee64Const1 = 1.0 +let ieee64Const2 = 0x0000000000000001LF + +let bigintConst = 1I + +// let bignumConst = 1N - you need a reference to PowerPack.dll now + +let decimalConst1 = 1.0M +let decimalConst2 = 1.0m + +let charConst = '1' + +let stringConst = "1" + +let bytestringConst = "1"B + +let bytecharConst = '1'B + +let boolConst1 = true +let boolConst2 = false + +let unitConst = () + """ + + [] + let ``Long with underscores``() = + CompilerAssert.CompileExeAndRun + """ +let creditCardNumber = 1234_5678_9012_3456L +let socialSecurityNumber = 999_99_9999L + +if socialSecurityNumber <> 999999999L then failwith "Wrong parsing" +if creditCardNumber <> 1234567890123456L then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``float 32 with underscores``() = + CompilerAssert.CompileExeAndRun + """ +let pi = 3.14_15F +if pi <> 3.1415F then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with underscores hexBytes``() = + CompilerAssert.CompileExeAndRun + """ +let hexBytes = 0xFF_EC_DE_5E +if hexBytes <> 0xFFECDE5E then failwith "Wrong parsing" +exit 0 + """ + + + [] + let ``int with underscore hexWords``() = + CompilerAssert.CompileExeAndRun + """ +let hexWords = 0xCAFE_BABE +if hexWords <> 0xCAFEBABE then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``Long with underscores maxLong``() = + CompilerAssert.CompileExeAndRun + """ +let maxLong = 0x7fff_ffff_ffff_ffffL +if maxLong <> 0x7fffffffffffffffL then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with underscore nybbles``() = + CompilerAssert.CompileExeAndRun + """ +let nybbles = 0b0010_0101 +if nybbles <> 0b00100101 then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with underscores bytes``() = + CompilerAssert.CompileExeAndRun + """ +let bytes = 0b11010010_01101001_10010100_10010010 +if bytes <> 0b11010010011010011001010010010010 then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with single underscore literal``() = + CompilerAssert.CompileExeAndRun + """ +let x2 = 5_2 +if x2 <> 52 then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with multiple underscores literal``() = + CompilerAssert.CompileExeAndRun + """ +let x4 = 5_______2 +if x4 <> 52 then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with single underscore Hex literal``() = + CompilerAssert.CompileExeAndRun + """ +let x7 = 0x5_2 +if x7 <> 0x52 then + failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with single underscore after leading zero literal``() = + CompilerAssert.CompileExeAndRun + """ +let x9 = 0_52 +if x9 <> 052 then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with single underscore after leteral with leading zero ``() = + CompilerAssert.CompileExeAndRun + """ +let x10 = 05_2 +if x10 <> 052 then failwith "Wrong parsing" +exit 0 + """ + + [] + let ``int with single underscore after octo leteral ``() = + CompilerAssert.CompileExeAndRun + """ +let x14 = 0o5_2 +if x14 <> 0o52 then failwith "Wrong parsing" +exit 0 + """ + + + + diff --git a/tests/fsharp/Compiler/ConstraintSolver/MemberConstraints.fs b/tests/fsharp/Compiler/ConstraintSolver/MemberConstraints.fs new file mode 100644 index 00000000000..d422c9b31fd --- /dev/null +++ b/tests/fsharp/Compiler/ConstraintSolver/MemberConstraints.fs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module MemberConstraints = + + [] + let ``we can overload operators on a type and not add all the extra jazz such as inlining and the ^ operator.``() = + CompilerAssert.CompileExeAndRun + """ +type Foo(x : int) = + member this.Val = x + + static member (-->) ((src : Foo), (target : Foo)) = new Foo(src.Val + target.Val) + static member (-->) ((src : Foo), (target : int)) = new Foo(src.Val + target) + + static member (+) ((src : Foo), (target : Foo)) = new Foo(src.Val + target.Val) + static member (+) ((src : Foo), (target : int)) = new Foo(src.Val + target) + +let x = Foo(3) --> 4 +let y = Foo(3) --> Foo(4) +let x2 = Foo(3) + 4 +let y2 = Foo(3) + Foo(4) + +if x.Val <> 7 then exit 1 +if y.Val <> 7 then exit 1 +if x2.Val <> 7 then exit 1 +if y2.Val <> 7 then exit 1 + """ + + [] + let ``Invalid member constraint with ErrorRanges``() = // Regression test for FSharp1.0:2262 + CompilerAssert.TypeCheckSingleErrorWithOptions + [| "--test:ErrorRanges" |] + """ +let inline length (x: ^a) : int = (^a : (member Length : int with get, set) (x, ())) + """ + FSharpErrorSeverity.Error + 697 + (2, 42, 2, 75) + "Invalid constraint" diff --git a/tests/fsharp/Compiler/ConstraintSolver/PrimitiveConstraints.fs b/tests/fsharp/Compiler/ConstraintSolver/PrimitiveConstraints.fs new file mode 100644 index 00000000000..fbfedfb550d --- /dev/null +++ b/tests/fsharp/Compiler/ConstraintSolver/PrimitiveConstraints.fs @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module PrimitiveConstraints = + + [] + let ``Test primitive : constraints``() = + CompilerAssert.CompileExeAndRun + """ +#light + +type Foo(x : int) = + member this.Value = x + override this.ToString() = "Foo" + +type Bar(x : int) = + inherit Foo(-1) + member this.Value2 = x + override this.ToString() = "Bar" + +let test1 (x : Foo) = x.Value +let test2 (x : Bar) = (x.Value, x.Value2) + +let f = new Foo(128) +let b = new Bar(256) + +if test1 f <> 128 then exit 1 +if test2 b <> (-1, 256) then exit 1 +""" + + [] + let ``Test primitive :> constraints``() = + CompilerAssert.CompileExeAndRun + """ +#light +type Foo(x : int) = + member this.Value = x + override this.ToString() = "Foo" + +type Bar(x : int) = + inherit Foo(-1) + member this.Value2 = x + override this.ToString() = "Bar" + +type Ram(x : int) = + inherit Foo(10) + member this.ValueA = x + override this.ToString() = "Ram" + +let test (x : Foo) = (x.Value, x.ToString()) + +let f = new Foo(128) +let b = new Bar(256) +let r = new Ram(314) + +if test f <> (128, "Foo") then exit 1 +if test b <> (-1, "Bar") then exit 1 +if test r <> (10, "Ram") then exit 1 +""" + + [] + let ``Test primitive : null constraint``() = + CompilerAssert.CompileExeAndRun + """ +let inline isNull<'a when 'a : null> (x : 'a) = + match x with + | null -> "is null" + | _ -> (x :> obj).ToString() + +let runTest = + // Wrapping in try block to work around FSB 1989 + try + if isNull null <> "is null" then exit 1 + if isNull "F#" <> "F#" then exit 1 + true + with _ -> exit 1 + +if runTest <> true then exit 1 + +exit 0 +""" + + [] + /// Title: Type checking oddity + /// + /// This suggestion was resolved as by design, + /// so the test makes sure, we're emitting error message about 'not being a valid object construction expression' + let ``Invalid object constructor``() = // Regression test for FSharp1.0:4189 + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--test:ErrorRanges" |] + """ +type ImmutableStack<'a> private(items: 'a list) = + + member this.Push item = ImmutableStack(item::items) + member this.Pop = match items with | [] -> failwith "No elements in stack" | x::xs -> x,ImmutableStack(xs) + + // Notice type annotation is commented out, which results in an error + new(col (*: seq<'a>*)) = ImmutableStack(List.ofSeq col) + + """ + [| FSharpErrorSeverity.Error, 41, (4, 29, 4, 56), "A unique overload for method 'ImmutableStack`1' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates: new : col:'b -> ImmutableStack<'a>, private new : items:'a list -> ImmutableStack<'a>" + FSharpErrorSeverity.Error, 41, (5, 93, 5, 111), "A unique overload for method 'ImmutableStack`1' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates: new : col:'b -> ImmutableStack<'a>, private new : items:'a list -> ImmutableStack<'a>" + FSharpErrorSeverity.Error, 41, (8, 30, 8, 60), "A unique overload for method 'ImmutableStack`1' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates: new : col:'b -> ImmutableStack<'a> when 'b :> seq<'c>, private new : items:'a list -> ImmutableStack<'a>" + FSharpErrorSeverity.Error, 696, (8, 30, 8, 60), "This is not a valid object construction expression. Explicit object constructors must either call an alternate constructor or initialize all fields of the object and specify a call to a super class constructor." |] \ No newline at end of file diff --git a/tests/fsharp/Compiler/ErrorMessages/AccessOfTypeAbbreviationTests.fs b/tests/fsharp/Compiler/ErrorMessages/AccessOfTypeAbbreviationTests.fs new file mode 100644 index 00000000000..0143486a349 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/AccessOfTypeAbbreviationTests.fs @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Access Of Type Abbreviation`` = + + [] + let ``Test1``() = + CompilerAssert.TypeCheckSingleError + """ +module Library = + type private Hidden = Hidden of unit + type Exported = Hidden + """ + FSharpErrorSeverity.Warning + 44 + (4, 8, 4, 16) + "This construct is deprecated. The type 'Hidden' is less accessible than the value, member or type 'Exported' it is used in.\r\nAs of F# 4.1, the accessibility of type abbreviations is checked at compile-time. Consider changing the accessibility of the type abbreviation. Ignoring this warning might lead to runtime errors." + + [] + let ``Test2``() = + CompilerAssert.Pass + """ +module Library = + type internal Hidden = Hidden of unit + type internal Exported = Hidden + """ + + [] + let ``Test3``() = + CompilerAssert.TypeCheckSingleError + """ +module Library = + type internal Hidden = Hidden of unit + type Exported = Hidden + """ + FSharpErrorSeverity.Warning + 44 + (4, 8, 4, 16) + "This construct is deprecated. The type 'Hidden' is less accessible than the value, member or type 'Exported' it is used in.\r\nAs of F# 4.1, the accessibility of type abbreviations is checked at compile-time. Consider changing the accessibility of the type abbreviation. Ignoring this warning might lead to runtime errors." + + [] + let ``Test4``() = + CompilerAssert.TypeCheckSingleError + """ +module Library = + type private Hidden = Hidden of unit + type internal Exported = Hidden + """ + FSharpErrorSeverity.Warning + 44 + (4, 17, 4, 25) + "This construct is deprecated. The type 'Hidden' is less accessible than the value, member or type 'Exported' it is used in.\r\nAs of F# 4.1, the accessibility of type abbreviations is checked at compile-time. Consider changing the accessibility of the type abbreviation. Ignoring this warning might lead to runtime errors." + + [] + let ``Test5``() = + CompilerAssert.Pass + """ +module Library = + type private Hidden = Hidden of unit + type private Exported = Hidden + """ + + [] + let ``Test6``() = + CompilerAssert.Pass + """ +module Library = + type Hidden = Hidden of unit + type Exported = Hidden + """ \ No newline at end of file diff --git a/tests/fsharp/Compiler/ErrorMessages/AssignmentErrorTests.fs b/tests/fsharp/Compiler/ErrorMessages/AssignmentErrorTests.fs new file mode 100644 index 00000000000..51b75dd87d7 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/AssignmentErrorTests.fs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Errors assigning to mutable objects`` = + + [] + let ``Assign to immutable error``() = + CompilerAssert.TypeCheckSingleError + """ +let x = 10 +x <- 20 + +exit 0 + """ + FSharpErrorSeverity.Error + 27 + (3, 1, 3, 8) + "This value is not mutable. Consider using the mutable keyword, e.g. 'let mutable x = expression'." \ No newline at end of file diff --git a/tests/fsharp/Compiler/ErrorMessages/ClassesTests.fs b/tests/fsharp/Compiler/ErrorMessages/ClassesTests.fs new file mode 100644 index 00000000000..1ce10cb7080 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/ClassesTests.fs @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Classes`` = + + [] + let ``Tuple In Abstract Method``() = + CompilerAssert.TypeCheckWithErrors + """ +type IInterface = + abstract Function : (int32 * int32) -> unit + +let x = + { new IInterface with + member this.Function (i, j) = () + } + """ + [| + FSharpErrorSeverity.Error, 768, (7, 16, 7, 36), "The member 'Function' does not accept the correct number of arguments. 1 argument(s) are expected, but 2 were given. The required signature is 'member IInterface.Function : (int32 * int32) -> unit'.\nA tuple type is required for one or more arguments. Consider wrapping the given arguments in additional parentheses or review the definition of the interface." + FSharpErrorSeverity.Error, 17, (7, 21, 7, 29), "The member 'Function : 'a * 'b -> unit' does not have the correct type to override the corresponding abstract method. The required signature is 'Function : (int32 * int32) -> unit'." + FSharpErrorSeverity.Error, 783, (6, 9, 6, 19), "At least one override did not correctly implement its corresponding abstract member" + |] + + [] + let ``Wrong Arity``() = + CompilerAssert.TypeCheckSingleError + """ +type MyType() = + static member MyMember(arg1, arg2:int ) = () + static member MyMember(arg1, arg2:byte) = () + + +MyType.MyMember("", 0, 0) + """ + FSharpErrorSeverity.Error + 503 + (7, 1, 7, 26) + "A member or object constructor 'MyMember' taking 3 arguments is not accessible from this code location. All accessible versions of method 'MyMember' take 2 arguments." + + [] + let ``Method Is Not Static``() = + CompilerAssert.TypeCheckSingleError + """ +type Class1() = + member this.X() = "F#" + +let x = Class1.X() + """ + FSharpErrorSeverity.Error + 3214 + (5, 9, 5, 17) + "Method or object constructor 'X' is not static" + + [] + let ``Matching Method With Same Name Is Not Abstract``() = + CompilerAssert.TypeCheckWithErrors + """ +type Foo(x : int) = + member v.MyX() = x + +let foo = + { new Foo(3) + with + member v.MyX() = 4 } + """ + [| + FSharpErrorSeverity.Error, 767, (8, 16, 8, 23), "The type Foo contains the member 'MyX' but it is not a virtual or abstract method that is available to override or implement." + FSharpErrorSeverity.Error, 17, (8, 18, 8, 21), "The member 'MyX : unit -> int' does not have the correct type to override any given virtual method" + FSharpErrorSeverity.Error, 783, (6, 11, 6, 14), "At least one override did not correctly implement its corresponding abstract member" + |] + + [] + let ``No Matching Abstract Method With Same Name``() = + CompilerAssert.TypeCheckWithErrors + """ +type IInterface = + abstract MyFunction : int32 * int32 -> unit + abstract SomeOtherFunction : int32 * int32 -> unit + +let x = + { new IInterface with + member this.Function (i, j) = () + } + """ + [| + FSharpErrorSeverity.Error, 767, (8, 14, 8, 34), "The member 'Function' does not correspond to any abstract or virtual method available to override or implement." + FSharpErrorSeverity.Error, 17, (8, 19, 8, 27), "The member 'Function : 'a * 'b -> unit' does not have the correct type to override any given virtual method" + FSharpErrorSeverity.Error, 366, (7, 3, 9, 4), "No implementation was given for those members: \r\n\t'abstract member IInterface.MyFunction : int32 * int32 -> unit'\r\n\t'abstract member IInterface.SomeOtherFunction : int32 * int32 -> unit'\r\nNote that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'." + FSharpErrorSeverity.Error, 783, (7, 9, 7, 19), "At least one override did not correctly implement its corresponding abstract member" + |] + + [] + let ``Member Has Multiple Possible Dispatch Slots``() = + CompilerAssert.TypeCheckWithErrors + """ +type IOverload = + abstract member Bar : int -> int + abstract member Bar : double -> int + +type Overload = + interface IOverload with + override __.Bar _ = 1 + """ + [| + FSharpErrorSeverity.Error, 366, (7, 15, 7, 24), "No implementation was given for those members: \r\n\t'abstract member IOverload.Bar : double -> int'\r\n\t'abstract member IOverload.Bar : int -> int'\r\nNote that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'." + FSharpErrorSeverity.Error, 3213, (8, 21, 8, 24), "The member 'Bar<'a0> : 'a0 -> int' matches multiple overloads of the same method.\nPlease restrict it to one of the following:\r\n Bar : double -> int\r\n Bar : int -> int." + |] + + [] + let ``Do Cannot Have Visibility Declarations``() = + CompilerAssert.ParseWithErrors + """ +type X() = + do () + private do () + static member Y() = 1 + """ + [| + FSharpErrorSeverity.Error, 531, (4, 5, 4, 12), "Accessibility modifiers should come immediately prior to the identifier naming a construct" + FSharpErrorSeverity.Error, 512, (4, 13, 4, 18), "Accessibility modifiers are not permitted on 'do' bindings, but 'Private' was given." + FSharpErrorSeverity.Error, 222, (2, 1, 3, 1), "Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. 'namespace SomeNamespace.SubNamespace' or 'module SomeNamespace.SomeModule'. Only the last source file of an application may omit such a declaration." + |] diff --git a/tests/fsharp/Compiler/ErrorMessages/ConstructorTests.fs b/tests/fsharp/Compiler/ErrorMessages/ConstructorTests.fs new file mode 100644 index 00000000000..97aa66e60a4 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/ConstructorTests.fs @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Constructor`` = + + [] + let ``Invalid Record``() = + CompilerAssert.TypeCheckWithErrors + """ +type Record = {field1:int; field2:int} +let doSomething (xs) = List.map (fun {field1=x} -> x) xs + +doSomething {Record.field1=0; field2=0} + """ + [| + FSharpErrorSeverity.Error, 1, (5, 13, 5, 40), "This expression was expected to have type\n 'Record list' \nbut here has type\n 'Record' " + FSharpErrorSeverity.Warning, 20, (5, 1, 5, 40), "The result of this expression has type 'int list' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'." + |] + + [] + let ``Comma In Rec Ctor``() = + CompilerAssert.TypeCheckWithErrors + """ +type Person = { Name : string; Age : int; City : string } +let x = { Name = "Isaac", Age = 21, City = "London" } + """ + [| + FSharpErrorSeverity.Error, 1, (3, 18, 3, 52), "This expression was expected to have type\n 'string' \nbut here has type\n ''a * 'b * 'c' \r\nA ';' is used to separate field values in records. Consider replacing ',' with ';'." + FSharpErrorSeverity.Error, 764, (3, 9, 3, 54), "No assignment given for field 'Age' of type 'Test.Person'" + |] + + [] + let ``Missing Comma In Ctor``() = + CompilerAssert.TypeCheckWithErrors + """ +type Person() = + member val Name = "" with get,set + member val Age = 0 with get,set + +let p = + Person(Name = "Fred" + Age = 18) + """ + [| + FSharpErrorSeverity.Error, 39, (7, 12, 7, 16), "The value or constructor 'Name' is not defined." + FSharpErrorSeverity.Warning, 20, (7, 12, 7, 25), "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'." + FSharpErrorSeverity.Error, 39, (8, 12, 8, 15), "The value or constructor 'Age' is not defined." + FSharpErrorSeverity.Error, 501, (7, 5, 8, 21), "The object constructor 'Person' takes 0 argument(s) but is here given 1. The required signature is 'new : unit -> Person'. If some of the arguments are meant to assign values to properties, consider separating those arguments with a comma (',')." + |] + + [] + let ``Missing Ctor Value``() = + CompilerAssert.TypeCheckSingleError + """ +type Person(x:int) = + member val Name = "" with get,set + member val Age = x with get,set + +let p = + Person(Name = "Fred", + Age = 18) + """ + FSharpErrorSeverity.Error + 496 + (7, 5, 8, 21) + "The member or object constructor 'Person' requires 1 argument(s). The required signature is 'new : x:int -> Person'." + + [] + let ``Extra Argument In Ctor``() = + CompilerAssert.TypeCheckSingleError + """ +type Person() = + member val Name = "" with get,set + member val Age = 0 with get,set + +let p = + Person(1) + """ + FSharpErrorSeverity.Error + 501 + (7, 5, 7, 14) + "The object constructor 'Person' takes 0 argument(s) but is here given 1. The required signature is 'new : unit -> Person'." + + [] + let ``Extra Argument In Ctor2``() = + CompilerAssert.TypeCheckSingleError + """ +type Person() = + member val Name = "" with get,set + member val Age = 0 with get,set + +let b = 1 + +let p = + Person(1=b) + """ + FSharpErrorSeverity.Error + 501 + (9, 5, 9, 16) + "The object constructor 'Person' takes 0 argument(s) but is here given 1. The required signature is 'new : unit -> Person'." + + [] + let ``Valid Comma In Rec Ctor``() = + CompilerAssert.Pass + """ +type Person = { Name : string * bool * bool } +let Age = 22 +let City = "London" +let x = { Name = "Isaac", Age = 21, City = "London" } + """ diff --git a/tests/fsharp/Compiler/ErrorMessages/DontSuggestTests.fs b/tests/fsharp/Compiler/ErrorMessages/DontSuggestTests.fs new file mode 100644 index 00000000000..0e5a4f19557 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/DontSuggestTests.fs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Don't Suggest`` = + + [] + let ``Dont Suggest Completely Wrong Stuff``() = + CompilerAssert.TypeCheckSingleError + """ +let _ = Path.GetFullPath "images" + """ + FSharpErrorSeverity.Error + 39 + (2, 9, 2, 13) + "The value, namespace, type or module 'Path' is not defined." + + [] + let ``Dont Suggest When Things Are Open``() = + CompilerAssert.ParseWithErrors + """ +module N = + let name = "hallo" + +type T = + static member myMember = 1 + +let x = N. + """ + [| + FSharpErrorSeverity.Error, 599, (8, 10, 8, 11), "Missing qualification after '.'" + FSharpErrorSeverity.Error, 222, (2, 1, 3, 1), "Files in libraries or multiple-file applications must begin with a namespace or module declaration. When using a module declaration at the start of a file the '=' sign is not allowed. If this is a top-level module, consider removing the = to resolve this error." + |] + + [] + let ``Dont Suggest Intentionally Unused Variables``() = + CompilerAssert.TypeCheckSingleError + """ +let hober xy _xyz = xyz + """ + FSharpErrorSeverity.Error + 39 + (2, 21, 2, 24) + "The value or constructor 'xyz' is not defined." diff --git a/tests/fsharp/Compiler/ErrorMessages/ElseBranchHasWrongTypeTests.fs b/tests/fsharp/Compiler/ErrorMessages/ElseBranchHasWrongTypeTests.fs new file mode 100644 index 00000000000..21c7bb29269 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/ElseBranchHasWrongTypeTests.fs @@ -0,0 +1,176 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Else branch has wrong type`` = + + [] + let ``Else branch is int while if branch is string``() = + CompilerAssert.TypeCheckSingleError + """ +let test = 100 +let y = + if test > 10 then "test" + else 123 + """ + FSharpErrorSeverity.Error + 1 + (5, 10, 5, 13) + "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'." + + [] + let ``Else branch is a function that returns int while if branch is string``() = + CompilerAssert.TypeCheckSingleError + """ +let test = 100 +let f x = test +let y = + if test > 10 then "test" + else f 10 + """ + FSharpErrorSeverity.Error + 1 + (6, 10, 6, 14) + "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'." + + + [] + let ``Else branch is a sequence of expressions that returns int while if branch is string``() = + CompilerAssert.TypeCheckSingleError + """ +let f x = x + 4 + +let y = + if true then + "" + else + "" |> ignore + (f 5) + """ + FSharpErrorSeverity.Error + 1 + (9, 10, 9, 13) + "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'." + + + [] + let ``Else branch is a longer sequence of expressions that returns int while if branch is string``() = + CompilerAssert.TypeCheckSingleError + """ +let f x = x + 4 + +let y = + if true then + "" + else + "" |> ignore + let z = f 4 + let a = 3 * z + (f a) + """ + FSharpErrorSeverity.Error + 1 + (11, 10, 11, 13) + "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'." + + + [] + let ``Else branch context doesn't propagate into function application``() = + CompilerAssert.TypeCheckSingleError + """ +let test = 100 +let f x : string = x +let y = + if test > 10 then "test" + else + f 123 + """ + FSharpErrorSeverity.Error + 1 + (7, 11, 7, 14) + "This expression was expected to have type\n 'string' \nbut here has type\n 'int' " + + [] + let ``Else branch context doesn't propagate into function application even if not last expr``() = + CompilerAssert.TypeCheckSingleError + """ +let test = 100 +let f x = printfn "%s" x +let y = + if test > 10 then "test" + else + f 123 + "test" + """ + FSharpErrorSeverity.Error + 1 + (7, 11, 7, 14) + "This expression was expected to have type\n 'string' \nbut here has type\n 'int' " + + [] + let ``Else branch context doesn't propagate into for loop``() = + CompilerAssert.TypeCheckSingleError + """ +let test = 100 +let list = [1..10] +let y = + if test > 10 then "test" + else + for (x:string) in list do + printfn "%s" x + + "test" + """ + FSharpErrorSeverity.Error + 1 + (7, 14, 7, 22) + "This expression was expected to have type\n 'int' \nbut here has type\n 'string' " + + [] + let ``Else branch context doesn't propagate to lines before last line``() = + CompilerAssert.TypeCheckSingleError + """ +let test = 100 +let list = [1..10] +let y = + if test > 10 then "test" + else + printfn "%s" 1 + + "test" + """ + FSharpErrorSeverity.Error + 1 + (7, 22, 7, 23) + "This expression was expected to have type\n 'string' \nbut here has type\n 'int' " + + [] + let ``Else branch should not have wrong context type``() = + CompilerAssert.TypeCheckWithErrors + """ +let x = 1 +let y : bool = + if x = 2 then "A" + else "B" + """ + [| FSharpErrorSeverity.Error, 1, (4, 19, 4, 22), "The 'if' expression needs to have type 'bool' to satisfy context type requirements. It currently has type 'string'." + FSharpErrorSeverity.Error, 1, (5, 10, 5, 13), "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'bool'. This branch returns a value of type 'string'." |] + + + [] + let ``Else branch has wrong type in nested if``() = + CompilerAssert.TypeCheckWithErrors + """ +let x = 1 +if x = 1 then true +else + if x = 2 then "A" + else "B" + """ + [| FSharpErrorSeverity.Error, 1, (5, 19, 5, 22), "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'bool'. This branch returns a value of type 'string'." + FSharpErrorSeverity.Error, 1, (6, 10, 6, 13), "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'bool'. This branch returns a value of type 'string'." + FSharpErrorSeverity.Warning, 20, (3, 1, 6, 13), "The result of this expression has type 'bool' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'." |] diff --git a/tests/fsharp/Compiler/ErrorMessages/MissingElseBranch.fs b/tests/fsharp/Compiler/ErrorMessages/MissingElseBranch.fs new file mode 100644 index 00000000000..06f9cb160d9 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/MissingElseBranch.fs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Else branch is missing`` = + + [] + let ``Fail if else branch is missing``() = + CompilerAssert.TypeCheckSingleError + """ +let x = 10 +let y = + if x > 10 then "test" + """ + FSharpErrorSeverity.Error + 1 + (4, 19, 4, 25) + "This 'if' expression is missing an 'else' branch. Because 'if' is an expression, and not a statement, add an 'else' branch which also returns a value of type 'string'." + + [] + let ``Fail on type error in condition``() = + CompilerAssert.TypeCheckSingleError + """ +let x = 10 +let y = + if x > 10 then + if x <> "test" then printfn "test" + () + """ + FSharpErrorSeverity.Error + 1 + (5, 14, 5, 20) + "This expression was expected to have type\n 'int' \nbut here has type\n 'string' " + + [] + let ``Fail if else branch is missing in nesting``() = + CompilerAssert.TypeCheckSingleError + """ +let x = 10 +let y = + if x > 10 then ("test") + """ + FSharpErrorSeverity.Error + 1 + (4, 20, 4, 26) + "This 'if' expression is missing an 'else' branch. Because 'if' is an expression, and not a statement, add an 'else' branch which also returns a value of type 'string'." diff --git a/tests/fsharp/Compiler/ErrorMessages/NameResolutionTests.fs b/tests/fsharp/Compiler/ErrorMessages/NameResolutionTests.fs new file mode 100644 index 00000000000..70def908d11 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/NameResolutionTests.fs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module NameResolutionTests = + + [] + let FieldNotInRecord () = + CompilerAssert.TypeCheckSingleError + """ +type A = { Hello:string; World:string } +type B = { Size:int; Height:int } +type C = { Wheels:int } +type D = { Size:int; Height:int; Walls:int } +type E = { Unknown:string } +type F = { Wallis:int; Size:int; Height:int; } + +let r:F = { Size=3; Height=4; Wall=1 } + """ + FSharpErrorSeverity.Error + 1129 + (9, 31, 9, 35) + "The record type 'F' does not contain a label 'Wall'." + + [] + let RecordFieldProposal () = + CompilerAssert.TypeCheckSingleError + """ +type A = { Hello:string; World:string } +type B = { Size:int; Height:int } +type C = { Wheels:int } +type D = { Size:int; Height:int; Walls:int } +type E = { Unknown:string } +type F = { Wallis:int; Size:int; Height:int; } + +let r = { Size=3; Height=4; Wall=1 } + """ + FSharpErrorSeverity.Error + 39 + (9, 29, 9, 33) + "The record label 'Wall' is not defined." \ No newline at end of file diff --git a/tests/fsharp/Compiler/ErrorMessages/TypeMismatchTests.fs b/tests/fsharp/Compiler/ErrorMessages/TypeMismatchTests.fs new file mode 100644 index 00000000000..652361045c9 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/TypeMismatchTests.fs @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Type Mismatch`` = + + [] + let ``return Instead Of return!``() = + CompilerAssert.TypeCheckSingleError + """ +let rec foo() = async { return foo() } + """ + FSharpErrorSeverity.Error + 1 + (2, 32, 2, 37) + "Type mismatch. Expecting a\n ''a' \nbut given a\n 'Async<'a>' \nThe types ''a' and 'Async<'a>' cannot be unified. Consider using 'return!' instead of 'return'." + + [] + let ``yield Instead Of yield!``() = + CompilerAssert.TypeCheckSingleError + """ +type Foo() = + member this.Yield(x) = [x] + +let rec f () = Foo() { yield f ()} + """ + FSharpErrorSeverity.Error + 1 + (5, 30, 5, 34) + "Type mismatch. Expecting a\n ''a' \nbut given a\n ''a list' \nThe types ''a' and ''a list' cannot be unified. Consider using 'yield!' instead of 'yield'." + + [] + let ``Ref Cell Instead Of Not``() = + CompilerAssert.TypeCheckSingleError + """ +let x = true +if !x then + printfn "hello" + """ + FSharpErrorSeverity.Error + 1 + (3, 5, 3, 6) + "This expression was expected to have type\n 'bool ref' \nbut here has type\n 'bool' \r\nThe '!' operator is used to dereference a ref cell. Consider using 'not expr' here." + + [] + let ``Ref Cell Instead Of Not 2``() = + CompilerAssert.TypeCheckSingleError + """ +let x = true +let y = !x + """ + FSharpErrorSeverity.Error + 1 + (3, 10, 3, 11) + "This expression was expected to have type\n ''a ref' \nbut here has type\n 'bool' \r\nThe '!' operator is used to dereference a ref cell. Consider using 'not expr' here." + + [] + let ``Guard Has Wrong Type``() = + CompilerAssert.TypeCheckWithErrors + """ +let x = 1 +match x with +| 1 when "s" -> true +| _ -> false + """ + [| + FSharpErrorSeverity.Error, 1, (4, 10, 4, 13), "A pattern match guard must be of type 'bool', but this 'when' expression is of type 'string'." + FSharpErrorSeverity.Warning, 20, (3, 1, 5, 13), "The result of this expression has type 'bool' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'." + |] + + [] + let ``Runtime Type Test In Pattern``() = + CompilerAssert.TypeCheckWithErrors + """ +open System.Collections.Generic + +let orig = Dictionary() + +let c = + match orig with + | :? IDictionary -> "yes" + | _ -> "no" + """ + [| + FSharpErrorSeverity.Warning, 67, (8, 5, 8, 28), "This type test or downcast will always hold" + FSharpErrorSeverity.Error, 193, (8, 5, 8, 28), "Type constraint mismatch. The type \n 'IDictionary' \nis not compatible with type\n 'Dictionary' \n" + |] + + [] + let ``Runtime Type Test In Pattern 2``() = + CompilerAssert.TypeCheckWithErrors + """ +open System.Collections.Generic + +let orig = Dictionary() + +let c = + match orig with + | :? IDictionary as y -> "yes" + y.ToString() + | _ -> "no" + """ + [| + FSharpErrorSeverity.Warning, 67, (8, 5, 8, 28), "This type test or downcast will always hold" + FSharpErrorSeverity.Error, 193, (8, 5, 8, 28), "Type constraint mismatch. The type \n 'IDictionary' \nis not compatible with type\n 'Dictionary' \n" + |] + + [] + let ``Override Errors``() = + CompilerAssert.TypeCheckWithErrors + """ +type Base() = + abstract member Member: int * string -> string + default x.Member (i, s) = s + +type Derived1() = + inherit Base() + override x.Member() = 5 + +type Derived2() = + inherit Base() + override x.Member (i : int) = "Hello" + +type Derived3() = + inherit Base() + override x.Member (s : string, i : int) = sprintf "Hello %s" s + """ + [| + FSharpErrorSeverity.Error, 856, (8, 16, 8, 22), "This override takes a different number of arguments to the corresponding abstract member. The following abstract members were found:\r\n abstract member Base.Member : int * string -> string" + FSharpErrorSeverity.Error, 856, (12, 16, 12, 22), "This override takes a different number of arguments to the corresponding abstract member. The following abstract members were found:\r\n abstract member Base.Member : int * string -> string" + FSharpErrorSeverity.Error, 1, (16, 24, 16, 34), "This expression was expected to have type\n 'int' \nbut here has type\n 'string' " + |] diff --git a/tests/fsharp/Compiler/ErrorMessages/UnitGenericAbstactType.fs b/tests/fsharp/Compiler/ErrorMessages/UnitGenericAbstactType.fs new file mode 100644 index 00000000000..e9165a4cf6a --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/UnitGenericAbstactType.fs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Unit generic abstract Type`` = + + [] + let ``Unit can not be used as return type of abstract method paramete on return type``() = + CompilerAssert.TypeCheckSingleError + """ +type EDF<'S> = + abstract member Apply : int -> 'S +type SomeEDF () = + interface EDF with + member this.Apply d = + // [ERROR] The member 'Apply' does not have the correct type to override the corresponding abstract method. + () + """ + FSharpErrorSeverity.Error + 17 + (6, 21, 6, 26) + "The member 'Apply : int -> unit' is specialized with 'unit' but 'unit' can't be used as return type of an abstract method parameterized on return type." + diff --git a/tests/fsharp/Compiler/ErrorMessages/UpcastDowncastTests.fs b/tests/fsharp/Compiler/ErrorMessages/UpcastDowncastTests.fs new file mode 100644 index 00000000000..739f841bfca --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/UpcastDowncastTests.fs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Upcast and Downcast`` = + + [] + let ``Downcast Instead Of Upcast``() = + CompilerAssert.TypeCheckSingleError + """ +open System.Collections.Generic + +let orig = Dictionary() :> IDictionary +let c = orig :> Dictionary + """ + FSharpErrorSeverity.Error + 193 + (5, 9, 5, 36) + "Type constraint mismatch. The type \n 'IDictionary' \nis not compatible with type\n 'Dictionary' \n" + + [] + let ``Upcast Instead Of Downcast``() = + CompilerAssert.TypeCheckWithErrors + """ +open System.Collections.Generic + +let orig = Dictionary() +let c = orig :?> IDictionary + """ + [| + FSharpErrorSeverity.Warning, 67, (5, 9, 5, 38), "This type test or downcast will always hold" + FSharpErrorSeverity.Error, 3198, (5, 9, 5, 38), "The conversion from Dictionary to IDictionary is a compile-time safe upcast, not a downcast. Consider using the :> (upcast) operator instead of the :?> (downcast) operator." + |] + + [] + let ``Upcast Function Instead Of Downcast``() = + CompilerAssert.TypeCheckWithErrors + """ +open System.Collections.Generic + +let orig = Dictionary() +let c : IDictionary = downcast orig + """ + [| + FSharpErrorSeverity.Warning, 67, (5, 32, 5, 45), "This type test or downcast will always hold" + FSharpErrorSeverity.Error, 3198, (5, 32, 5, 45), "The conversion from Dictionary to IDictionary is a compile-time safe upcast, not a downcast. Consider using 'upcast' instead of 'downcast'." + |] diff --git a/tests/fsharp/Compiler/ErrorMessages/WarnExpressionTests.fs b/tests/fsharp/Compiler/ErrorMessages/WarnExpressionTests.fs new file mode 100644 index 00000000000..7bf6cc211c1 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/WarnExpressionTests.fs @@ -0,0 +1,217 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Warn Expression`` = + + [] + let ``Warn If Expression Result Unused``() = + CompilerAssert.TypeCheckSingleError + """ +1 + 2 +printfn "%d" 3 + """ + FSharpErrorSeverity.Warning + 20 + (2, 1, 2, 6) + "The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'." + + [] + let ``Warn If Possible Assignment``() = + CompilerAssert.TypeCheckSingleError + """ +let x = 10 +let y = "hello" + +let changeX() = + x = 20 + y = "test" + """ + FSharpErrorSeverity.Warning + 20 + (6, 5, 6, 11) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to mutate a value, then mark the value 'mutable' and use the '<-' operator e.g. 'x <- expression'." + + [] + let ``Warn If Possible Assignment To Mutable``() = + CompilerAssert.TypeCheckSingleError + """ +let mutable x = 10 +let y = "hello" + +let changeX() = + x = 20 + y = "test" + """ + FSharpErrorSeverity.Warning + 20 + (6, 5, 6, 11) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to mutate a value, then use the '<-' operator e.g. 'x <- expression'." + + [] + let ``Warn If Possible dotnet Property Setter``() = + CompilerAssert.TypeCheckWithErrors + """ +open System + +let z = System.Timers.Timer() +let y = "hello" + +let changeProperty() = + z.Enabled = true + y = "test" + """ + [| + FSharpErrorSeverity.Warning, 760, (4, 9, 4, 30), "It is recommended that objects supporting the IDisposable interface are created using the syntax 'new Type(args)', rather than 'Type(args)' or 'Type' as a function value representing the constructor, to indicate that resources may be owned by the generated value" + FSharpErrorSeverity.Warning, 20, (8, 5, 8, 21), "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to set a value to a property, then use the '<-' operator e.g. 'z.Enabled <- expression'." + |] + + [] + let ``Don't Warn If Property Without Setter``() = + CompilerAssert.TypeCheckSingleError + """ +type MyClass(property1 : int) = + member val Property2 = "" with get + +let x = MyClass(1) +let y = "hello" + +let changeProperty() = + x.Property2 = "22" + y = "test" + """ + FSharpErrorSeverity.Warning + 20 + (9, 5, 9, 23) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'." + + [] + let ``Warn If Implicitly Discarded``() = + CompilerAssert.TypeCheckSingleError + """ +let x = 10 +let y = 20 + +let changeX() = + y * x = 20 + y = 30 + """ + FSharpErrorSeverity.Warning + 20 + (6, 5, 6, 15) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'." + + // [] // Disable this test until we refactor tcImports and tcGlobals + let ``Warn If Discarded In List``() = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + """ +let div _ _ = 1 +let subView _ _ = [1; 2] + +// elmish view +let view model dispatch = + [ + yield! subView model dispatch + div [] [] + ] + """ + [| + FSharpErrorSeverity.Warning, + 3221, + (9, 8, 9, 17), + "This expression returns a value of type 'int' but is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to use the expression as a value in the sequence then use an explicit 'yield'." + |] + + // [] // Disable this test until we refactor tcImports and tcGlobals + let ``Warn If Discarded In List 2``() = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + """ +// stupid things to make the sample compile +let div _ _ = 1 +let subView _ _ = [1; 2] +let y = 1 + +// elmish view +let view model dispatch = + [ + div [] [ + match y with + | 1 -> yield! subView model dispatch + | _ -> subView model dispatch + ] + ] + """ + [| + FSharpErrorSeverity.Warning, + 3222, + (13, 19, 13, 41), + "This expression returns a value of type 'int list' but is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to use the expression as a value in the sequence then use an explicit 'yield!'." + |] + + // [] // Disable this test until we refactor tcImports and tcGlobals + let ``Warn If Discarded In List 3``() = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + """ +// stupid things to make the sample compile +let div _ _ = 1 +let subView _ _ = true +let y = 1 + +// elmish view +let view model dispatch = + [ + div [] [ + match y with + | 1 -> () + | _ -> subView model dispatch + ] + ] + """ + [| + FSharpErrorSeverity.Warning, + 20, + (13, 19, 13, 41), + "The result of this expression has type 'bool' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'." + |] + + [] + let ``Warn Only On Last Expression``() = + CompilerAssert.TypeCheckSingleError + """ +let mutable x = 0 +while x < 1 do + printfn "unneeded" + x <- x + 1 + true + """ + FSharpErrorSeverity.Warning + 20 + (6, 5, 6, 9) + "The result of this expression has type 'bool' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'." + + [] + let ``Warn If Possible Property Setter``() = + CompilerAssert.TypeCheckSingleError + """ +type MyClass(property1 : int) = + member val Property1 = property1 + member val Property2 = "" with get, set + +let x = MyClass(1) +let y = "hello" + +let changeProperty() = + x.Property2 = "20" + y = "test" + """ + FSharpErrorSeverity.Warning + 20 + (10, 5, 10, 23) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to set a value to a property, then use the '<-' operator e.g. 'x.Property2 <- expression'." diff --git a/tests/fsharp/Compiler/Language/AnonRecordTests.fs b/tests/fsharp/Compiler/Language/AnonRecordTests.fs index 7182e359b19..befa39f2bfc 100644 --- a/tests/fsharp/Compiler/Language/AnonRecordTests.fs +++ b/tests/fsharp/Compiler/Language/AnonRecordTests.fs @@ -3,6 +3,7 @@ namespace FSharp.Compiler.UnitTests open NUnit.Framework +open FSharp.Compiler.SourceCodeServices [] module AnonRecordsTests = @@ -30,9 +31,10 @@ let sAnon = StructClass() type RefClass<'a when 'a : not struct>() = class end let rAnon = RefClass() """ + FSharpErrorSeverity.Error 1 - (3, 12, 3, 41) - "A generic construct requires that the type 'struct {|R : int|}' have reference semantics, but it does not, i.e. it is a struct" + (3, 13, 3, 42) + "A generic construct requires that the type 'struct {| R: int |}' have reference semantics, but it does not, i.e. it is a struct" [] let StructConstraintFail() = @@ -40,7 +42,8 @@ let rAnon = RefClass() """ type StructClass<'a when 'a : struct>() = class end let sAnon = StructClass<{| S: int |}>() - """ + """ + FSharpErrorSeverity.Error 1 - (3, 12, 3, 37) - "A generic construct requires that the type '{|S : int|}' is a CLI or F# struct type" \ No newline at end of file + (3, 13, 3, 38) + "A generic construct requires that the type '{| S: int |}' is a CLI or F# struct type" diff --git a/tests/fsharp/Compiler/Language/OpenStaticClasses.fs b/tests/fsharp/Compiler/Language/OpenStaticClasses.fs new file mode 100644 index 00000000000..bd036d3a109 --- /dev/null +++ b/tests/fsharp/Compiler/Language/OpenStaticClasses.fs @@ -0,0 +1,173 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open FSharp.Compiler.SourceCodeServices +open NUnit.Framework + + +(* + Tests in this file evaluate whether the language supports accessing functions on static classes using open + The feature was added in FSharp4.7, the test cases ensure that the original errors are reproduced when the langversion:4.6 is specified +*) + +[] +module OpenStaticClassesTests = + + let baseModule = """ +module Core_OpenStaticClasses + +[] +type MyMath() = + static member Min(a: double, b: double) = System.Math.Min(a, b) + static member Min(a: int, b: int) = System.Math.Min(a, b) + +[] +type AutoOpenMyMath() = + static member AutoMin(a: double, b: double) = System.Math.Min(a, b) + static member AutoMin(a: int, b: int) = System.Math.Min(a, b) + +[] +type NotAllowedToOpen() = + static member QualifiedMin(a: double, b: double) = System.Math.Min(a, b) + static member QualifiedMin(a: int, b: int) = System.Math.Min(a, b) + +""" + + [] + let ``OpenStaticClassesTests - OpenSystemMathOnce - langversion:v4.6`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + (baseModule + """ +module OpenSystemMathOnce = + + open System.Math + let x = Min(1.0, 2.0)""") + [| + (FSharpErrorSeverity.Error, 39, (22,28,22,32), "The namespace 'Math' is not defined."); + (FSharpErrorSeverity.Error, 39, (23,24,23,27), "The value or constructor 'Min' is not defined.") + |] + + [] + let ``OpenStaticClassesTests - OpenSystemMathOnce - langversion:v4.7`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.7" |] + (baseModule + """ +module OpenSystemMathOnce = + + open System.Math + let x = Min(1.0, 2.0)""") + [| |] + + [] + let ``OpenStaticClassesTests - OpenSystemMathTwice - langversion:v4.6`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + (baseModule + """ +module OpenSystemMathTwice = + + open System.Math + let x = Min(1.0, 2.0) + + open System.Math + let x2 = Min(2.0, 1.0)""") + [| + (FSharpErrorSeverity.Error, 39, (22,17,22,21), "The namespace 'Math' is not defined."); + (FSharpErrorSeverity.Error, 39, (23,13,23,16), "The value or constructor 'Min' is not defined.") + (FSharpErrorSeverity.Error, 39, (25,17,25,21), "The namespace 'Math' is not defined."); + (FSharpErrorSeverity.Error, 39, (26,14,26,17), "The value or constructor 'Min' is not defined.") + |] + + [] + let ``OpenStaticClassesTests - OpenSystemMathTwice - langversion:v4.7`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.7" |] + (baseModule + """ +module OpenSystemMathOnce = + + open System.Math + let x = Min(1.0, 2.0)""") + [| |] + + [] + let ``OpenStaticClassesTests - OpenMyMathOnce - langversion:v4.6`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + (baseModule + """ +module OpenMyMathOnce = + + open MyMath + let x = Min(1.0, 2.0) + let x2 = Min(1, 2)""") + [| + (FSharpErrorSeverity.Error, 39, (22,10,22,16), "The namespace or module 'MyMath' is not defined."); + (FSharpErrorSeverity.Error, 39, (23,13,23,16), "The value or constructor 'Min' is not defined.") + (FSharpErrorSeverity.Error, 39, (24,14,24,17), "The value or constructor 'Min' is not defined.") + |] + + [] + let ``OpenStaticClassesTests - OpenMyMathOnce - langversion:v4.7`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.7" |] + (baseModule + """ +module OpenMyMathOnce = + + open MyMath + let x = Min(1.0, 2.0) + let x2 = Min(1, 2)""") + [| |] + + [] + let ``OpenStaticClassesTests - DontOpenAutoMath - langversion:v4.6`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + (baseModule + """ +module DontOpenAutoMath = + + let x = AutoMin(1.0, 2.0) + let x2 = AutoMin(1, 2)""") + [| + (FSharpErrorSeverity.Error, 39, (22,13,22,20), "The value or constructor 'AutoMin' is not defined."); + (FSharpErrorSeverity.Error, 39, (23,14,23,21), "The value or constructor 'AutoMin' is not defined.") + |] + + [] + let ``OpenStaticClassesTests - DontOpenAutoMath - langversion:v4.7`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.7" |] + (baseModule + """ +module DontOpenAutoMath = + + let x = AutoMin(1.0, 2.0) + let x2 = AutoMin(1, 2)""") + [| |] + + [] + let ``OpenStaticClassesTests - OpenAutoMath - langversion:v4.6`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.6" |] + (baseModule + """ +module OpenAutoMath = + open AutoOpenMyMath + //open NotAllowedToOpen + + let x = AutoMin(1.0, 2.0) + let x2 = AutoMin(1, 2)""") + [| + (FSharpErrorSeverity.Error, 39, (21,10,21,24), "The namespace or module 'AutoOpenMyMath' is not defined."); + (FSharpErrorSeverity.Error, 39, (24,13,24,20), "The value or constructor 'AutoMin' is not defined.") + (FSharpErrorSeverity.Error, 39, (25,14,25,21), "The value or constructor 'AutoMin' is not defined.") + |] + + [] + let ``OpenStaticClassesTests - OpenAutoMath - langversion:v4.7`` () = + CompilerAssert.TypeCheckWithErrorsAndOptions + [| "--langversion:4.7" |] + (baseModule + """ +module OpenAutoMath = + open AutoOpenMyMath + //open NotAllowedToOpen + + let x = AutoMin(1.0, 2.0) + let x2 = AutoMin(1, 2)""") + [| |] diff --git a/tests/fsharp/Compiler/Language/SpanOptimizationTests.fs b/tests/fsharp/Compiler/Language/SpanOptimizationTests.fs index efcea68afd3..c5fd682e993 100644 --- a/tests/fsharp/Compiler/Language/SpanOptimizationTests.fs +++ b/tests/fsharp/Compiler/Language/SpanOptimizationTests.fs @@ -27,45 +27,45 @@ let test () = verifier.VerifyIL [ """.method public static void test() cil managed -{ - - .maxstack 5 - .locals init (valuetype [System.Private.CoreLib]System.Span`1 V_0, - int32 V_1, - valuetype [System.Private.CoreLib]System.Int32 V_2, - class [System.Private.CoreLib]System.Object& V_3) - IL_0000: call valuetype [System.Private.CoreLib]System.Span`1 valuetype [System.Private.CoreLib]System.Span`1::get_Empty() - IL_0005: stloc.0 - IL_0006: ldc.i4.0 - IL_0007: stloc.2 - IL_0008: ldloca.s V_0 - IL_000a: call instance int32 valuetype [System.Private.CoreLib]System.Span`1::get_Length() - IL_000f: ldc.i4.1 - IL_0010: sub - IL_0011: stloc.1 - IL_0012: ldloc.1 - IL_0013: ldloc.2 - IL_0014: blt.s IL_0034 - - IL_0016: ldloca.s V_0 - IL_0018: ldloc.2 - IL_0019: call instance !0& valuetype [System.Private.CoreLib]System.Span`1::get_Item(int32) - IL_001e: stloc.3 - IL_001f: ldloc.3 - IL_0020: ldobj [System.Private.CoreLib]System.Object - IL_0025: call void [System.Console]System.Console::WriteLine(object) - IL_002a: ldloc.2 - IL_002b: ldc.i4.1 - IL_002c: add - IL_002d: stloc.2 - IL_002e: ldloc.2 - IL_002f: ldloc.1 - IL_0030: ldc.i4.1 - IL_0031: add - IL_0032: bne.un.s IL_0016 - - IL_0034: ret -} """ + { + + .maxstack 5 + .locals init (valuetype [System.Runtime]System.Span`1 V_0, + int32 V_1, + int32 V_2, + object& V_3) + IL_0000: call valuetype [System.Runtime]System.Span`1 valuetype [System.Runtime]System.Span`1::get_Empty() + IL_0005: stloc.0 + IL_0006: ldc.i4.0 + IL_0007: stloc.2 + IL_0008: ldloca.s V_0 + IL_000a: call instance int32 valuetype [System.Runtime]System.Span`1::get_Length() + IL_000f: ldc.i4.1 + IL_0010: sub + IL_0011: stloc.1 + IL_0012: ldloc.1 + IL_0013: ldloc.2 + IL_0014: blt.s IL_0034 + + IL_0016: ldloca.s V_0 + IL_0018: ldloc.2 + IL_0019: call instance !0& valuetype [System.Runtime]System.Span`1::get_Item(int32) + IL_001e: stloc.3 + IL_001f: ldloc.3 + IL_0020: ldobj [System.Runtime]System.Object + IL_0025: call void [System.Console]System.Console::WriteLine(object) + IL_002a: ldloc.2 + IL_002b: ldc.i4.1 + IL_002c: add + IL_002d: stloc.2 + IL_002e: ldloc.2 + IL_002f: ldloc.1 + IL_0030: ldc.i4.1 + IL_0031: add + IL_0032: bne.un.s IL_0016 + + IL_0034: ret + }""" ]) [] @@ -88,18 +88,18 @@ let test () = [ """.method public static void test() cil managed { - + .maxstack 5 - .locals init (valuetype [System.Private.CoreLib]System.ReadOnlySpan`1 V_0, + .locals init (valuetype [System.Runtime]System.ReadOnlySpan`1 V_0, int32 V_1, - valuetype [System.Private.CoreLib]System.Int32 V_2, - class [System.Private.CoreLib]System.Object& V_3) - IL_0000: call valuetype [System.Private.CoreLib]System.ReadOnlySpan`1 valuetype [System.Private.CoreLib]System.ReadOnlySpan`1::get_Empty() + int32 V_2, + object& V_3) + IL_0000: call valuetype [System.Runtime]System.ReadOnlySpan`1 valuetype [System.Runtime]System.ReadOnlySpan`1::get_Empty() IL_0005: stloc.0 IL_0006: ldc.i4.0 IL_0007: stloc.2 IL_0008: ldloca.s V_0 - IL_000a: call instance int32 valuetype [System.Private.CoreLib]System.ReadOnlySpan`1::get_Length() + IL_000a: call instance int32 valuetype [System.Runtime]System.ReadOnlySpan`1::get_Length() IL_000f: ldc.i4.1 IL_0010: sub IL_0011: stloc.1 @@ -109,10 +109,10 @@ let test () = IL_0016: ldloca.s V_0 IL_0018: ldloc.2 - IL_0019: call instance !0& modreq([System.Private.CoreLib]System.Runtime.InteropServices.InAttribute) valuetype [System.Private.CoreLib]System.ReadOnlySpan`1::get_Item(int32) + IL_0019: call instance !0& modreq([System.Runtime]System.Runtime.InteropServices.InAttribute) valuetype [System.Runtime]System.ReadOnlySpan`1::get_Item(int32) IL_001e: stloc.3 IL_001f: ldloc.3 - IL_0020: ldobj [System.Private.CoreLib]System.Object + IL_0020: ldobj [System.Runtime]System.Object IL_0025: call void [System.Console]System.Console::WriteLine(object) IL_002a: ldloc.2 IL_002b: ldc.i4.1 @@ -176,29 +176,29 @@ module Test = [ """.method public static void test() cil managed { - + .maxstack 3 - .locals init (valuetype System.Span`1 V_0, - class [System.Private.CoreLib]System.Collections.IEnumerator V_1, + .locals init (valuetype System.Span`1 V_0, + class [System.Runtime]System.Collections.IEnumerator V_1, class [FSharp.Core]Microsoft.FSharp.Core.Unit V_2, - class [System.Private.CoreLib]System.IDisposable V_3) + class [System.Runtime]System.IDisposable V_3) IL_0000: ldc.i4.0 - IL_0001: newarr [System.Private.CoreLib]System.Object - IL_0006: newobj instance void valuetype System.Span`1::.ctor(!0[]) + IL_0001: newarr [System.Runtime]System.Object + IL_0006: newobj instance void valuetype System.Span`1::.ctor(!0[]) IL_000b: stloc.0 IL_000c: ldloc.0 - IL_000d: box valuetype System.Span`1 - IL_0012: unbox.any [System.Private.CoreLib]System.Collections.IEnumerable - IL_0017: callvirt instance class [System.Private.CoreLib]System.Collections.IEnumerator [System.Private.CoreLib]System.Collections.IEnumerable::GetEnumerator() + IL_000d: box valuetype System.Span`1 + IL_0012: unbox.any [System.Runtime]System.Collections.IEnumerable + IL_0017: callvirt instance class [System.Runtime]System.Collections.IEnumerator [System.Runtime]System.Collections.IEnumerable::GetEnumerator() IL_001c: stloc.1 .try { IL_001d: ldloc.1 - IL_001e: callvirt instance bool [System.Private.CoreLib]System.Collections.IEnumerator::MoveNext() + IL_001e: callvirt instance bool [System.Runtime]System.Collections.IEnumerator::MoveNext() IL_0023: brfalse.s IL_0032 IL_0025: ldloc.1 - IL_0026: callvirt instance object [System.Private.CoreLib]System.Collections.IEnumerator::get_Current() + IL_0026: callvirt instance object [System.Runtime]System.Collections.IEnumerator::get_Current() IL_002b: call void [System.Console]System.Console::WriteLine(object) IL_0030: br.s IL_001d @@ -206,24 +206,24 @@ module Test = IL_0033: stloc.2 IL_0034: leave.s IL_004c - } + } finally { IL_0036: ldloc.1 - IL_0037: isinst [System.Private.CoreLib]System.IDisposable + IL_0037: isinst [System.Runtime]System.IDisposable IL_003c: stloc.3 IL_003d: ldloc.3 IL_003e: brfalse.s IL_0049 IL_0040: ldloc.3 - IL_0041: callvirt instance void [System.Private.CoreLib]System.IDisposable::Dispose() + IL_0041: callvirt instance void [System.Runtime]System.IDisposable::Dispose() IL_0046: ldnull IL_0047: pop IL_0048: endfinally IL_0049: ldnull IL_004a: pop IL_004b: endfinally - } + } IL_004c: ldloc.2 IL_004d: pop IL_004e: ret diff --git a/tests/fsharp/Compiler/Warnings/AssignmentWarningTests.fs b/tests/fsharp/Compiler/Warnings/AssignmentWarningTests.fs new file mode 100644 index 00000000000..2a0d15d8f8b --- /dev/null +++ b/tests/fsharp/Compiler/Warnings/AssignmentWarningTests.fs @@ -0,0 +1,108 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework +open FSharp.Compiler.SourceCodeServices + +[] +module ``Warnings assigning to mutable and immutable objects`` = + + [] + let ``Unused compare with immutable when assignment might be intended``() = + CompilerAssert.TypeCheckSingleError + """ +let x = 10 +let y = "hello" + +let changeX() = + x = 20 + y = "test" + +exit 0 + """ + FSharpErrorSeverity.Warning + 20 + (6, 5, 6, 11) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to mutate a value, then mark the value 'mutable' and use the '<-' operator e.g. 'x <- expression'." + + [] + let ``Unused compare with mutable when assignment might be intended``() = + CompilerAssert.TypeCheckSingleError + """ +let mutable x = 10 +let y = "hello" + +let changeX() = + x = 20 + y = "test" + +exit 0 + """ + FSharpErrorSeverity.Warning + 20 + (6, 5, 6, 11) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to mutate a value, then use the '<-' operator e.g. 'x <- expression'." + + [] + let ``Unused comparison of property in dotnet object when assignment might be intended``() = + CompilerAssert.TypeCheckSingleError + """ +open System + +let z = new System.Timers.Timer() +let y = "hello" + +let changeProperty() = + z.Enabled = true + y = "test" + +exit 0 + """ + FSharpErrorSeverity.Warning + 20 + (8, 5, 8, 21) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to set a value to a property, then use the '<-' operator e.g. 'z.Enabled <- expression'." + + [] + let ``Unused comparison of property when assignment might be intended ``() = + CompilerAssert.TypeCheckSingleError + """ +type MyClass(property1 : int) = + member val Property1 = property1 + member val Property2 = "" with get, set + +let x = MyClass(1) +let y = "hello" + +let changeProperty() = + x.Property2 = "20" + y = "test" + +exit 0 + """ + FSharpErrorSeverity.Warning + 20 + (10, 5, 10, 23) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to set a value to a property, then use the '<-' operator e.g. 'x.Property2 <- expression'." + + [] + let ``Don't warn if assignment to property without setter ``() = + CompilerAssert.TypeCheckSingleError + """ +type MyClass(property1 : int) = + member val Property2 = "" with get + +let x = MyClass(1) +let y = "hello" + +let changeProperty() = + x.Property2 = "22" + y = "test" + +exit 0 + """ + FSharpErrorSeverity.Warning + 20 + (9, 5, 9, 23) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'." \ No newline at end of file diff --git a/tests/fsharp/FSharpSuite.Tests.fsproj b/tests/fsharp/FSharpSuite.Tests.fsproj index 363fd286548..b7f4184af40 100644 --- a/tests/fsharp/FSharpSuite.Tests.fsproj +++ b/tests/fsharp/FSharpSuite.Tests.fsproj @@ -33,8 +33,24 @@ + + + + + + + + + + + + + + + + diff --git a/tests/fsharp/Libraries/Async/AsyncTests.fs b/tests/fsharp/Libraries/Async/AsyncTests.fs new file mode 100644 index 00000000000..04a82a97160 --- /dev/null +++ b/tests/fsharp/Libraries/Async/AsyncTests.fs @@ -0,0 +1,168 @@ +namespace FSharp.Libraries.UnitTests + +open System +open NUnit.Framework +open FSharp.Compiler.UnitTests + +[] +module AsyncTests = + // Regression for FSHARP1.0:5969 + // Async.StartChild: error when wait async is executed more than once + [] + let ``Execute Async multiple times``() = + CompilerAssert.CompileExeAndRun + """ +module M + +let a = async { + let! a = Async.StartChild( + async { + do! Async.Sleep(1) + return 27 + }) + let! result = Async.Parallel [ a; a; a; a ] + return result + } |> Async.RunSynchronously + +exit 0 + """ + + + // Regression for FSHARP1.0:5970 + // Async.StartChild: race in implementation of ResultCell in FSharp.Core + [] + let ``Joining StartChild``() = + CompilerAssert.CompileExeAndRun + """ +module M + +let Join (a1: Async<'a>) (a2: Async<'b>) = async { + let! task1 = a1 |> Async.StartChild + let! task2 = a2 |> Async.StartChild + + let! res1 = task1 + let! res2 = task2 + return (res1,res2) } + +let r = + try + Async.RunSynchronously (Join (async { do! Async.Sleep(30) + failwith "fail" + return 3+3 }) + (async { do! Async.Sleep(30) + return 2 + 2 } )) + with _ -> + (0,0) + +exit 0 + + """ + + // Regression test for FSHARP1.0:6086 + [] + let ``Mailbox Async dot not StackOverflow``() = + CompilerAssert.CompileExeAndRun + """ +open Microsoft.FSharp.Control + +type Color = Blue | Red | Yellow +let complement = function + | (Red, Yellow) | (Yellow, Red) -> Blue + | (Red, Blue) | (Blue, Red) -> Yellow + | (Yellow, Blue) | (Blue, Yellow) -> Red + | (Blue, Blue) -> Blue + | (Red, Red) -> Red + | (Yellow, Yellow) -> Yellow + +type Message = Color * AsyncReplyChannel + +let chameleon (meetingPlace : MailboxProcessor) initial = + let rec loop c meets = async { + let replyMessage = meetingPlace.PostAndReply(fun reply -> c, reply) + match replyMessage with + | Some(newColor) -> return! loop newColor (meets + 1) + | None -> return meets + } + loop initial 0 + +let meetingPlace chams n = MailboxProcessor.Start(fun (processor : MailboxProcessor)-> + let rec fadingLoop total = + async { + if total <> 0 then + let! (_, reply) = processor.Receive() + reply.Reply None + return! fadingLoop (total - 1) + else + printfn "Done" + } + let rec mainLoop curr = + async { + if (curr > 0) then + let! (color1, reply1) = processor.Receive() + let! (color2, reply2) = processor.Receive() + let newColor = complement (color1, color2) + reply1.Reply <| Some(newColor) + reply2.Reply <| Some(newColor) + return! mainLoop (curr - 1) + else + return! fadingLoop chams + } + mainLoop n + ) + +open System +open System.Diagnostics + +let meetings = 100000 + +let colors = [Blue; Red; Yellow; Blue] +let mp = meetingPlace (colors.Length) meetings +let watch = Stopwatch.StartNew() +let meets = + colors + |> List.map (chameleon mp) + |> Async.Parallel + |> Async.RunSynchronously +watch.Stop() +for meet in meets do + printfn "%d" meet +printfn "Total: %d in %O" (Seq.sum meets) (watch.Elapsed) + +exit 0 + """ + + // Regression for FSHARP1.0:5971 + [] + let ``StartChild do not throw ObjectDisposedException``() = + CompilerAssert.CompileExeAndRun + """ +module M + +let b = async {return 5} |> Async.StartChild +printfn "%A" (b |> Async.RunSynchronously |> Async.RunSynchronously) + +exit 0 + """ + + + [] + let ``StartChild test Trampoline HijackLimit``() = + CompilerAssert.CompileExeAndRun + """ +module M + +let r = + async { + let! a = Async.StartChild( + async { + do! Async.Sleep(1) + return 5 + } + ) + let! _ = a + for __ in 1..10000 do // 10000 > bindHijackLimit + () + } |> Async.RunSynchronously + +exit 0 + """ diff --git a/tests/fsharp/core/anon/lib.fs b/tests/fsharp/core/anon/lib.fs index 9fc219e1cb1..cc3f7de7043 100644 --- a/tests/fsharp/core/anon/lib.fs +++ b/tests/fsharp/core/anon/lib.fs @@ -52,8 +52,8 @@ module KindB1 = check "coijoiwcnkwle1" {| a = 1 |} {| a = 1 |} check "coijoiwcnkwle2" {| a = 2 |} {| a = 2 |} - check "coijoiwcnkwle3" (sprintf "%A" {| X = 10 |}) "{X = 10;}" - check "coijoiwcnkwle4" (sprintf "%A" {| X = 10; Y = 1 |} |> fun s -> s.Replace("\n","").Replace("\r","")) ("{X = 10; Y = 1;}".Replace("\n","").Replace("\r","")) + check "coijoiwcnkwle3" (sprintf "%A" {| X = 10 |}) "{ X = 10 }" + check "coijoiwcnkwle4" (sprintf "%A" {| X = 10; Y = 1 |}) "{ X = 10\n Y = 1 }" check "clekoiew09" (f2 {| X = {| X = 10 |} |}) 10 check "cewkew0oijew" (f2 {| X = {| X = 20 |} |}) 20 diff --git a/tests/fsharp/core/anon/test.fsx b/tests/fsharp/core/anon/test.fsx index 092a8977143..580772b3446 100644 --- a/tests/fsharp/core/anon/test.fsx +++ b/tests/fsharp/core/anon/test.fsx @@ -25,13 +25,13 @@ module Test = let testAccess = (KindB1.data1.X, KindB1.data3.X) - check "coijoiwcnkwle2" (sprintf "%A" KindB1.data1) "{X = 1;}" + check "coijoiwcnkwle2" (sprintf "%A" KindB1.data1) "{ X = 1 }" module Tests2 = let testAccess = (KindB2.data1.X, KindB2.data3.X, KindB2.data3.Y) - check "coijoiwcnkwle3" (sprintf "%A" KindB2.data1) "{X = 1;}" + check "coijoiwcnkwle3" (sprintf "%A" KindB2.data1) "{ X = 1 }" let _ = (KindB2.data1 = KindB2.data1) @@ -49,7 +49,7 @@ module CrossAssemblyTest = check "vrknvio1" (SampleAPI.SampleFunction {| A=1; B = "abc" |}) 4 // note, this is creating an instance of an anonymous record from another assembly. check "vrknvio2" (SampleAPI.SampleFunctionAcceptingList [ {| A=1; B = "abc" |}; {| A=2; B = "def" |} ]) [4; 5] // note, this is creating an instance of an anonymous record from another assembly. check "vrknvio3" (let d = SampleAPI.SampleFunctionReturningAnonRecd() in d.A + d.B.Length) 4 - check "vrknvio4" (let d = SampleAPIStruct.SampleFunctionReturningAnonRecd() in d.ToString().Replace("\n","").Replace("\r","")) """{A = 1; B = "abc";}""" + check "vrknvio4" (let d = SampleAPIStruct.SampleFunctionReturningAnonRecd() in d.ToString()) ("{ A = 1\n " + """B = "abc" }""") tests() module CrossAssemblyTestStruct = diff --git a/tests/fsharp/core/fsfromfsviacs/lib3.cs b/tests/fsharp/core/fsfromfsviacs/lib3.cs index b688b710bc2..91a3dffe4bb 100644 --- a/tests/fsharp/core/fsfromfsviacs/lib3.cs +++ b/tests/fsharp/core/fsfromfsviacs/lib3.cs @@ -24,3 +24,29 @@ public static void SomeMethod() { } } } +namespace CSharpOptionalParameters +{ + // This should be preferred over the same type in lib2.cs + public class SomeClass + { + public SomeClass() { } + public static int MethodTakingOptionals(int x = 3, string y = "abc", double d = 5.0) + { + return x + y.Length + (int) d; + } + public static int MethodTakingNullableOptionalsWithDefaults(int? x = 3, string y = "abc", double? d = 5.0) + { + return (x.HasValue ? x.Value : -100) + y.Length + (int) (d.HasValue ? d.Value : 0.0); + } + public static int MethodTakingNullableOptionals(int? x = null, string y = null, double? d = null) + { + int length; + if (y == null) + length = -1; + else + length = y.Length; + return (x.HasValue ? x.Value : -1) + length + (int) (d.HasValue ? d.Value : -1.0); + } + } + +} diff --git a/tests/fsharp/core/fsfromfsviacs/test.fsx b/tests/fsharp/core/fsfromfsviacs/test.fsx index 76ec203112f..072a896c1eb 100644 --- a/tests/fsharp/core/fsfromfsviacs/test.fsx +++ b/tests/fsharp/core/fsfromfsviacs/test.fsx @@ -71,22 +71,53 @@ let _ = test "structunion394b36" (Lib.NestedStructUnionsTests.testPattern3mut(u2 // F# option implicit converter tests -let testFsOpt() = - let testOpt (t : 'T option) = - test (sprintf "fsimplicitconv (%A)" t) (ApiWrapper.ConsumeOptionalParam<'T>(t) = t) - - testOpt(Option.None) - testOpt(Some 42) - - // check that implicit conversion of optionals does - // differentiate between 'null' and 'Some null' - testOpt(Option.None) - testOpt(Option.Some null) - testOpt(Some "") - testOpt(Some "test") - -testFsOpt() - +module TestConsumeOptionalParameter = + let testFsOpt() = + let testOpt (t : 'T option) = + test (sprintf "fsimplicitconv (%A)" t) (ApiWrapper.ConsumeOptionalParam<'T>(t) = t) + + testOpt(Option.None) + testOpt(Some 42) + + // check that implicit conversion of optionals does + // differentiate between 'null' and 'Some null' + testOpt(Option.None) + testOpt(Option.Some null) + testOpt(Some "") + testOpt(Some "test") + + testFsOpt() + +module TestConsumeCSharpOptionalParameter = + open System + open CSharpOptionalParameters + check "csoptional23982f31" (SomeClass.MethodTakingOptionals()) 11 + check "csoptional23982f32" (SomeClass.MethodTakingOptionals(x = 6)) 14 + check "csoptional23982f33" (SomeClass.MethodTakingOptionals(y = "aaaaaa")) 14 + check "csoptional23982f34" (SomeClass.MethodTakingOptionals(d = 8.0)) 14 + + check "csoptional23982f41" (SomeClass.MethodTakingNullableOptionalsWithDefaults()) 11 + check "csoptional23982f42" (SomeClass.MethodTakingNullableOptionalsWithDefaults(x = Nullable 6)) 14 + check "csoptional23982f43" (SomeClass.MethodTakingNullableOptionalsWithDefaults(y = "aaaaaa")) 14 + check "csoptional23982f44" (SomeClass.MethodTakingNullableOptionalsWithDefaults(d = Nullable 8.0)) 14 + + check "csoptional23982f51" (SomeClass.MethodTakingNullableOptionals()) -3 + check "csoptional23982f52" (SomeClass.MethodTakingNullableOptionals(x = Nullable 6)) 4 + check "csoptional23982f53" (SomeClass.MethodTakingNullableOptionals(y = "aaaaaa")) 4 + check "csoptional23982f54" (SomeClass.MethodTakingNullableOptionals(d = Nullable 8.0)) 6 + + // These require https://github.com/fsharp/fslang-suggestions/issues/774 to be implemented + //check "csoptional23982f3no" (SomeClass.SomeMethod(?x = Some 6)) 14 + //check "csoptional23982f3no" (SomeClass.SomeMethod(?y = Some "aaaaaa")) 14 + //check "csoptional23982f3no" (SomeClass.SomeMethod(?d = Some 8.0)) 14 + //check "csoptional23982f3no" (SomeClass.SomeMethod(?x = None)) 11 + //check "csoptional23982f3no" (SomeClass.SomeMethod(?y = None)) 11 + //check "csoptional23982f3no" (SomeClass.SomeMethod(?d = None)) 11 + + //check "csoptional23982f42" (SomeClass.MethodTakingNullableOptionalsWithDefaults(x = 6)) 14 + //check "csoptional23982f44" (SomeClass.MethodTakingNullableOptionalsWithDefaults(d = 8.0)) 14 + //check "csoptional23982f52" (SomeClass.MethodTakingNullableOptionals(x = 6)) 4 + //check "csoptional23982f54" (SomeClass.MethodTakingNullableOptionals(d = 8.0)) 6 module NestedStructPatternMatchingAcrossAssemblyBoundaries = open Lib.NestedStructUnionsTests diff --git a/tests/fsharp/core/longnames/version46/test.bsl b/tests/fsharp/core/longnames/version46/test.bsl deleted file mode 100644 index 70f110197bb..00000000000 --- a/tests/fsharp/core/longnames/version46/test.bsl +++ /dev/null @@ -1,39 +0,0 @@ - -test.fs(34,17,34,21): typecheck error FS0039: The namespace 'Math' is not defined. - -test.fs(35,13,35,16): typecheck error FS0039: The value or constructor 'Min' is not defined. Maybe you want one of the following: - min - sin - -test.fs(41,17,41,21): typecheck error FS0039: The namespace 'Math' is not defined. - -test.fs(42,13,42,16): typecheck error FS0039: The value or constructor 'Min' is not defined. Maybe you want one of the following: - min - sin - -test.fs(44,17,44,21): typecheck error FS0039: The namespace 'Math' is not defined. - -test.fs(45,14,45,17): typecheck error FS0039: The value or constructor 'Min' is not defined. Maybe you want one of the following: - min - sin - -test.fs(51,10,51,16): typecheck error FS0039: The namespace or module 'MyMath' is not defined. Maybe you want one of the following: - Math - -test.fs(52,13,52,16): typecheck error FS0039: The value or constructor 'Min' is not defined. Maybe you want one of the following: - min - sin - -test.fs(53,14,53,17): typecheck error FS0039: The value or constructor 'Min' is not defined. Maybe you want one of the following: - min - sin - -test.fs(60,13,60,20): typecheck error FS0039: The value or constructor 'AutoMin' is not defined. - -test.fs(61,14,61,21): typecheck error FS0039: The value or constructor 'AutoMin' is not defined. - -test.fs(67,10,67,24): typecheck error FS0039: The namespace or module 'AutoOpenMyMath' is not defined. - -test.fs(70,13,70,20): typecheck error FS0039: The value or constructor 'AutoMin' is not defined. - -test.fs(71,14,71,21): typecheck error FS0039: The value or constructor 'AutoMin' is not defined. diff --git a/tests/fsharp/core/longnames/version46/test.fs b/tests/fsharp/core/longnames/version46/test.fs deleted file mode 100644 index 8c41fdc81f0..00000000000 --- a/tests/fsharp/core/longnames/version46/test.fs +++ /dev/null @@ -1,84 +0,0 @@ -module Core_longnames -let failures = ref [] - -let report_failure (s : string) = - stderr.Write" NO: " - stderr.WriteLine s - failures := !failures @ [s] - -let test (s : string) b = - stderr.Write(s) - if b then stderr.WriteLine " OK" - else report_failure (s) - -let check s b1 b2 = test s (b1 = b2) - -(* Some test expressions *) -[] -type MyMath() = - static member Min(a: double, b: double) = System.Math.Min(a, b) - static member Min(a: int, b: int) = System.Math.Min(a, b) - -[] -type AutoOpenMyMath() = - static member AutoMin(a: double, b: double) = System.Math.Min(a, b) - static member AutoMin(a: int, b: int) = System.Math.Min(a, b) - -[] -type NotAllowedToOpen() = - static member QualifiedMin(a: double, b: double) = System.Math.Min(a, b) - static member QualifiedMin(a: int, b: int) = System.Math.Min(a, b) - -module OpenSystemMathOnce = - - open System.Math - let x = Min(1.0, 2.0) - test "vwejhweoiu" (x = 1.0) - - -module OpenSystemMathTwice = - - open System.Math - let x = Min(1.0, 2.0) - - open System.Math - let x2 = Min(2.0, 1.0) - - test "vwejhweoiu2" (x2 = 1.0) - -module OpenMyMathOnce = - - open MyMath - let x = Min(1.0, 2.0) - let x2 = Min(1, 2) - - test "vwejhweoiu2" (x = 1.0) - test "vwejhweoiu3" (x2 = 1) - -module DontOpenAutoMath = - - let x = AutoMin(1.0, 2.0) - let x2 = AutoMin(1, 2) - - test "vwejhweoiu2" (x = 1.0) - test "vwejhweoiu3" (x2 = 1) - -module OpenAutoMath = - open AutoOpenMyMath - //open NotAllowedToOpen - - let x = AutoMin(1.0, 2.0) - let x2 = AutoMin(1, 2) - - test "vwejhweoiu2" (x = 1.0) - test "vwejhweoiu3" (x2 = 1) - -let RUN() = - match !failures with - | [] -> - stdout.WriteLine "Test Passed" - System.IO.File.WriteAllText("test.ok","ok") - exit 0 - | _ -> - stdout.WriteLine "Test Failed" - exit 1 diff --git a/tests/fsharp/core/longnames/version47/test.fsx b/tests/fsharp/core/longnames/version47/test.fsx deleted file mode 100644 index 03702cb996b..00000000000 --- a/tests/fsharp/core/longnames/version47/test.fsx +++ /dev/null @@ -1,91 +0,0 @@ -// #Conformance #ObjectConstructors -#if TESTS_AS_APP -module Core_longnames -#endif -let failures = ref [] - -let report_failure (s : string) = - stderr.Write" NO: " - stderr.WriteLine s - failures := !failures @ [s] - -let test (s : string) b = - stderr.Write(s) - if b then stderr.WriteLine " OK" - else report_failure (s) - -let check s b1 b2 = test s (b1 = b2) - -(* Some test expressions *) -[] -type MyMath() = - static member Min(a: double, b: double) = System.Math.Min(a, b) - static member Min(a: int, b: int) = System.Math.Min(a, b) - -[] -type AutoOpenMyMath() = - static member AutoMin(a: double, b: double) = System.Math.Min(a, b) - static member AutoMin(a: int, b: int) = System.Math.Min(a, b) - -[] -type NotAllowedToOpen() = - static member QualifiedMin(a: double, b: double) = System.Math.Min(a, b) - static member QualifiedMin(a: int, b: int) = System.Math.Min(a, b) - -module OpenSystemMathOnce = - - open System.Math - let x = Min(1.0, 2.0) - test "vwejhweoiu" (x = 1.0) - - -module OpenSystemMathTwice = - - open System.Math - let x = Min(1.0, 2.0) - - open System.Math - let x2 = Min(2.0, 1.0) - - test "vwejhweoiu2" (x2 = 1.0) - -module OpenMyMathOnce = - - open MyMath - let x = Min(1.0, 2.0) - let x2 = Min(1, 2) - - test "vwejhweoiu2" (x = 1.0) - test "vwejhweoiu3" (x2 = 1) - -module DontOpenAutoMath = - - let x = AutoMin(1.0, 2.0) - let x2 = AutoMin(1, 2) - - test "vwejhweoiu2" (x = 1.0) - test "vwejhweoiu3" (x2 = 1) - -module OpenAutoMath = - open AutoOpenMyMath - //open NotAllowedToOpen - - let x = AutoMin(1.0, 2.0) - let x2 = AutoMin(1, 2) - - test "vwejhweoiu2" (x = 1.0) - test "vwejhweoiu3" (x2 = 1) - -#if TESTS_AS_APP -let RUN() = !failures -#else -let aa = - match !failures with - | [] -> - stdout.WriteLine "Test Passed" - System.IO.File.WriteAllText("test.ok","ok") - exit 0 - | _ -> - stdout.WriteLine "Test Failed" - exit 1 -#endif diff --git a/tests/fsharp/core/members/basics/test.fs b/tests/fsharp/core/members/basics/test.fs index 27c9e6c3a40..a5da244c0a6 100644 --- a/tests/fsharp/core/members/basics/test.fs +++ b/tests/fsharp/core/members/basics/test.fs @@ -1178,8 +1178,8 @@ module ToStringOnRecordTest = begin let a1 = {A = "201"; B = 7} let c1 = {C = "20"; D = 17} - let expected1 = "{A = \"201\";\n B = 7;}" - let expected2 = "{C = \"20\";\n D = 17;}" + let expected1 = "{ A = \"201\"\n B = 7 }" + let expected2 = "{ C = \"20\"\n D = 17 }" do test "record-tostring-def" (a1.ToString() = expected1) do test "record-sprintfO-def" ((sprintf "%O" a1) = expected1) diff --git a/tests/fsharp/core/printing/z.output.test.1000.stdout.bsl b/tests/fsharp/core/printing/z.output.test.1000.stdout.bsl index 1f9224b67b7..52c96dd7598 100644 --- a/tests/fsharp/core/printing/z.output.test.1000.stdout.bsl +++ b/tests/fsharp/core/printing/z.output.test.1000.stdout.bsl @@ -226,7 +226,7 @@ type T = end val f_as_method : x:int -> int val f_as_thunk : (int -> int) -val refCell : string ref = {contents = "value";} +val refCell : string ref = { contents = "value" } module D1 = begin val words : System.Collections.Generic.IDictionary val words2000 : System.Collections.Generic.IDictionary @@ -1134,7 +1134,7 @@ end | B > type internal T2 = - {x: int;} + { x: int } > type internal T3 @@ -1148,28 +1148,28 @@ end | B > type T2 = - internal {x: int;} + internal { x: int } > type private T1 = | A | B > type private T2 = - {x: int;} + { x: int } > type T1 = private | A | B > type T2 = - private {x: int;} + private { x: int } > type internal T1 = private | A | B > type internal T2 = - private {x: int;} + private { x: int } > type private T3 @@ -1233,121 +1233,121 @@ type 'a T1Pre with member E : IEvent > type r = - {f0: int; - f1: int; - f2: int; - f3: int; - f4: int; - f5: int; - f6: int; - f7: int; - f8: int; - f9: int;} -val r10 : r = {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;} + { f0: int + f1: int + f2: int + f3: int + f4: int + f5: int + f6: int + f7: int + f8: int + f9: int } +val r10 : r = { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 } val r10s : r [] = - [|{f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; ...|] + [|{ f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; ...|] val r10s' : string * r [] = ("one extra node", - [|{f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = ...;}; ...|]) + [|{ f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = ... }; ...|]) > val x1564_A1 : int = 1 @@ -1398,7 +1398,7 @@ val x1564_A3 : int = 3 | A | B type T2 = - {x: int;} + { x: int } type T3 type T4 = class @@ -1408,22 +1408,22 @@ val x1564_A3 : int = 3 | A | B type T6 = - {x: int;} + { x: int } type private T7 = | A | B type private T8 = - {x: int;} + { x: int } type T9 = private | A | B type T10 = - private {x: int;} + private { x: int } type T11 = private | A | B type T12 = - private {x: int;} + private { x: int } type private T13 type private T14 = class @@ -1446,7 +1446,7 @@ module internal PrivateM = begin | A | B type T2 = - {x: int;} + { x: int } type T3 type T4 = class @@ -1456,22 +1456,22 @@ module internal PrivateM = begin | A | B type T6 = - {x: int;} + { x: int } type private T7 = | A | B type private T8 = - {x: int;} + { x: int } type T9 = private | A | B type T10 = - private {x: int;} + private { x: int } type T11 = private | A | B type T12 = - private {x: int;} + private { x: int } type private T13 type private T14 = class @@ -1806,9 +1806,9 @@ module Regression1019_long = begin val single_infinity : float32 = infinityf end -> val it : int ref = {contents = 1;} +> val it : int ref = { contents = 1 } -> val x : int ref = {contents = 1;} +> val x : int ref = { contents = 1 } val f : (unit -> int) > val it : int = 1 @@ -2732,11 +2732,11 @@ val namedEx1 : exn = MyNamedException1 (5,"") val namedEx2 : exn = MyNamedException7 25 > type optionRecord = - {x: int option;} -val x : optionRecord = {x = None;} + { x: int option } +val x : optionRecord = { x = None } > type optionRecord = - {x: obj;} -val x : optionRecord = {x = null;} + { x: obj } +val x : optionRecord = { x = null } > > > diff --git a/tests/fsharp/core/printing/z.output.test.200.stdout.bsl b/tests/fsharp/core/printing/z.output.test.200.stdout.bsl index 0877fcb8002..249743e0cff 100644 --- a/tests/fsharp/core/printing/z.output.test.200.stdout.bsl +++ b/tests/fsharp/core/printing/z.output.test.200.stdout.bsl @@ -121,7 +121,7 @@ type T = end val f_as_method : x:int -> int val f_as_thunk : (int -> int) -val refCell : string ref = {contents = "value";} +val refCell : string ref = { contents = "value" } module D1 = begin val words : System.Collections.Generic.IDictionary val words2000 : System.Collections.Generic.IDictionary @@ -458,7 +458,7 @@ end | B > type internal T2 = - {x: int;} + { x: int } > type internal T3 @@ -472,28 +472,28 @@ end | B > type T2 = - internal {x: int;} + internal { x: int } > type private T1 = | A | B > type private T2 = - {x: int;} + { x: int } > type T1 = private | A | B > type T2 = - private {x: int;} + private { x: int } > type internal T1 = private | A | B > type internal T2 = - private {x: int;} + private { x: int } > type private T3 @@ -557,46 +557,46 @@ type 'a T1Pre with member E : IEvent > type r = - {f0: int; - f1: int; - f2: int; - f3: int; - f4: int; - f5: int; - f6: int; - f7: int; - f8: int; - f9: int;} -val r10 : r = {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;} -val r10s : r [] = [|{f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; ...|] -val r10s' : string * r [] = ("one extra node", [|{f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = ...;}; ...|]) + { f0: int + f1: int + f2: int + f3: int + f4: int + f5: int + f6: int + f7: int + f8: int + f9: int } +val r10 : r = { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 } +val r10s : r [] = [|{ f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; ...|] +val r10s' : string * r [] = ("one extra node", [|{ f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = ... }; ...|]) > val x1564_A1 : int = 1 @@ -647,7 +647,7 @@ val x1564_A3 : int = 3 | A | B type T2 = - {x: int;} + { x: int } type T3 type T4 = class @@ -657,22 +657,22 @@ val x1564_A3 : int = 3 | A | B type T6 = - {x: int;} + { x: int } type private T7 = | A | B type private T8 = - {x: int;} + { x: int } type T9 = private | A | B type T10 = - private {x: int;} + private { x: int } type T11 = private | A | B type T12 = - private {x: int;} + private { x: int } type private T13 type private T14 = class @@ -695,7 +695,7 @@ module internal PrivateM = begin | A | B type T2 = - {x: int;} + { x: int } type T3 type T4 = class @@ -705,22 +705,22 @@ module internal PrivateM = begin | A | B type T6 = - {x: int;} + { x: int } type private T7 = | A | B type private T8 = - {x: int;} + { x: int } type T9 = private | A | B type T10 = - private {x: int;} + private { x: int } type T11 = private | A | B type T12 = - private {x: int;} + private { x: int } type private T13 type private T14 = class @@ -1055,9 +1055,9 @@ module Regression1019_long = begin val single_infinity : float32 = infinityf end -> val it : int ref = {contents = 1;} +> val it : int ref = { contents = 1 } -> val x : int ref = {contents = 1;} +> val x : int ref = { contents = 1 } val f : (unit -> int) > val it : int = 1 @@ -1981,11 +1981,11 @@ val namedEx1 : exn = MyNamedException1 (5,"") val namedEx2 : exn = MyNamedException7 25 > type optionRecord = - {x: int option;} -val x : optionRecord = {x = None;} + { x: int option } +val x : optionRecord = { x = None } > type optionRecord = - {x: obj;} -val x : optionRecord = {x = null;} + { x: obj } +val x : optionRecord = { x = null } > > > diff --git a/tests/fsharp/core/printing/z.output.test.default.stdout.bsl b/tests/fsharp/core/printing/z.output.test.default.stdout.bsl index fab8d8dbaa8..f861d11fef2 100644 --- a/tests/fsharp/core/printing/z.output.test.default.stdout.bsl +++ b/tests/fsharp/core/printing/z.output.test.default.stdout.bsl @@ -241,7 +241,7 @@ type T = end val f_as_method : x:int -> int val f_as_thunk : (int -> int) -val refCell : string ref = {contents = "value";} +val refCell : string ref = { contents = "value" } module D1 = begin val words : System.Collections.Generic.IDictionary val words2000 : System.Collections.Generic.IDictionary @@ -4072,7 +4072,7 @@ end | B > type internal T2 = - {x: int;} + { x: int } > type internal T3 @@ -4086,28 +4086,28 @@ end | B > type T2 = - internal {x: int;} + internal { x: int } > type private T1 = | A | B > type private T2 = - {x: int;} + { x: int } > type T1 = private | A | B > type T2 = - private {x: int;} + private { x: int } > type internal T1 = private | A | B > type internal T2 = - private {x: int;} + private { x: int } > type private T3 @@ -4171,709 +4171,709 @@ type 'a T1Pre with member E : IEvent > type r = - {f0: int; - f1: int; - f2: int; - f3: int; - f4: int; - f5: int; - f6: int; - f7: int; - f8: int; - f9: int;} -val r10 : r = {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;} + { f0: int + f1: int + f2: int + f3: int + f4: int + f5: int + f6: int + f7: int + f8: int + f9: int } +val r10 : r = { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 } val r10s : r [] = - [|{f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; - {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; - {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; - {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; - {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; - {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; - {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}|] + [|{ f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; + { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; + { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; + { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; + { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; + { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; + { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }|] val r10s' : string * r [] = ("one extra node", - [|{f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; - {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; - {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; - {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; - {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; - {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}; - {f0 = 0; - f1 = 1; - f2 = 2; - f3 = 3; - f4 = 4; - f5 = 5; - f6 = 6; - f7 = 7; - f8 = 8; - f9 = 9;}|]) + [|{ f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; + { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; + { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; + { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; + { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; + { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }; + { f0 = 0 + f1 = 1 + f2 = 2 + f3 = 3 + f4 = 4 + f5 = 5 + f6 = 6 + f7 = 7 + f8 = 8 + f9 = 9 }|]) > val x1564_A1 : int = 1 @@ -4924,7 +4924,7 @@ val x1564_A3 : int = 3 | A | B type T2 = - {x: int;} + { x: int } type T3 type T4 = class @@ -4934,22 +4934,22 @@ val x1564_A3 : int = 3 | A | B type T6 = - {x: int;} + { x: int } type private T7 = | A | B type private T8 = - {x: int;} + { x: int } type T9 = private | A | B type T10 = - private {x: int;} + private { x: int } type T11 = private | A | B type T12 = - private {x: int;} + private { x: int } type private T13 type private T14 = class @@ -4972,7 +4972,7 @@ module internal PrivateM = begin | A | B type T2 = - {x: int;} + { x: int } type T3 type T4 = class @@ -4982,22 +4982,22 @@ module internal PrivateM = begin | A | B type T6 = - {x: int;} + { x: int } type private T7 = | A | B type private T8 = - {x: int;} + { x: int } type T9 = private | A | B type T10 = - private {x: int;} + private { x: int } type T11 = private | A | B type T12 = - private {x: int;} + private { x: int } type private T13 type private T14 = class @@ -5332,9 +5332,9 @@ module Regression1019_long = begin val single_infinity : float32 = infinityf end -> val it : int ref = {contents = 1;} +> val it : int ref = { contents = 1 } -> val x : int ref = {contents = 1;} +> val x : int ref = { contents = 1 } val f : (unit -> int) > val it : int = 1 @@ -6258,11 +6258,11 @@ val namedEx1 : exn = MyNamedException1 (5,"") val namedEx2 : exn = MyNamedException7 25 > type optionRecord = - {x: int option;} -val x : optionRecord = {x = None;} + { x: int option } +val x : optionRecord = { x = None } > type optionRecord = - {x: obj;} -val x : optionRecord = {x = null;} + { x: obj } +val x : optionRecord = { x = null } > > > diff --git a/tests/fsharp/core/printing/z.output.test.off.stdout.bsl b/tests/fsharp/core/printing/z.output.test.off.stdout.bsl index 2b0d6ca9877..9c90f3e2fac 100644 --- a/tests/fsharp/core/printing/z.output.test.off.stdout.bsl +++ b/tests/fsharp/core/printing/z.output.test.off.stdout.bsl @@ -289,7 +289,7 @@ end | B > type internal T2 = - {x: int;} + { x: int } > type internal T3 @@ -303,28 +303,28 @@ end | B > type T2 = - internal {x: int;} + internal { x: int } > type private T1 = | A | B > type private T2 = - {x: int;} + { x: int } > type T1 = private | A | B > type T2 = - private {x: int;} + private { x: int } > type internal T1 = private | A | B > type internal T2 = - private {x: int;} + private { x: int } > type private T3 @@ -388,16 +388,16 @@ type 'a T1Pre with member E : IEvent > type r = - {f0: int; - f1: int; - f2: int; - f3: int; - f4: int; - f5: int; - f6: int; - f7: int; - f8: int; - f9: int;} + { f0: int + f1: int + f2: int + f3: int + f4: int + f5: int + f6: int + f7: int + f8: int + f9: int } val r10 : r val r10s : r [] val r10s' : string * r [] @@ -451,7 +451,7 @@ val x1564_A3 : int | A | B type T2 = - {x: int;} + { x: int } type T3 type T4 = class @@ -461,22 +461,22 @@ val x1564_A3 : int | A | B type T6 = - {x: int;} + { x: int } type private T7 = | A | B type private T8 = - {x: int;} + { x: int } type T9 = private | A | B type T10 = - private {x: int;} + private { x: int } type T11 = private | A | B type T12 = - private {x: int;} + private { x: int } type private T13 type private T14 = class @@ -499,7 +499,7 @@ module internal PrivateM = begin | A | B type T2 = - {x: int;} + { x: int } type T3 type T4 = class @@ -509,22 +509,22 @@ module internal PrivateM = begin | A | B type T6 = - {x: int;} + { x: int } type private T7 = | A | B type private T8 = - {x: int;} + { x: int } type T9 = private | A | B type T10 = - private {x: int;} + private { x: int } type T11 = private | A | B type T12 = - private {x: int;} + private { x: int } type private T13 type private T14 = class @@ -831,7 +831,7 @@ module Regression1019_long = begin val single_infinity : float32 end -> val it : int ref = {contents = 1;} +> val it : int ref = { contents = 1 } > val x : int ref val f : (unit -> int) @@ -1755,11 +1755,11 @@ val namedEx1 : exn val namedEx2 : exn > type optionRecord = - {x: int option;} + { x: int option } val x : optionRecord > type optionRecord = - {x: obj;} + { x: obj } val x : optionRecord > > > diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index fab4a5fa84b..94c46a1dced 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -1302,21 +1302,6 @@ module CoreTests = [] let ``longnames-FSI_BASIC`` () = singleTestBuildAndRun "core/longnames" FSI_BASIC -#if !FSHARP_SUITE_DRIVES_CORECLR_TESTS - [] - let ``longnames-version46`` () = - let cfg = testConfig "core/longnames/version46" - // For some reason this warning is off by default in the test framework but in this case we are testing for it - let cfg = { cfg with fsc_flags = cfg.fsc_flags.Replace("--nowarn:20", "") } - singleVersionedNegTest cfg "4.6" "test" -#endif - - [] - let ``longnames-version47-FSC_BASIC`` () = singleTestBuildAndRunVersion "core/longnames/version47" FSC_BASIC "preview" - - [] - let ``longnames-version47-FSI_BASIC`` () = singleTestBuildAndRunVersion "core/longnames/version47" FSI_BASIC "preview" - [] let ``math-numbersVS2008-FSC_BASIC`` () = singleTestBuildAndRun "core/math/numbersVS2008" FSC_BASIC diff --git a/tests/fsharp/typecheck/sigs/neg113.bsl b/tests/fsharp/typecheck/sigs/neg113.bsl index 211ba670f91..b9f0190c63b 100644 --- a/tests/fsharp/typecheck/sigs/neg113.bsl +++ b/tests/fsharp/typecheck/sigs/neg113.bsl @@ -3,20 +3,20 @@ neg113.fs(5,50,5,61): typecheck error FS0001: Two anonymous record types have mi neg113.fs(7,41,7,52): typecheck error FS0001: Two anonymous record types have mismatched sets of field names '["b"]' and '["a"]' -neg113.fs(10,27,10,55): typecheck error FS0059: The type '{|a : int|}' does not have any proper subtypes and need not be used as the target of a static coercion +neg113.fs(10,27,10,55): typecheck error FS0059: The type '{| a: int |}' does not have any proper subtypes and need not be used as the target of a static coercion neg113.fs(10,27,10,55): typecheck error FS0193: Type constraint mismatch. The type - '{|b : int|}' + '{| b: int |}' is not compatible with type - '{|a : int|}' + '{| a: int |}' -neg113.fs(13,27,13,62): typecheck error FS0059: The type '{|a : int|}' does not have any proper subtypes and need not be used as the target of a static coercion +neg113.fs(13,27,13,62): typecheck error FS0059: The type '{| a: int |}' does not have any proper subtypes and need not be used as the target of a static coercion neg113.fs(13,27,13,62): typecheck error FS0193: Type constraint mismatch. The type - '{|a : int ; b : int|}' + '{| a: int; b: int |}' is not compatible with type - '{|a : int|}' + '{| a: int |}' neg113.fs(18,34,18,36): typecheck error FS0001: The type '('a -> 'a)' does not support the 'comparison' constraint. For example, it does not support the 'System.IComparable' interface diff --git a/tests/fsharp/typecheck/sigs/neg113.vsbsl b/tests/fsharp/typecheck/sigs/neg113.vsbsl index 211ba670f91..b9f0190c63b 100644 --- a/tests/fsharp/typecheck/sigs/neg113.vsbsl +++ b/tests/fsharp/typecheck/sigs/neg113.vsbsl @@ -3,20 +3,20 @@ neg113.fs(5,50,5,61): typecheck error FS0001: Two anonymous record types have mi neg113.fs(7,41,7,52): typecheck error FS0001: Two anonymous record types have mismatched sets of field names '["b"]' and '["a"]' -neg113.fs(10,27,10,55): typecheck error FS0059: The type '{|a : int|}' does not have any proper subtypes and need not be used as the target of a static coercion +neg113.fs(10,27,10,55): typecheck error FS0059: The type '{| a: int |}' does not have any proper subtypes and need not be used as the target of a static coercion neg113.fs(10,27,10,55): typecheck error FS0193: Type constraint mismatch. The type - '{|b : int|}' + '{| b: int |}' is not compatible with type - '{|a : int|}' + '{| a: int |}' -neg113.fs(13,27,13,62): typecheck error FS0059: The type '{|a : int|}' does not have any proper subtypes and need not be used as the target of a static coercion +neg113.fs(13,27,13,62): typecheck error FS0059: The type '{| a: int |}' does not have any proper subtypes and need not be used as the target of a static coercion neg113.fs(13,27,13,62): typecheck error FS0193: Type constraint mismatch. The type - '{|a : int ; b : int|}' + '{| a: int; b: int |}' is not compatible with type - '{|a : int|}' + '{| a: int |}' neg113.fs(18,34,18,36): typecheck error FS0001: The type '('a -> 'a)' does not support the 'comparison' constraint. For example, it does not support the 'System.IComparable' interface diff --git a/tests/fsharp/typecheck/sigs/neg_anon_1.bsl b/tests/fsharp/typecheck/sigs/neg_anon_1.bsl index d7aaaecd939..3e75d81144c 100644 --- a/tests/fsharp/typecheck/sigs/neg_anon_1.bsl +++ b/tests/fsharp/typecheck/sigs/neg_anon_1.bsl @@ -3,20 +3,20 @@ neg_anon_1.fs(5,50,5,61): typecheck error FS0001: Two anonymous record types hav neg_anon_1.fs(7,41,7,52): typecheck error FS0001: Two anonymous record types have mismatched sets of field names '["b"]' and '["a"]' -neg_anon_1.fs(10,27,10,55): typecheck error FS0059: The type '{|a : int|}' does not have any proper subtypes and need not be used as the target of a static coercion +neg_anon_1.fs(10,27,10,55): typecheck error FS0059: The type '{| a: int |}' does not have any proper subtypes and need not be used as the target of a static coercion neg_anon_1.fs(10,27,10,55): typecheck error FS0193: Type constraint mismatch. The type - '{|b : int|}' + '{| b: int |}' is not compatible with type - '{|a : int|}' + '{| a: int |}' -neg_anon_1.fs(13,27,13,62): typecheck error FS0059: The type '{|a : int|}' does not have any proper subtypes and need not be used as the target of a static coercion +neg_anon_1.fs(13,27,13,62): typecheck error FS0059: The type '{| a: int |}' does not have any proper subtypes and need not be used as the target of a static coercion neg_anon_1.fs(13,27,13,62): typecheck error FS0193: Type constraint mismatch. The type - '{|a : int ; b : int|}' + '{| a: int; b: int |}' is not compatible with type - '{|a : int|}' + '{| a: int |}' neg_anon_1.fs(18,34,18,36): typecheck error FS0001: The type '('a -> 'a)' does not support the 'comparison' constraint. For example, it does not support the 'System.IComparable' interface diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/dumpAllCommandLineOptions/dummy.fs b/tests/fsharpqa/Source/CompilerOptions/fsc/dumpAllCommandLineOptions/dummy.fs index 65d7f3ba86d..0c3c619c33e 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsc/dumpAllCommandLineOptions/dummy.fs +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/dumpAllCommandLineOptions/dummy.fs @@ -39,6 +39,7 @@ //section='- ADVANCED - ' ! option=fullpaths kind=OptionUnit //section='- ADVANCED - ' ! option=lib kind=OptionStringList //section='- ADVANCED - ' ! option=baseaddress kind=OptionString +//section='- ADVANCED - ' ! option=checksumalgorithm kind=OptionString //section='- ADVANCED - ' ! option=noframework kind=OptionUnit //section='- ADVANCED - ' ! option=standalone kind=OptionUnit //section='- ADVANCED - ' ! option=staticlink kind=OptionString diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/help/help40.437.1033.bsl b/tests/fsharpqa/Source/CompilerOptions/fsc/help/help40.437.1033.bsl index d1321663d01..5c4045831d7 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsc/help/help40.437.1033.bsl +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/help/help40.437.1033.bsl @@ -137,6 +137,10 @@ Copyright (c) Microsoft Corporation. All Rights Reserved. Default - mscorlib --baseaddress:
Base address for the library to be built +--checksumalgorithm:{SHA1|SHA256} Specify algorithm for calculating + source file checksum stored in PDB. + Supported values are: SHA1 or SHA256 + (default) --noframework Do not reference the default CLI assemblies by default --standalone Statically link the F# library and diff --git a/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/BasicConstants.fs b/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/BasicConstants.fs deleted file mode 100644 index 78303d2713e..00000000000 --- a/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/BasicConstants.fs +++ /dev/null @@ -1,99 +0,0 @@ -// #Conformance #BasicGrammarElements #Constants -#light - -// Verify the ability to specify basic constants - -let sbyteConst = 1y -let int16Const = 1us -let int32Const = 1ul -let int64Const = 1UL - -let byteConst = 1uy -let uint16Const = 1us -let uint32Const = 1ul -let uint64Const = 1uL - -let ieee32Const1 = 1.0f -let ieee32Const2 = 1.0F -let ieee32Const3 = 0x0000000000000001lf - -let ieee64Const1 = 1.0 -let ieee64Const2 = 0x0000000000000001LF - -let bigintConst = 1I - -// let bignumConst = 1N - you need a reference to PowerPack.dll now - -let decimalConst1 = 1.0M -let decimalConst2 = 1.0m - -let charConst = '1' - -let stringConst = "1" - -let bytestringConst = "1"B - -let bytecharConst = '1'B - -let boolConst1 = true -let boolConst2 = false - -let unitConst = () - -let creditCardNumber = 1234_5678_9012_3456L -if creditCardNumber <> 1234567890123456L then - failwith "Wrong parsing" - -let socialSecurityNumber = 999_99_9999L -if socialSecurityNumber <> 999999999L then - failwith "Wrong parsing" - -let pi = 3.14_15F -if pi <> 3.1415F then - failwith "Wrong parsing" - -let hexBytes = 0xFF_EC_DE_5E -if hexBytes <> 0xFFECDE5E then - failwith "Wrong parsing" - -let hexWords = 0xCAFE_BABE -if hexWords <> 0xCAFEBABE then - failwith "Wrong parsing" - -let maxLong = 0x7fff_ffff_ffff_ffffL -if maxLong <> 0x7fffffffffffffffL then - failwith "Wrong parsing" - -let nybbles = 0b0010_0101 -if nybbles <> 0b00100101 then - failwith "Wrong parsing" - -let bytes = 0b11010010_01101001_10010100_10010010 -if bytes <> 0b11010010011010011001010010010010 then - failwith "Wrong parsing" - -let x2 = 5_2 -if x2 <> 52 then - failwith "Wrong parsing" - -let x4 = 5_______2 -if x4 <> 52 then - failwith "Wrong parsing" - -let x7 = 0x5_2 -if x7 <> 0x52 then - failwith "Wrong parsing" - -let x9 = 0_52 -if x9 <> 052 then - failwith "Wrong parsing" - -let x10 = 05_2 -if x10 <> 052 then - failwith "Wrong parsing" - -let x14 = 0o5_2 -if x14 <> 0o52 then - failwith "Wrong parsing" - -exit 0 diff --git a/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/env.lst b/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/env.lst index 500d42d77e1..97183b49781 100644 --- a/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/env.lst +++ b/tests/fsharpqa/Source/Conformance/BasicGrammarElements/Constants/env.lst @@ -1,4 +1,3 @@ - SOURCE=BasicConstants.fs # BasicConstants.fs NOMONO,NoMT SOURCE=E_BasicConstantsBigNum40.fsx SCFLAGS="--test:ErrorRanges" # E_BasicConstantsBigNum40.fsx diff --git a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_MemberConstraints01.fs b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_MemberConstraints01.fs deleted file mode 100644 index 643ec7f7db7..00000000000 --- a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_MemberConstraints01.fs +++ /dev/null @@ -1,6 +0,0 @@ -// #Regression #Conformance #TypeInference #TypeConstraints -// Regression test for FSharp1.0:2262 -// We should emit an error, not ICE -//Invalid constraint - -let inline length (x: ^a) : int = (^a : (member Length : int with get, set) (x, ())) diff --git a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_PrimConstraint04.fs b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_PrimConstraint04.fs deleted file mode 100644 index 08dcbfde122..00000000000 --- a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_PrimConstraint04.fs +++ /dev/null @@ -1,16 +0,0 @@ -// #Regression #Conformance #TypeInference #TypeConstraints -// Regression test for FSharp1.0:4189 -// Title: Type checking oddity - -// This suggestion was resolved as by design, -// so the test makes sure, we're emitting error message about 'not being avalid object construction expression' - -//This is not a valid object construction expression\. Explicit object constructors must either call an alternate constructor or initialize all fields of the object and specify a call to a super class constructor\.$ - -type ImmutableStack<'a> private(items: 'a list) = - - member this.Push item = ImmutableStack(item::items) - member this.Pop = match items with | [] -> failwith "No elements in stack" | x::xs -> x,ImmutableStack(xs) - - // Notice type annotation is commented out, which results in an error - new(col (*: seq<'a>*)) = ImmutableStack(List.ofSeq col) diff --git a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/MemberConstraints01.fs b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/MemberConstraints01.fs deleted file mode 100644 index af263142458..00000000000 --- a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/MemberConstraints01.fs +++ /dev/null @@ -1,24 +0,0 @@ -// #Conformance #TypeInference #TypeConstraints -// Verify you can overload operators on a type and not add all the extra jazz -// such as inlining and the ^ operator. - -type Foo(x : int) = - member this.Val = x - - static member (-->) ((src : Foo), (target : Foo)) = new Foo(src.Val + target.Val) - static member (-->) ((src : Foo), (target : int)) = new Foo(src.Val + target) - - static member (+) ((src : Foo), (target : Foo)) = new Foo(src.Val + target.Val) - static member (+) ((src : Foo), (target : int)) = new Foo(src.Val + target) - -let x = Foo(3) --> 4 -let y = Foo(3) --> Foo(4) -let x2 = Foo(3) + 4 -let y2 = Foo(3) + Foo(4) - -if x.Val <> 7 then exit 1 -if y.Val <> 7 then exit 1 -if x2.Val <> 7 then exit 1 -if y2.Val <> 7 then exit 1 - -exit 0 diff --git a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/PrimConstraint01.fs b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/PrimConstraint01.fs deleted file mode 100644 index e9b11b1c99f..00000000000 --- a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/PrimConstraint01.fs +++ /dev/null @@ -1,26 +0,0 @@ -// #Conformance #TypeInference #TypeConstraints -#light - -// Test primitive constraints - -// Test ':' constraints - -type Foo(x : int) = - member this.Value = x - override this.ToString() = "Foo" - -type Bar(x : int) = - inherit Foo(-1) - member this.Value2 = x - override this.ToString() = "Bar" - -let test1 (x : Foo) = x.Value -let test2 (x : Bar) = (x.Value, x.Value2) - -let f = new Foo(128) -let b = new Bar(256) - -if test1 f <> 128 then exit 1 -if test2 b <> (-1, 256) then exit 1 - -exit 0 diff --git a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/PrimConstraint02.fs b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/PrimConstraint02.fs deleted file mode 100644 index b410f4e528f..00000000000 --- a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/PrimConstraint02.fs +++ /dev/null @@ -1,33 +0,0 @@ -// #Conformance #TypeInference #TypeConstraints - -#light - -// Test primitive constraints - -// Test ':>' constraints - -type Foo(x : int) = - member this.Value = x - override this.ToString() = "Foo" - -type Bar(x : int) = - inherit Foo(-1) - member this.Value2 = x - override this.ToString() = "Bar" - -type Ram(x : int) = - inherit Foo(10) - member this.ValueA = x - override this.ToString() = "Ram" - -let test (x : Foo) = (x.Value, x.ToString()) - -let f = new Foo(128) -let b = new Bar(256) -let r = new Ram(314) - -if test f <> (128, "Foo") then exit 1 -if test b <> (-1, "Bar") then exit 1 -if test r <> (10, "Ram") then exit 1 - -exit 0 diff --git a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/PrimConstraint03.fs b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/PrimConstraint03.fs deleted file mode 100644 index 7f9a072fd65..00000000000 --- a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/PrimConstraint03.fs +++ /dev/null @@ -1,23 +0,0 @@ -// #Conformance #TypeInference #TypeConstraints -#light - -// Test primitive constraints - -// Test ': null' constraints - -let inline isNull<'a when 'a : null> (x : 'a) = - match x with - | null -> "is null" - | _ -> (x :> obj).ToString() - -let runTest = - // Wrapping in try block to work around FSB 1989 - try - if isNull null <> "is null" then exit 1 - if isNull "F#" <> "F#" then exit 1 - true - with _ -> exit 1 - -if runTest <> true then exit 1 - -exit 0 diff --git a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/env.lst b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/env.lst index 4b89bcc2ba8..041ba830d0b 100644 --- a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/env.lst +++ b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/env.lst @@ -1,10 +1,5 @@ SOURCE=E_NoImplicitDowncast01.fs SCFLAGS="--test:ErrorRanges --flaterrors" # E_NoImplicitDowncast01.fs - SOURCE=PrimConstraint01.fs # PrimConstraint01.fs - SOURCE=PrimConstraint02.fs # PrimConstraint02.fs - SOURCE=PrimConstraint03.fs # PrimConstraint03.fs - SOURCE=E_PrimConstraint04.fs SCFLAGS="--test:ErrorRanges" # E_PrimConstraint04.fs - SOURCE=E_TypeFuncDeclaredExplicit01.fs # E_TypeFuncDeclaredExplicit01.fs SOURCE=ValueRestriction01.fs # ValueRestriction01.fs @@ -16,7 +11,4 @@ SOURCE=DelegateConstraint01.fs # DelegateConstraint01.fs SOURCE=E_DelegateConstraint01.fs # E_DelegateConstraint01.fs - SOURCE=MemberConstraints01.fs # MemberConstraints01.fs - SOURCE=E_MemberConstraints01.fs SCFLAGS="--test:ErrorRanges" # E_MemberConstraints01.fs - SOURCE=ConstructorConstraint01.fs # ConstructorConstraint01.fs \ No newline at end of file diff --git a/tests/fsharpqa/Source/ErrorMessages/NameResolution/E_FieldNotInRecord.fs b/tests/fsharpqa/Source/ErrorMessages/NameResolution/E_FieldNotInRecord.fs deleted file mode 100644 index 4a5361f8f67..00000000000 --- a/tests/fsharpqa/Source/ErrorMessages/NameResolution/E_FieldNotInRecord.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #ErrorMessages #NameResolution -//The record type 'F' does not contain a label 'Wall'\. - -type A = { Hello:string; World:string } -type B = { Size:int; Height:int } -type C = { Wheels:int } -type D = { Size:int; Height:int; Walls:int } -type E = { Unknown:string } -type F = { Wallis:int; Size:int; Height:int; } - -let r:F = { Size=3; Height=4; Wall=1 } - -exit 0 diff --git a/tests/fsharpqa/Source/ErrorMessages/NameResolution/E_GlobalQualifierAfterDot.fs b/tests/fsharpqa/Source/ErrorMessages/NameResolution/E_GlobalQualifierAfterDot.fs deleted file mode 100644 index b369ffad37f..00000000000 --- a/tests/fsharpqa/Source/ErrorMessages/NameResolution/E_GlobalQualifierAfterDot.fs +++ /dev/null @@ -1,6 +0,0 @@ -// #ErrorMessages #NameResolution -//'global' may only be used as the first name in a qualified path - -let x = global.System.String.Empty.global.System.String.Empty - -exit 0 diff --git a/tests/fsharpqa/Source/ErrorMessages/NameResolution/E_RecordFieldProposal.fs b/tests/fsharpqa/Source/ErrorMessages/NameResolution/E_RecordFieldProposal.fs deleted file mode 100644 index ca73d5c1e54..00000000000 --- a/tests/fsharpqa/Source/ErrorMessages/NameResolution/E_RecordFieldProposal.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #ErrorMessages #NameResolution -//The record label 'Wall' is not defined\. - -type A = { Hello:string; World:string } -type B = { Size:int; Height:int } -type C = { Wheels:int } -type D = { Size:int; Height:int; Walls:int } -type E = { Unknown:string } -type F = { Wallis:int; Size:int; Height:int; } - -let r = { Size=3; Height=4; Wall=1 } - -exit 0 diff --git a/tests/fsharpqa/Source/ErrorMessages/NameResolution/env.lst b/tests/fsharpqa/Source/ErrorMessages/NameResolution/env.lst deleted file mode 100644 index 42209ddd28e..00000000000 --- a/tests/fsharpqa/Source/ErrorMessages/NameResolution/env.lst +++ /dev/null @@ -1,3 +0,0 @@ - SOURCE=E_RecordFieldProposal.fs # E_RecordFieldProposal - SOURCE=E_GlobalQualifierAfterDot.fs # E_GlobalQualifierAfterDot - SOURCE=E_FieldNotInRecord.fs # E_FieldNotInRecord \ No newline at end of file diff --git a/tests/fsharpqa/Source/ErrorMessages/UnitGenericAbstractType/E_UnitGenericAbstractType1.fs b/tests/fsharpqa/Source/ErrorMessages/UnitGenericAbstractType/E_UnitGenericAbstractType1.fs deleted file mode 100644 index 0b7f1d98a6d..00000000000 --- a/tests/fsharpqa/Source/ErrorMessages/UnitGenericAbstractType/E_UnitGenericAbstractType1.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #ErrorMessages #UnitGenericAbstractType -//The member 'Apply : int -> unit' is specialized with 'unit' but 'unit' can't be used as return type of an abstract method parameterized on return type\. -type EDF<'S> = - abstract member Apply : int -> 'S -type SomeEDF () = - interface EDF with - member this.Apply d = - // [ERROR] The member 'Apply' does not have the correct type to override the corresponding abstract method. - () \ No newline at end of file diff --git a/tests/fsharpqa/Source/ErrorMessages/UnitGenericAbstractType/env.lst b/tests/fsharpqa/Source/ErrorMessages/UnitGenericAbstractType/env.lst deleted file mode 100644 index 26ae602bd6a..00000000000 --- a/tests/fsharpqa/Source/ErrorMessages/UnitGenericAbstractType/env.lst +++ /dev/null @@ -1 +0,0 @@ - SOURCE=E_UnitGenericAbstractType1.fs # E_UnitGenericAbstractType1 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Libraries/Control/ExecuteAsyncMultipleTimes01.fs b/tests/fsharpqa/Source/Libraries/Control/ExecuteAsyncMultipleTimes01.fs deleted file mode 100644 index e042c6f02df..00000000000 --- a/tests/fsharpqa/Source/Libraries/Control/ExecuteAsyncMultipleTimes01.fs +++ /dev/null @@ -1,17 +0,0 @@ -// #Regression #Libraries #Async -// Regression for FSHARP1.0:5969 -// Async.StartChild: error when wait async is executed more than once - -module M - -let a = async { - let! a = Async.StartChild( - async { - do! Async.Sleep(500) - return 27 - }) - let! result = Async.Parallel [ a; a; a; a ] - return result - } |> Async.RunSynchronously - -exit 0 diff --git a/tests/fsharpqa/Source/Libraries/Control/JoiningStartChild01.fs b/tests/fsharpqa/Source/Libraries/Control/JoiningStartChild01.fs deleted file mode 100644 index 692bb583844..00000000000 --- a/tests/fsharpqa/Source/Libraries/Control/JoiningStartChild01.fs +++ /dev/null @@ -1,25 +0,0 @@ -// #Regression #Libraries #Async -// Regression for FSHARP1.0:5970 -// Async.StartChild: race in implementation of ResultCell in FSharp.Core - -module M - -let Join (a1: Async<'a>) (a2: Async<'b>) = async { - let! task1 = a1 |> Async.StartChild - let! task2 = a2 |> Async.StartChild - - let! res1 = task1 - let! res2 = task2 - return (res1,res2) } - -let r = - try - Async.RunSynchronously (Join (async { do! Async.Sleep(30) - failwith "fail" - return 3+3 }) - (async { do! Async.Sleep(30) - return 2 + 2 } )) - with _ -> - (0,0) - -exit 0 diff --git a/tests/fsharpqa/Source/Libraries/Control/MailboxAsyncNoStackOverflow01.fs b/tests/fsharpqa/Source/Libraries/Control/MailboxAsyncNoStackOverflow01.fs deleted file mode 100644 index 33e0e590a7b..00000000000 --- a/tests/fsharpqa/Source/Libraries/Control/MailboxAsyncNoStackOverflow01.fs +++ /dev/null @@ -1,78 +0,0 @@ -// #Regression #Libraries #Async -// Regression test for FSHARP1.0:6086 -// This is a bit of duplication because the same/similar test -// can also be found under the FSHARP suite. Yet, I like to have -// it here... - -// The interesting thing about this test is that is used to throw -// an exception when executed on 64bit (FSharp.Core 2.0) - -open Microsoft.FSharp.Control - -type Color = Blue | Red | Yellow -let complement = function - | (Red, Yellow) | (Yellow, Red) -> Blue - | (Red, Blue) | (Blue, Red) -> Yellow - | (Yellow, Blue) | (Blue, Yellow) -> Red - | (Blue, Blue) -> Blue - | (Red, Red) -> Red - | (Yellow, Yellow) -> Yellow - -type Message = Color * AsyncReplyChannel - -let chameleon (meetingPlace : MailboxProcessor) initial = - let rec loop c meets = async { - let replyMessage = meetingPlace.PostAndReply(fun reply -> c, reply) - match replyMessage with - | Some(newColor) -> return! loop newColor (meets + 1) - | None -> return meets - } - loop initial 0 - -let meetingPlace chams n = MailboxProcessor.Start(fun (processor : MailboxProcessor)-> - let rec fadingLoop total = - async { - if total <> 0 then - let! (_, reply) = processor.Receive() - reply.Reply None - return! fadingLoop (total - 1) - else - printfn "Done" - } - let rec mainLoop curr = - async { - if (curr > 0) then - let! (color1, reply1) = processor.Receive() - let! (color2, reply2) = processor.Receive() - let newColor = complement (color1, color2) - reply1.Reply <| Some(newColor) - reply2.Reply <| Some(newColor) - return! mainLoop (curr - 1) - else - return! fadingLoop chams - } - mainLoop n - ) - -open System -open System.Diagnostics - -[] -let main(args : string[]) = - printfn "CommandLine : %s" (String.concat ", " args) - let meetings = if args.Length > 0 then Int32.Parse(args.[0]) else 100000 - - let colors = [Blue; Red; Yellow; Blue] - let mp = meetingPlace (colors.Length) meetings - let watch = Stopwatch.StartNew() - let meets = - colors - |> List.map (chameleon mp) - |> Async.Parallel - |> Async.RunSynchronously - watch.Stop() - for meet in meets do - printfn "%d" meet - printfn "Total: %d in %O" (Seq.sum meets) (watch.Elapsed) - 0 - diff --git a/tests/fsharpqa/Source/Libraries/Control/StartChildNoObjectDisposedException01.fs b/tests/fsharpqa/Source/Libraries/Control/StartChildNoObjectDisposedException01.fs deleted file mode 100644 index 5186548c79a..00000000000 --- a/tests/fsharpqa/Source/Libraries/Control/StartChildNoObjectDisposedException01.fs +++ /dev/null @@ -1,12 +0,0 @@ -// #Regression #Libraries #Async -// Regression for FSHARP1.0:5971 -// Async.StartChild: ObjectDisposedException - -module M - -let shortVersion(args: string []) = - let b = async {return 5} |> Async.StartChild - printfn "%A" (b |> Async.RunSynchronously |> Async.RunSynchronously) - (0) - -exit 0 diff --git a/tests/fsharpqa/Source/Libraries/Control/StartChildTestTrampolineHijackLimit01.fs b/tests/fsharpqa/Source/Libraries/Control/StartChildTestTrampolineHijackLimit01.fs deleted file mode 100644 index 46cfeb59376..00000000000 --- a/tests/fsharpqa/Source/Libraries/Control/StartChildTestTrampolineHijackLimit01.fs +++ /dev/null @@ -1,19 +0,0 @@ -// #Regression #Libraries #Async -// Regression for FSHARP1.0:5972 -// Async.StartChild: fails to install trampolines properly -module M - -let r = - async { - let! a = Async.StartChild( - async { - do! Async.Sleep(500) - return 5 - } - ) - let! b = a - for i in 1..10000 do // 10000 > bindHijackLimit - () - } |> Async.RunSynchronously - -exit 0 diff --git a/tests/fsharpqa/Source/Libraries/Control/env.lst b/tests/fsharpqa/Source/Libraries/Control/env.lst deleted file mode 100644 index 6c034ca5b46..00000000000 --- a/tests/fsharpqa/Source/Libraries/Control/env.lst +++ /dev/null @@ -1,6 +0,0 @@ - SOURCE=MailboxAsyncNoStackOverflow01.fs # MailboxAsyncNoStackOverflow01.fs - - SOURCE=ExecuteAsyncMultipleTimes01.fs # ExecuteAsyncMultipleTimes01.fs - SOURCE=JoiningStartChild01.fs # JoiningStartChild01.fs - SOURCE=StartChildNoObjectDisposedException01.fs # StartChildNoObjectDisposedException01.fs - SOURCE=StartChildTestTrampolineHijackLimit01.fs # StartChildTestTrampolineHijackLimit01.fs \ No newline at end of file diff --git a/tests/fsharpqa/Source/Printing/BindingsWithValues01.fsx b/tests/fsharpqa/Source/Printing/BindingsWithValues01.fsx index 052100c05f6..30b453b9fc6 100644 --- a/tests/fsharpqa/Source/Printing/BindingsWithValues01.fsx +++ b/tests/fsharpqa/Source/Printing/BindingsWithValues01.fsx @@ -4,14 +4,14 @@ // Test for FSharp1.0:2581 - FSI should display bound values, not just evaluated expressions (was: FSI should print the value of the last declared value is there is no last expression) //type RecT = -// {Name: string;} +// { Name: string } //type Bldg = // \| House // \| Museum // \| Office //val a : int = 1 //val B : string = "Hello" -//val c' : RecT = {Name = "F#";} +//val c' : RecT = { Name = "F#" } //val _d : Bldg = Office //val e : seq //val F'F : int list = \[3; 2; 1] @@ -19,7 +19,7 @@ //val g' : Set<'a> //val getPointF : x:float32 \* y:float32 -> System\.Drawing\.PointF //val h : System\.Drawing\.PointF = {X=.+, Y=.+} -//val i : int \* RecT \* Bldg = \(1, {Name = "F#";}, Office\) +//val i : int \* RecT \* Bldg = \(1, { Name = "F#" }, Office\) //val J_ : int \[\] = \[\|1; 2; 3\|] //val j_' : float \[\] = \[\|1\.0; 1\.0\|] //val j_'_ : RecT \[\] = \[\|\|] diff --git a/tests/fsharpqa/Source/Printing/CustomExceptions01.fs b/tests/fsharpqa/Source/Printing/CustomExceptions01.fs index 6f33bff2e19..7a2949be917 100644 --- a/tests/fsharpqa/Source/Printing/CustomExceptions01.fs +++ b/tests/fsharpqa/Source/Printing/CustomExceptions01.fs @@ -16,7 +16,7 @@ exception WeekendEx of WeekendDay if sprintf "%A" (Foo) <> "Foo" || sprintf "%A" (Bar 10) <> "Bar 10" || sprintf "%A" (FooBaz System.DateTime.Today) <> ("FooBaz " + System.DateTime.Today.ToString()) - || sprintf "%A" (MarkupEx {Body = ""}) <> "MarkupEx {Body = \"\";}" + || sprintf "%A" (MarkupEx {Body = ""}) <> "MarkupEx { Body = \"\" }" || sprintf "%A" (WeekendEx Saturday) <> "WeekendEx Saturday" then exit 1 diff --git a/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation.fs b/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation.fs deleted file mode 100644 index b72fdb7baae..00000000000 --- a/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation.fs +++ /dev/null @@ -1,8 +0,0 @@ -// #Warnings -//The type 'Hidden' is less accessible than the value, member or type 'Exported' it is used in - -module Library = - type private Hidden = Hidden of unit - type Exported = Hidden - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation2.fs b/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation2.fs deleted file mode 100644 index 898e941523e..00000000000 --- a/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation2.fs +++ /dev/null @@ -1,8 +0,0 @@ -// #Warnings -// - -module Library = - type internal Hidden = Hidden of unit - type internal Exported = Hidden - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation3.fs b/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation3.fs deleted file mode 100644 index de1875bf576..00000000000 --- a/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation3.fs +++ /dev/null @@ -1,8 +0,0 @@ -// #Warnings -//The type 'Hidden' is less accessible than the value, member or type 'Exported' it is used in - -module Library = - type internal Hidden = Hidden of unit - type Exported = Hidden - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation4.fs b/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation4.fs deleted file mode 100644 index 728dc399bf2..00000000000 --- a/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation4.fs +++ /dev/null @@ -1,8 +0,0 @@ -// #Warnings -//The type 'Hidden' is less accessible than the value, member or type 'Exported' it is used in - -module Library = - type private Hidden = Hidden of unit - type internal Exported = Hidden - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation5.fs b/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation5.fs deleted file mode 100644 index d0d3b251008..00000000000 --- a/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation5.fs +++ /dev/null @@ -1,8 +0,0 @@ -// #Warnings -// - -module Library = - type private Hidden = Hidden of unit - type private Exported = Hidden - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation6.fs b/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation6.fs deleted file mode 100644 index d179e5f20e0..00000000000 --- a/tests/fsharpqa/Source/Warnings/AccessOfTypeAbbreviation6.fs +++ /dev/null @@ -1,8 +0,0 @@ -// #Warnings -// - -module Library = - type Hidden = Hidden of unit - type Exported = Hidden - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/AssignmentOnImmutable.fs b/tests/fsharpqa/Source/Warnings/AssignmentOnImmutable.fs deleted file mode 100644 index a2e35c78a90..00000000000 --- a/tests/fsharpqa/Source/Warnings/AssignmentOnImmutable.fs +++ /dev/null @@ -1,7 +0,0 @@ -// #Warnings -//This value is not mutable. Consider using the mutable keyword, e.g. 'let mutable x = expression'. - -let x = 10 -x <- 20 - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/CommaInRecCtor.fs b/tests/fsharpqa/Source/Warnings/CommaInRecCtor.fs deleted file mode 100644 index b14d6c6dc98..00000000000 --- a/tests/fsharpqa/Source/Warnings/CommaInRecCtor.fs +++ /dev/null @@ -1,12 +0,0 @@ -// #Warnings -//This expression was expected to have type -// 'string' -//but here has type -// ''a \* 'b \* 'c' -//A ';' is used to separate field values in records. Consider replacing ',' with ';'. - - -type Person = { Name : string; Age : int; City : string } -let x = { Name = "Isaac", Age = 21, City = "London" } - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/DoCannotHaveVisibilityDeclarations.fs b/tests/fsharpqa/Source/Warnings/DoCannotHaveVisibilityDeclarations.fs deleted file mode 100644 index b57356ee9a0..00000000000 --- a/tests/fsharpqa/Source/Warnings/DoCannotHaveVisibilityDeclarations.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Warnings -//Accessibility -//Accessibility modifiers are not permitted on 'do' bindings, but 'Private' was given. - -type X() = - do () - private do () - static member Y() = 1 - - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/DontSuggestCompletelyWrongStuff.fs b/tests/fsharpqa/Source/Warnings/DontSuggestCompletelyWrongStuff.fs deleted file mode 100644 index 68b6d6dcb7e..00000000000 --- a/tests/fsharpqa/Source/Warnings/DontSuggestCompletelyWrongStuff.fs +++ /dev/null @@ -1,7 +0,0 @@ -// #Warnings -//The value, namespace, type or module 'Path' is not defined. -//Maybe you want one of the following:\s+Math - -let _ = Path.GetFullPath "images" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/DontSuggestIntentionallyUnusedVariables.fs b/tests/fsharpqa/Source/Warnings/DontSuggestIntentionallyUnusedVariables.fs deleted file mode 100644 index 602d459d518..00000000000 --- a/tests/fsharpqa/Source/Warnings/DontSuggestIntentionallyUnusedVariables.fs +++ /dev/null @@ -1,8 +0,0 @@ -//The value or constructor 'xyz' is not defined. -//Maybe you want one of the following: -//\s+xy -//\s+_xyz - -let hober xy _xyz = xyz - -exit 0 diff --git a/tests/fsharpqa/Source/Warnings/DontSuggestWhenThingsAreOpen.fs b/tests/fsharpqa/Source/Warnings/DontSuggestWhenThingsAreOpen.fs deleted file mode 100644 index dad90178a5f..00000000000 --- a/tests/fsharpqa/Source/Warnings/DontSuggestWhenThingsAreOpen.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #Warnings -//Missing qualification after '.' - -module N = - let name = "hallo" - -type T = - static member myMember = 1 - -let x = N. - - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/DontWarnIfPropertyWithoutSetter.fs b/tests/fsharpqa/Source/Warnings/DontWarnIfPropertyWithoutSetter.fs deleted file mode 100644 index 4492e6338c6..00000000000 --- a/tests/fsharpqa/Source/Warnings/DontWarnIfPropertyWithoutSetter.fs +++ /dev/null @@ -1,14 +0,0 @@ -// #Warnings -//The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. - -type MyClass(property1 : int) = - member val Property2 = "" with get - -let x = MyClass(1) -let y = "hello" - -let changeProperty() = - x.Property2 = "22" - y = "test" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/DowncastInsteadOfUpcast.fs b/tests/fsharpqa/Source/Warnings/DowncastInsteadOfUpcast.fs deleted file mode 100644 index a815425e294..00000000000 --- a/tests/fsharpqa/Source/Warnings/DowncastInsteadOfUpcast.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -//Type constraint mismatch. The type - -open System.Collections.Generic - -let orig = Dictionary() :> IDictionary -let c = orig :> Dictionary - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInAppl.fs b/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInAppl.fs deleted file mode 100644 index 79152abb78a..00000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInAppl.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Warnings -//This expression was expected to have - -let test = 100 -let f x : string = x -let y = - if test > 10 then "test" - else - f 123 - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInAppl2.fs b/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInAppl2.fs deleted file mode 100644 index 5478d8b09d3..00000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInAppl2.fs +++ /dev/null @@ -1,12 +0,0 @@ -// #Warnings -//This expression was expected to have - -let test = 100 -let f x = printfn "%s" x -let y = - if test > 10 then "test" - else - f 123 - "test" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInForLoop.fs b/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInForLoop.fs deleted file mode 100644 index bfd5a18dd17..00000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInForLoop.fs +++ /dev/null @@ -1,14 +0,0 @@ -// #Warnings -//This expression was expected to have - -let test = 100 -let list = [1..10] -let y = - if test > 10 then "test" - else - for (x:string) in list do - printfn "%s" x - - "test" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateToLinesBeforeLastLine.fs b/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateToLinesBeforeLastLine.fs deleted file mode 100644 index 9facc603ff6..00000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateToLinesBeforeLastLine.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #Warnings -//This expression was expected to have type - -let test = 100 -let list = [1..10] -let y = - if test > 10 then "test" - else - printfn "%s" 1 - - "test" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongContextType.fs b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongContextType.fs deleted file mode 100644 index 895881ac7be..00000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongContextType.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -//The 'if' expression needs to have type 'bool' - -let x = 1 -let y : bool = - if x = 2 then "A" - else "B" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType.fs b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType.fs deleted file mode 100644 index b14b495304e..00000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -//All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'. - -let test = 100 -let y = - if test > 10 then "test" - else 123 - -exit 0 diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType2.fs b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType2.fs deleted file mode 100644 index 06d83f76aa0..00000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType2.fs +++ /dev/null @@ -1,10 +0,0 @@ -// #Warnings -//All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'. - -let test = 100 -let f x = test -let y = - if test > 10 then "test" - else f 10 - -exit 0 diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType3.fs b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType3.fs deleted file mode 100644 index 1306c794759..00000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType3.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #Warnings -//All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'. - -let f x = x + 4 - -let y = - if true then - "" - else - "" |> ignore - (f 5) - -exit 0 diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType4.fs b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType4.fs deleted file mode 100644 index 8339a930d30..00000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType4.fs +++ /dev/null @@ -1,15 +0,0 @@ -// #Warnings -//All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'. - -let f x = x + 4 - -let y = - if true then - "" - else - "" |> ignore - let z = f 4 - let a = 3 * z - (f a) - -exit 0 diff --git a/tests/fsharpqa/Source/Warnings/ExtraArgumentInCtor.fs b/tests/fsharpqa/Source/Warnings/ExtraArgumentInCtor.fs deleted file mode 100644 index 794245b450b..00000000000 --- a/tests/fsharpqa/Source/Warnings/ExtraArgumentInCtor.fs +++ /dev/null @@ -1,10 +0,0 @@ -// #Warnings -//The object constructor 'Person' takes 0 argument\(s\) but is here given 1. The required signature is 'new : unit -> Person'.$ - -type Person() = - member val Name = "" with get,set - member val Age = 0 with get,set - - -let p = - Person(1) \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ExtraArgumentInCtor2.fs b/tests/fsharpqa/Source/Warnings/ExtraArgumentInCtor2.fs deleted file mode 100644 index c73f250c551..00000000000 --- a/tests/fsharpqa/Source/Warnings/ExtraArgumentInCtor2.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Warnings -//The object constructor 'Person' takes 0 argument\(s\) but is here given 1. The required signature is 'new : unit -> Person'.$ - -type Person() = - member val Name = "" with get,set - member val Age = 0 with get,set - -let b = 1 - -let p = - Person(1=b) \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/GuardHasWrongType.fs b/tests/fsharpqa/Source/Warnings/GuardHasWrongType.fs deleted file mode 100644 index ac0c3cb4f3c..00000000000 --- a/tests/fsharpqa/Source/Warnings/GuardHasWrongType.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -//A pattern match guard must be of type 'bool' - -let x = 1 -match x with -| 1 when "s" -> true -| _ -> false - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/InvalidRecord.fs b/tests/fsharpqa/Source/Warnings/InvalidRecord.fs deleted file mode 100644 index f04f24e4576..00000000000 --- a/tests/fsharpqa/Source/Warnings/InvalidRecord.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -//This expression was expected to have type - -type Record = {field1:int; field2:int} -let doSomething (xs) = List.map (fun {field1=x} -> x) xs - -doSomething {Record.field1=0; field2=0} - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/MatchingMethodWithSameNameIsNotAbstract.fs b/tests/fsharpqa/Source/Warnings/MatchingMethodWithSameNameIsNotAbstract.fs deleted file mode 100644 index 36275ff0e92..00000000000 --- a/tests/fsharpqa/Source/Warnings/MatchingMethodWithSameNameIsNotAbstract.fs +++ /dev/null @@ -1,14 +0,0 @@ -// #Warnings -//The type Foo contains the member 'MyX' but it is not a virtual or abstract method that is available to override or implement. -//ToString - -type Foo(x : int) = - member v.MyX() = x - -let foo = - { new Foo(3) - with - member v.MyX() = 4 } - - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/MemberHasMultiplePossibleDispatchSlots.fs b/tests/fsharpqa/Source/Warnings/MemberHasMultiplePossibleDispatchSlots.fs deleted file mode 100644 index ae6738208b6..00000000000 --- a/tests/fsharpqa/Source/Warnings/MemberHasMultiplePossibleDispatchSlots.fs +++ /dev/null @@ -1,15 +0,0 @@ -// #Warnings -//The member 'Bar -//Please restrict it to one of the following: -//Bar : double -> int -//Bar : int -> int - -type IOverload = - abstract member Bar : int -> int - abstract member Bar : double -> int - -type Overload = - interface IOverload with - override __.Bar _ = 1 - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/MethodIsNotStatic.fs b/tests/fsharpqa/Source/Warnings/MethodIsNotStatic.fs deleted file mode 100644 index 299a88abc3a..00000000000 --- a/tests/fsharpqa/Source/Warnings/MethodIsNotStatic.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -//Method or object constructor 'X' is not static - -type Class1() = - member this.X() = "F#" - -let x = Class1.X() - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/MissingCommaInCtor.fs b/tests/fsharpqa/Source/Warnings/MissingCommaInCtor.fs deleted file mode 100644 index 6c407bc6c4e..00000000000 --- a/tests/fsharpqa/Source/Warnings/MissingCommaInCtor.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Warnings -//The object constructor 'Person' takes 0 argument\(s\) but is here given 1. The required signature is 'new : unit -> Person'. If some of the arguments are meant to assign values to properties, consider separating those arguments with a comma \(','\). - -type Person() = - member val Name = "" with get,set - member val Age = 0 with get,set - - -let p = - Person(Name = "Fred" - Age = 18) \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/MissingCtorValue.fs b/tests/fsharpqa/Source/Warnings/MissingCtorValue.fs deleted file mode 100644 index c90377be50b..00000000000 --- a/tests/fsharpqa/Source/Warnings/MissingCtorValue.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Warnings -//The member or object constructor 'Person' requires 1 argument\(s\). The required signature is 'new : x:int -> Person'. - -type Person(x:int) = - member val Name = "" with get,set - member val Age = x with get,set - - -let p = - Person(Name = "Fred", - Age = 18) \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/NestedElseBranchHasWrongType.fs b/tests/fsharpqa/Source/Warnings/NestedElseBranchHasWrongType.fs deleted file mode 100644 index a8e63cee65a..00000000000 --- a/tests/fsharpqa/Source/Warnings/NestedElseBranchHasWrongType.fs +++ /dev/null @@ -1,10 +0,0 @@ -// #Warnings -//All branches of an 'if' expression must return values of the same type as the first branch, which here is 'bool'. This branch returns a value of type 'string'. - -let x = 1 -if x = 1 then true -else - if x = 2 then "A" - else "B" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/NoMatchingAbstractMethodWithSameName.fs b/tests/fsharpqa/Source/Warnings/NoMatchingAbstractMethodWithSameName.fs deleted file mode 100644 index a59f863a774..00000000000 --- a/tests/fsharpqa/Source/Warnings/NoMatchingAbstractMethodWithSameName.fs +++ /dev/null @@ -1,14 +0,0 @@ -// #Warnings -//The member 'Function' does not correspond to any abstract or virtual method available to override or implement. -//MyFunction - -type IInterface = - abstract MyFunction : int32 * int32 -> unit - abstract SomeOtherFunction : int32 * int32 -> unit - -let x = - { new IInterface with - member this.Function (i, j) = () - } - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/OverrideErrors.fs b/tests/fsharpqa/Source/Warnings/OverrideErrors.fs deleted file mode 100644 index ff03ba6ed4e..00000000000 --- a/tests/fsharpqa/Source/Warnings/OverrideErrors.fs +++ /dev/null @@ -1,22 +0,0 @@ -// #Warnings -//This override takes a different number of arguments to the corresponding abstract member. The following abstract members were found: -//abstract member Base.Member : int * string -> string -//This expression was expected to have type - -type Base() = - abstract member Member: int * string -> string - default x.Member (i, s) = s - -type Derived1() = - inherit Base() - override x.Member() = 5 - -type Derived2() = - inherit Base() - override x.Member (i : int) = "Hello" - -type Derived3() = - inherit Base() - override x.Member (s : string, i : int) = sprintf "Hello %s" s - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/RefCellInsteadOfNot.fs b/tests/fsharpqa/Source/Warnings/RefCellInsteadOfNot.fs deleted file mode 100644 index 1c6987bfa63..00000000000 --- a/tests/fsharpqa/Source/Warnings/RefCellInsteadOfNot.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -//This expression was expected to have type -//The '!' operator is used to dereference a ref cell. Consider using 'not expr' here. - -let x = true -if !x then - printfn "hello" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/RefCellInsteadOfNot2.fs b/tests/fsharpqa/Source/Warnings/RefCellInsteadOfNot2.fs deleted file mode 100644 index 090934d8f56..00000000000 --- a/tests/fsharpqa/Source/Warnings/RefCellInsteadOfNot2.fs +++ /dev/null @@ -1,8 +0,0 @@ -// #Warnings -//This expression was expected to have type -//The '!' operator is used to dereference a ref cell. Consider using 'not expr' here. - -let x = true -let y = !x - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ReturnInsteadOfReturnBang.fs b/tests/fsharpqa/Source/Warnings/ReturnInsteadOfReturnBang.fs deleted file mode 100644 index d9f87c521bd..00000000000 --- a/tests/fsharpqa/Source/Warnings/ReturnInsteadOfReturnBang.fs +++ /dev/null @@ -1,10 +0,0 @@ -// #Warnings -//Type mismatch. Expecting a -//''a' -//but given a -//'Async<'a>' -//The types ''a' and 'Async<'a>' cannot be unified. Consider using 'return!' instead of 'return'. - -let rec foo() = async { return foo() } - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/RuntimeTypeTestInPattern.fs b/tests/fsharpqa/Source/Warnings/RuntimeTypeTestInPattern.fs deleted file mode 100644 index 67ae796376d..00000000000 --- a/tests/fsharpqa/Source/Warnings/RuntimeTypeTestInPattern.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #Warnings -//Type constraint mismatch. The type - -open System.Collections.Generic - -let orig = Dictionary() - -let c = - match orig with - | :? IDictionary -> "yes" - | _ -> "no" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/RuntimeTypeTestInPattern2.fs b/tests/fsharpqa/Source/Warnings/RuntimeTypeTestInPattern2.fs deleted file mode 100644 index 098969482c5..00000000000 --- a/tests/fsharpqa/Source/Warnings/RuntimeTypeTestInPattern2.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #Warnings -//Type constraint mismatch. The type - -open System.Collections.Generic - -let orig = Dictionary() - -let c = - match orig with - | :? IDictionary as y -> "yes" + y.ToString() - | _ -> "no" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/TupleInAbstractMethod.fs b/tests/fsharpqa/Source/Warnings/TupleInAbstractMethod.fs deleted file mode 100644 index 0ed439073e3..00000000000 --- a/tests/fsharpqa/Source/Warnings/TupleInAbstractMethod.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #Warnings -//The member 'Function' does not accept the correct number of arguments. -//A tuple type is required for one or more arguments - -type IInterface = - abstract Function : (int32 * int32) -> unit - -let x = - { new IInterface with - member this.Function (i, j) = () - } - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/UpcastFunctionInsteadOfDowncast.fs b/tests/fsharpqa/Source/Warnings/UpcastFunctionInsteadOfDowncast.fs deleted file mode 100644 index 6bc8c54c124..00000000000 --- a/tests/fsharpqa/Source/Warnings/UpcastFunctionInsteadOfDowncast.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -//The conversion from Dictionary to IDictionary is a compile-time safe upcast, not a downcast. Consider using 'upcast' instead of 'downcast'. - -open System.Collections.Generic - -let orig = Dictionary() -let c : IDictionary = downcast orig - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/UpcastInsteadOfDowncast.fs b/tests/fsharpqa/Source/Warnings/UpcastInsteadOfDowncast.fs deleted file mode 100644 index 00962a1521b..00000000000 --- a/tests/fsharpqa/Source/Warnings/UpcastInsteadOfDowncast.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -//The conversion from Dictionary to IDictionary is a compile-time safe upcast, not a downcast. - -open System.Collections.Generic - -let orig = Dictionary() -let c = orig :?> IDictionary - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ValidCommaInRecCtor.fs b/tests/fsharpqa/Source/Warnings/ValidCommaInRecCtor.fs deleted file mode 100644 index 6cbee50f02c..00000000000 --- a/tests/fsharpqa/Source/Warnings/ValidCommaInRecCtor.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -// - -type Person = { Name : string * bool * bool } -let Age = 22 -let City = "London" -let x = { Name = "Isaac", Age = 21, City = "London" } - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/WarnIfExpressionResultUnused.fs b/tests/fsharpqa/Source/Warnings/WarnIfExpressionResultUnused.fs deleted file mode 100644 index 9480f35b6b6..00000000000 --- a/tests/fsharpqa/Source/Warnings/WarnIfExpressionResultUnused.fs +++ /dev/null @@ -1,5 +0,0 @@ -// #Warnings -//The result of this expression has type 'int' and is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$ - -1 + 2 -printfn "%d" 3 diff --git a/tests/fsharpqa/Source/Warnings/WarnIfImplicitlyDiscarded.fs b/tests/fsharpqa/Source/Warnings/WarnIfImplicitlyDiscarded.fs deleted file mode 100644 index ad7f9deacdd..00000000000 --- a/tests/fsharpqa/Source/Warnings/WarnIfImplicitlyDiscarded.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Warnings -//The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. - -let x = 10 -let y = 20 - -let changeX() = - y * x = 20 - y = 30 - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/WarnIfMissingElseBranch.fs b/tests/fsharpqa/Source/Warnings/WarnIfMissingElseBranch.fs deleted file mode 100644 index 9e6e9d7efe9..00000000000 --- a/tests/fsharpqa/Source/Warnings/WarnIfMissingElseBranch.fs +++ /dev/null @@ -1,8 +0,0 @@ -// #Warnings -//This 'if' expression is missing an 'else' branch. Because 'if' is an expression, and not a statement, add an 'else' branch which also returns a value of type 'string'. - -let x = 10 -let y = - if x > 10 then "test" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/WarnIfMissingElseBranch2.fs b/tests/fsharpqa/Source/Warnings/WarnIfMissingElseBranch2.fs deleted file mode 100644 index a8b98922a0e..00000000000 --- a/tests/fsharpqa/Source/Warnings/WarnIfMissingElseBranch2.fs +++ /dev/null @@ -1,10 +0,0 @@ -// #Warnings -//This expression was expected to have type - -let x = 10 -let y = - if x > 10 then - if x <> "test" then printfn "test" - () - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/WarnIfMissingElseBranch3.fs b/tests/fsharpqa/Source/Warnings/WarnIfMissingElseBranch3.fs deleted file mode 100644 index cbf7d5acf16..00000000000 --- a/tests/fsharpqa/Source/Warnings/WarnIfMissingElseBranch3.fs +++ /dev/null @@ -1,8 +0,0 @@ -// #Warnings -//This 'if' expression is missing an 'else' branch. Because 'if' is an expression, and not a statement, add an 'else' branch which also returns a value of type 'string'. - -let x = 10 -let y = - if x > 10 then ("test") - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/WarnIfPossibleAssignment.fs b/tests/fsharpqa/Source/Warnings/WarnIfPossibleAssignment.fs deleted file mode 100644 index b3fca3a0b92..00000000000 --- a/tests/fsharpqa/Source/Warnings/WarnIfPossibleAssignment.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Warnings -//If you intended to mutate a value, then mark the value 'mutable' and use the '<-' operator e.g. 'x <- expression'. - -let x = 10 -let y = "hello" - -let changeX() = - x = 20 - y = "test" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/WarnIfPossibleAssignmentToMutable.fs b/tests/fsharpqa/Source/Warnings/WarnIfPossibleAssignmentToMutable.fs deleted file mode 100644 index bd827ec4adc..00000000000 --- a/tests/fsharpqa/Source/Warnings/WarnIfPossibleAssignmentToMutable.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Warnings -//If you intended to mutate a value, then use the '<-' operator e.g. 'x <- expression'. - -let mutable x = 10 -let y = "hello" - -let changeX() = - x = 20 - y = "test" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/WarnIfPossibleDotNetPropertySetter.fs b/tests/fsharpqa/Source/Warnings/WarnIfPossibleDotNetPropertySetter.fs deleted file mode 100644 index 7c461349ec2..00000000000 --- a/tests/fsharpqa/Source/Warnings/WarnIfPossibleDotNetPropertySetter.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #Warnings -//If you intended to set a value to a property, then use the '<-' operator e.g. 'z.Enabled <- expression' - -open System - -let z = System.Timers.Timer() -let y = "hello" - -let changeProperty() = - z.Enabled = true - y = "test" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/WarnIfPossiblePropertySetter.fs b/tests/fsharpqa/Source/Warnings/WarnIfPossiblePropertySetter.fs deleted file mode 100644 index 7548d204685..00000000000 --- a/tests/fsharpqa/Source/Warnings/WarnIfPossiblePropertySetter.fs +++ /dev/null @@ -1,15 +0,0 @@ -// #Warnings -//If you intended to set a value to a property, then use the '<-' operator e.g. 'x.Property2 <- expression' - -type MyClass(property1 : int) = - member val Property1 = property1 - member val Property2 = "" with get, set - -let x = MyClass(1) -let y = "hello" - -let changeProperty() = - x.Property2 = "20" - y = "test" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/WarnOnlyOnLastExpression.fs b/tests/fsharpqa/Source/Warnings/WarnOnlyOnLastExpression.fs deleted file mode 100644 index 7b0b968c23b..00000000000 --- a/tests/fsharpqa/Source/Warnings/WarnOnlyOnLastExpression.fs +++ /dev/null @@ -1,10 +0,0 @@ -// #Warnings -//The result of this expression has type 'bool' and is implicitly ignored - -let mutable x = 0 -while x < 1 do - printfn "unneeded" - x <- x + 1 - true - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/WrongArity.fs b/tests/fsharpqa/Source/Warnings/WrongArity.fs deleted file mode 100644 index 459f9a5c7a4..00000000000 --- a/tests/fsharpqa/Source/Warnings/WrongArity.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Warnings -//A member or object constructor 'MyMember' taking 3 - -type MyType() = - static member MyMember(arg1, arg2:int ) = () - static member MyMember(arg1, arg2:byte) = () - - -MyType.MyMember("", 0, 0) - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/YieldInsteadOfYieldBang.fs b/tests/fsharpqa/Source/Warnings/YieldInsteadOfYieldBang.fs deleted file mode 100644 index bd547fa7b28..00000000000 --- a/tests/fsharpqa/Source/Warnings/YieldInsteadOfYieldBang.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #Warnings -//Type mismatch. Expecting a -//''a' -//but given a -//''a list' -//The types ''a' and ''a list' cannot be unified. Consider using 'yield!' instead of 'yield'. - -type Foo() = - member this.Yield(x) = [x] - -let rec f () = Foo() { yield f ()} - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/env.lst b/tests/fsharpqa/Source/Warnings/env.lst index 2992fb0e58e..275959c6957 100644 --- a/tests/fsharpqa/Source/Warnings/env.lst +++ b/tests/fsharpqa/Source/Warnings/env.lst @@ -1,27 +1,5 @@ SOURCE=WrongNumericLiteral.fs # WrongNumericLiteral.fs - SOURCE=WarnIfMissingElseBranch.fs # WarnIfMissingElseBranch.fs - SOURCE=WarnIfMissingElseBranch2.fs # WarnIfMissingElseBranch2.fs - SOURCE=WarnIfMissingElseBranch3.fs # WarnIfMissingElseBranch3.fs - SOURCE=ReturnInsteadOfReturnBang.fs # ReturnInsteadOfReturnBang.fs - SOURCE=YieldInsteadOfYieldBang.fs # YieldInsteadOfYieldBang.fs - SOURCE=TupleInAbstractMethod.fs # TupleInAbstractMethod.fs - SOURCE=InvalidRecord.fs # InvalidRecord.fs - SOURCE=CommaInRecCtor.fs # CommaInRecCtor.fs - SOURCE=MissingCommaInCtor.fs # MissingCommaInCtor.fs - SOURCE=MissingCtorValue.fs # MissingCtorValue.fs - SOURCE=ExtraArgumentInCtor.fs # ExtraArgumentInCtor.fs - SOURCE=ExtraArgumentInCtor2.fs # ExtraArgumentInCtor2.fs - SOURCE=ValidCommaInRecCtor.fs # ValidCommaInRecCtor.fs SOURCE=FS0988AtEndOfFile.fs # FS0988AtEndOfFile.fs - SOURCE=WrongArity.fs # WrongArity.fs - SOURCE=OverrideErrors.fs # OverrideErrors.fs - SOURCE=MethodIsNotStatic.fs # MethodIsNotStatic.fs - SOURCE=AccessOfTypeAbbreviation.fs # AccessOfTypeAbbreviation.fs - SOURCE=AccessOfTypeAbbreviation2.fs # AccessOfTypeAbbreviation2.fs - SOURCE=AccessOfTypeAbbreviation3.fs # AccessOfTypeAbbreviation3.fs - SOURCE=AccessOfTypeAbbreviation4.fs # AccessOfTypeAbbreviation4.fs - SOURCE=AccessOfTypeAbbreviation5.fs # AccessOfTypeAbbreviation5.fs - SOURCE=AccessOfTypeAbbreviation6.fs # AccessOfTypeAbbreviation6.fs SOURCE=EqualsInsteadOfInInForLoop.fs # EqualsInsteadOfInInForLoop.fs SOURCE=DontWarnExternalFunctionAsUnused.fs SCFLAGS="--warnon:1182 --warnaserror+" # DontWarnExternalFunctionAsUnused.fs SOURCE=SuggestTypesInModule.fs # SuggestTypesInModule.fs @@ -38,53 +16,13 @@ SOURCE=SuggestUnionCases.fs SCFLAGS="--vserrors" # SuggestUnionCases.fs SOURCE=SuggestArrayModuleFunctions.fs SCFLAGS="--vserrors" # SuggestArrayModuleFunctions.fs SOURCE=SuggestTypesInNamespace.fs # SuggestTypesInNamespace.fs - SOURCE=DontSuggestCompletelyWrongStuff.fs SCFLAGS="--vserrors" # DontSuggestCompletelyWrongStuff.fs SOURCE=SuggestTypesInNamespaceVS.fs SCFLAGS="--vserrors" # SuggestTypesInNamespaceVS.fs SOURCE=SuggestAsyncModule.fs SCFLAGS="--vserrors" # SuggestAsyncModule.fs - SOURCE=DontSuggestWhenThingsAreOpen.fs SCFLAGS="--vserrors" # DontSuggestWhenThingsAreOpen.fs SOURCE=SuggestDoubleBacktickIdentifiers.fs SCFLAGS="--vserrors" # SuggestDoubleBacktickIdentifiers.fs SOURCE=SuggestDoubleBacktickUnions.fs SCFLAGS="--vserrors" # SuggestDoubleBacktickUnions.fs - SOURCE=GuardHasWrongType.fs # GuardHasWrongType.fs - SOURCE=ElseBranchHasWrongType.fs # ElseBranchHasWrongType.fs - SOURCE=ElseBranchHasWrongType2.fs # ElseBranchHasWrongType2.fs - SOURCE=ElseBranchHasWrongType3.fs # ElseBranchHasWrongType3.fs - SOURCE=ElseBranchHasWrongType4.fs # ElseBranchHasWrongType4.fs - SOURCE=NestedElseBranchHasWrongType.fs # NestedElseBranchHasWrongType.fs - SOURCE=ElseBranchHasWrongContextType.fs # ElseBranchHasWrongContextType.fs - SOURCE=ElseBranchContextDoesntPropagateInAppl.fs # ElseBranchContextDoesntPropagateInAppl.fs - SOURCE=ElseBranchContextDoesntPropagateInAppl2.fs # ElseBranchContextDoesntPropagateInAppl2.fs - SOURCE=ElseBranchContextDoesntPropagateInForLoop.fs # ElseBranchContextDoesntPropagateInForLoop.fs - SOURCE=ElseBranchContextDoesntPropagateToLinesBeforeLastLine.fs # ElseBranchContextDoesntPropagateToLinesBeforeLastLine.fs - SOURCE=MatchingMethodWithSameNameIsNotAbstract.fs # MatchingMethodWithSameNameIsNotAbstract.fs - SOURCE=NoMatchingAbstractMethodWithSameName.fs # NoMatchingAbstractMethodWithSameName.fs SOURCE=MissingExpressionAfterLet.fs # MissingExpressionAfterLet.fs - SOURCE=AssignmentOnImmutable.fs # AssignmentOnImmutable.fs SOURCE=SuggestFieldsInCtor.fs # SuggestFieldsInCtor.fs SOURCE=FieldSuggestion.fs # FieldSuggestion.fs SOURCE=SuggestToUseIndexer.fs # SuggestToUseIndexer.fs - SOURCE=RefCellInsteadOfNot.fs # RefCellInsteadOfNot.fs - SOURCE=RefCellInsteadOfNot2.fs # RefCellInsteadOfNot2.fs - SOURCE=UpcastInsteadOfDowncast.fs # UpcastInsteadOfDowncast.fs - SOURCE=UpcastFunctionInsteadOfDowncast.fs # UpcastFunctionInsteadOfDowncast.fs - SOURCE=DowncastInsteadOfUpcast.fs # DowncastInsteadOfUpcast.fs - SOURCE=RuntimeTypeTestInPattern.fs # RuntimeTypeTestInPattern.fs - SOURCE=RuntimeTypeTestInPattern2.fs # RuntimeTypeTestInPattern2.fs - SOURCE=WarnIfExpressionResultUnused.fs # WarnIfExpressionResultUnused.fs - SOURCE=MemberHasMultiplePossibleDispatchSlots.fs # MemberHasMultiplePossibleDispatchSlots.fs SOURCE=Repro1548.fs SCFLAGS="-r:Repro1548.dll" # Repro1548.fs - SOURCE=WarnIfPossibleAssignment.fs - SOURCE=WarnIfPossibleAssignmentToMutable.fs - SOURCE=WarnIfPossibleDotNetPropertySetter.fs - SOURCE=DontWarnIfPropertyWithoutSetter.fs - SOURCE=WarnIfImplicitlyDiscarded.fs - SOURCE=version46/WarnIfDiscardedInList.fs SCFLAGS="--langversion:4.6" #version46/WarnIfDiscardedInList - SOURCE=version46/WarnIfDiscardedInList2.fs SCFLAGS="--langversion:4.6" #version46/WarnIfDiscardedInList2 - SOURCE=version46/WarnIfDiscardedInList3.fs SCFLAGS="--langversion:4.6" #version46/WarnIfDiscardedInList3 - SOURCE=version47/WarnIfDiscardedInList.fs #version47/WarnIfDiscardedInList - SOURCE=version47/WarnIfDiscardedInList2.fs #version47/WarnIfDiscardedInList2 - SOURCE=version47/WarnIfDiscardedInList3.fs #version47/WarnIfDiscardedInList3 - SOURCE=WarnOnlyOnLastExpression.fs - SOURCE=WarnIfPossiblePropertySetter.fs - SOURCE=DoCannotHaveVisibilityDeclarations.fs SOURCE=ModuleAbbreviationsArePrivate.fs - SOURCE=DontSuggestIntentionallyUnusedVariables.fs SCFLAGS="--vserrors" # DontSuggestIntentionallyUnusedVariables.fs diff --git a/tests/fsharpqa/Source/test.lst b/tests/fsharpqa/Source/test.lst index 58ca9df397e..0ee3f28866d 100644 --- a/tests/fsharpqa/Source/test.lst +++ b/tests/fsharpqa/Source/test.lst @@ -267,7 +267,6 @@ Misc01 Libraries\Core\Operators Misc01 Libraries\Core\Reflection Misc01 Libraries\Core\Unchecked Misc01 Warnings -Misc01 ErrorMessages\NameResolution Misc01 ErrorMessages\UnitGenericAbstractType Misc01 ErrorMessages\ConfusingTypeName diff --git a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.QuickInfo.fs b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.QuickInfo.fs index 16d2f34a4e8..09f358678df 100644 --- a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.QuickInfo.fs +++ b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.QuickInfo.fs @@ -762,7 +762,7 @@ Full name: Microsoft.FSharp.Control.Async""".TrimStart().Replace("\r\n", "\n") let fileContents = """namespace NS type Re(*MarkerRecord*) = { X : int } """ - let expectedQuickinfoTypeRecored = "type Re = {X: int;}" + let expectedQuickinfoTypeRecored = "type Re = { X: int }" this.InfoInDeclarationTestQuickInfoImplWithTrim fileContents "Re(*MarkerRecord*)" expectedQuickinfoTypeRecored diff --git a/vsintegration/tests/UnitTests/QuickInfoTests.fs b/vsintegration/tests/UnitTests/QuickInfoTests.fs index bfa6c7df729..415079942e7 100644 --- a/vsintegration/tests/UnitTests/QuickInfoTests.fs +++ b/vsintegration/tests/UnitTests/QuickInfoTests.fs @@ -154,9 +154,9 @@ module Test = let quickInfo = GetQuickInfoTextFromCode code let expected = expectedLines [ "type MyEmployee =" - " {mutable Name: string;" - " mutable Age: int;" - " mutable IsFTE: bool;}" + " { mutable Name: string" + " mutable Age: int" + " mutable IsFTE: bool }" "Full name: FsTest.MyEmployee" ] Assert.AreEqual(expected, quickInfo) ()