diff --git a/.config/service-branch-merge.json b/.config/service-branch-merge.json
index 9eaf6479d45..ec35ec5bcb5 100644
--- a/.config/service-branch-merge.json
+++ b/.config/service-branch-merge.json
@@ -1,12 +1,16 @@
{
"merge-flow-configurations": {
// regular branch flow
+ "release/dev17.12": {
+ "MergeToBranch": "release/dev17.13",
+ "ExtraSwitches": "-QuietComments"
+ },
"release/dev17.13": {
- "MergeToBranch": "main",
+ "MergeToBranch": "release/dev17.14",
"ExtraSwitches": "-QuietComments"
},
"release/dev17.14": {
- "MergeToBranch": "release/dev18.0",
+ "MergeToBranch": "main",
"ExtraSwitches": "-QuietComments"
},
"main": {
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 47927f1f370..db23964cc66 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,12 +1,12 @@
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
{
"name": "F#",
- "image": "mcr.microsoft.com/dotnet/sdk:9.0.202",
+ "image": "mcr.microsoft.com/dotnet/sdk:10.0.100-preview.3",
"features": {
- "ghcr.io/devcontainers/features/common-utils:2.5.2": {},
- "ghcr.io/devcontainers/features/git:1.3.2": {},
- "ghcr.io/devcontainers/features/github-cli:1.0.13": {},
- "ghcr.io/devcontainers/features/dotnet:2.2.0": {}
+ "ghcr.io/devcontainers/features/common-utils:2.5.3": {},
+ "ghcr.io/devcontainers/features/git:1.3.3": {},
+ "ghcr.io/devcontainers/features/github-cli:1.0.14": {},
+ "ghcr.io/devcontainers/features/dotnet:2.2.1": {}
},
"hostRequirements": {
"cpus": 2,
diff --git a/.github/workflows/add_to_project.yml b/.github/workflows/add_to_project.yml
index 68e5cc454f2..67df3f58a1f 100644
--- a/.github/workflows/add_to_project.yml
+++ b/.github/workflows/add_to_project.yml
@@ -16,7 +16,7 @@ permissions:
jobs:
cleanup_old_runs:
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
if: github.event_name != 'pull_request_target'
permissions:
actions: write
diff --git a/.github/workflows/commands.yml b/.github/workflows/commands.yml
index 72fa71e6e9c..01203a6c562 100644
--- a/.github/workflows/commands.yml
+++ b/.github/workflows/commands.yml
@@ -14,7 +14,7 @@ permissions:
jobs:
cleanup_old_runs:
if: github.event.schedule == '0 13 * * *'
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
permissions:
actions: write
env:
@@ -33,7 +33,7 @@ jobs:
run_command:
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/run')
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- name: Extract command to run
uses: actions/github-script@v3
@@ -76,13 +76,61 @@ jobs:
if: steps.command-extractor.outputs.result == 'fantomas'
id: fantomas
run: dotnet fantomas . -r
- - name: Process fantomas command
+ - name: Process xlf command
if: steps.command-extractor.outputs.result == 'xlf'
id: xlf
run: dotnet build src/Compiler /t:UpdateXlf
+ - name: Post ilverify start comment
+ if: steps.command-extractor.outputs.result == 'ilverify'
+ uses: actions/github-script@v3
+ with:
+ script: |
+ const body = `Started to run ilverify baseline update`;
+ await github.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: body
+ });
+
+ - name: Process ilverify command (Update ILVerify baselines)
+ if: steps.command-extractor.outputs.result == 'ilverify'
+ id: ilverify
+ env:
+ TEST_UPDATE_BSL: 1
+ run: |
+ # Run the ilverify script with TEST_UPDATE_BSL=1
+ pwsh tests/ILVerify/ilverify.ps1
+
+ # Calculate the changes per file
+ echo "Checking for changes in baseline files..."
+ FILES_CHANGED=0
+ CHANGES_OUTPUT=""
+
+ for file in tests/ILVerify/*.bsl; do
+ if git diff --quiet "$file"; then
+ continue
+ else
+ FILES_CHANGED=$((FILES_CHANGED + 1))
+ LINES_CHANGED=$(git diff --numstat "$file" | awk '{print $1 + $2}')
+ CHANGES_OUTPUT="${CHANGES_OUTPUT}${file}: ${LINES_CHANGED} lines changed\n"
+ fi
+ done
+
+ if [ "$FILES_CHANGED" -eq 0 ]; then
+ echo "result=The ilverify command ran and did not modify any baseline." >> $GITHUB_OUTPUT
+ else
+ echo -e "result=The ilverify command ran and triggered the following number of changes per file:\n${CHANGES_OUTPUT}" >> $GITHUB_OUTPUT
+ fi
- name: Commit and push changes
- if: steps.fantomas.outcome == 'success' || steps.xlf.outcome == 'success'
+ if: steps.fantomas.outcome == 'success' || steps.xlf.outcome == 'success' || steps.ilverify.outcome == 'success'
run: |
+ # Only commit if there are actual changes
+ if git diff --quiet; then
+ echo "No changes to commit, skipping."
+ exit 0
+ fi
+
git config --local user.name "github-actions[bot]"
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
git commit -a -m 'Automated command ran: ${{ steps.command-extractor.outputs.result }}
@@ -90,7 +138,7 @@ jobs:
Co-authored-by: ${{ github.event.comment.user.login }} <${{ github.event.comment.user.id }}+${{ github.event.comment.user.login }}@users.noreply.github.com>'
git push
- name: Post command comment
- if: steps.fantomas.outcome == 'success' || steps.xlf.outcome == 'success'
+ if: steps.fantomas.outcome == 'success' || steps.xlf.outcome == 'success' || steps.ilverify.outcome == 'success'
uses: actions/github-script@v3
with:
script: |
@@ -98,8 +146,10 @@ jobs:
var output = ""
if ("${{steps.command-extractor.outputs.result}}" == 'fantomas') {
output = "${{steps.fantomas.outputs.result}}"
- } else if("${{steps.command-extractor.outputs.result}}" == 'xlf') {
+ } else if ("${{steps.command-extractor.outputs.result}}" == 'xlf') {
output = "${{steps.xlf.outputs.result}}"
+ } else if ("${{steps.command-extractor.outputs.result}}" == 'ilverify') {
+ output = "${{steps.ilverify.outputs.result}}"
}
const body = `Ran ${{ steps.command-extractor.outputs.result }}: https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${process.env.GITHUB_RUN_ID}\n${output}`;
await github.issues.createComment({
diff --git a/NuGet.config b/NuGet.config
index 48c5b72a3d8..4e7dd1d4e5e 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -8,6 +8,7 @@
+
@@ -19,6 +20,8 @@
+
+
diff --git a/README.md b/README.md
index 0def09e17fe..e5fde71496f 100644
--- a/README.md
+++ b/README.md
@@ -132,3 +132,13 @@ If you're curious about F# itself, check out these links:
* [Get started with F#](https://learn.microsoft.com/dotnet/fsharp/get-started/)
* [F# Software Foundation](https://fsharp.org)
* [F# Testimonials](https://fsharp.org/testimonials)
+
+## Contributors ✨
+
+F# exists because of these wonderful people:
+
+
+
+
+
+Made with [contrib.rocks](https://contrib.rocks).
diff --git a/azure-pipelines-PR.yml b/azure-pipelines-PR.yml
index bf59708bdb1..cc88c091482 100644
--- a/azure-pipelines-PR.yml
+++ b/azure-pipelines-PR.yml
@@ -14,7 +14,7 @@ trigger:
- docs/*
- .vscode/*
- .devcontainer/*
- - tests/scripts/
+ - tests/scripts/*
- attributions.md
- CODE_OF_CONDUCT.md
- DEVGUIDE.md
@@ -306,11 +306,13 @@ stages:
name: $(DncEngPublicBuildPool)
demands: ImageOverride -equals $(WindowsMachineQueueName)
timeoutInMinutes: 120
+ strategy:
+ parallel: 4
steps:
- checkout: self
clean: true
- - script: eng\CIBuild.cmd -compressallmetadata -buildnorealsig -testDesktop -configuration Release
+ - script: eng\CIBuild.cmd -compressallmetadata -buildnorealsig -testDesktop -configuration Release -testBatch $(System.JobPositionInPhase)
env:
DOTNET_DbgEnableMiniDump: 1
DOTNET_DbgMiniDumpType: 3 # Triage dump, 1 for mini, 2 for Heap, 3 for triage, 4 for full. Don't use 4 unless you know what you're doing.
@@ -318,9 +320,18 @@ stages:
NativeToolsOnMachine: true
displayName: Build
+ - task: PublishTestResults@2
+ displayName: Publish Test Results
+ inputs:
+ testResultsFormat: 'XUnit'
+ testRunTitle: WindowsNoRealsig_testDesktop batch $(System.JobPositionInPhase)
+ mergeTestResults: true
+ testResultsFiles: '*.xml'
+ searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/Release'
+ continueOnError: true
- task: PublishBuildArtifacts@1
displayName: Publish Build BinLog
- condition: always()
+ condition: eq(variables['System.JobPositionInPhase'], 1)
continueOnError: true
inputs:
PathToPublish: '$(Build.SourcesDirectory)\artifacts\log/Release\Build.VisualFSharp.sln.binlog'
@@ -333,7 +344,7 @@ stages:
continueOnError: true
inputs:
PathToPublish: '$(Build.SourcesDirectory)\artifacts\log\Release'
- ArtifactName: 'Windows Release WindowsNoRealsig_testDesktop process dumps'
+ ArtifactName: 'Windows Release WindowsNoRealsig_testDesktop process dumps $(System.JobPositionInPhase)'
ArtifactType: Container
parallel: true
@@ -429,55 +440,36 @@ stages:
demands: ImageOverride -equals $(WindowsMachineQueueName)
timeoutInMinutes: 120
strategy:
- maxParallel: 5
matrix:
- desktop_release:
- _configuration: Release
- _testKind: testDesktop
coreclr_release:
_configuration: Release
_testKind: testCoreclr
+ transparentCompiler: # Empty display name part.
fsharpqa_release:
_configuration: Release
_testKind: testFSharpQA
+ transparentCompiler:
vs_release:
_configuration: Release
_testKind: testVs
+ setupVsHive: true
+ transparentCompiler:
transparent_compiler_release:
_configuration: Release
_testKind: testCoreclr
-
- ${{ if eq(variables['Build.Reason'], 'Flaky, disabled, was PullRequest') }}:
- inttests_release:
- _configuration: Release
- _testKind: testIntegration
+ TEST_TRANSPARENT_COMPILER: 1 # Pipeline variable will map to env var.
+ transparentCompiler: TransparentCompiler
+ # inttests_release:
+ # _configuration: Release
+ # _testKind: testIntegration
+ # setupVsHive: true
steps:
- checkout: self
clean: true
- powershell: eng\SetupVSHive.ps1
displayName: Setup VS Hive
- condition: or(eq(variables['_testKind'], 'testVs'), eq(variables['_testKind'], 'testIntegration'))
-
- # yes, this is miserable, but - https://github.com/dotnet/arcade/issues/13239
- - script: eng\CIBuild.cmd -compressallmetadata -configuration $(_configuration) -$(_testKind)
- env:
- DOTNET_DbgEnableMiniDump: 1
- DOTNET_DbgMiniDumpType: 3 # Triage dump, 1 for mini, 2 for Heap, 3 for triage, 4 for full. Don't use 4 unless you know what you're doing.
- DOTNET_DbgMiniDumpName: $(Build.SourcesDirectory)\artifacts\log\$(_configuration)\$(Build.BuildId)-%e-%p-%t.dmp
- NativeToolsOnMachine: true
- displayName: Build / Test
- condition: and( ne(variables['_testKind'], 'testIntegration'), ne(variables['System.JobName'], 'transparent_compiler_release') )
-
- - script: eng\CIBuild.cmd -compressallmetadata -configuration $(_configuration) -$(_testKind)
- env:
- DOTNET_DbgEnableMiniDump: 1
- DOTNET_DbgMiniDumpType: 3 # Triage dump, 1 for mini, 2 for Heap, 3 for triage, 4 for full. Don't use 4 unless you know what you're doing.
- DOTNET_DbgMiniDumpName: $(Build.SourcesDirectory)\artifacts\log\$(_configuration)\$(Build.BuildId)-%e-%p-%t.dmp
- TEST_TRANSPARENT_COMPILER: 1
- NativeToolsOnMachine: true
- displayName: Build / Test Transparent Compiler
- condition: and( eq(variables['System.JobName'], 'transparent_compiler_release'), ne(variables['_testKind'], 'testIntegration') )
+ condition: eq(variables.setupVsHive, 'true')
- script: eng\CIBuild.cmd -compressallmetadata -configuration $(_configuration) -$(_testKind)
env:
@@ -485,15 +477,13 @@ stages:
DOTNET_DbgMiniDumpType: 3 # Triage dump, 1 for mini, 2 for Heap, 3 for triage, 4 for full. Don't use 4 unless you know what you're doing.
DOTNET_DbgMiniDumpName: $(Build.SourcesDirectory)\artifacts\log\$(_configuration)\$(Build.BuildId)-%e-%p-%t.dmp
NativeToolsOnMachine: true
- displayName: Build / Integration Test
- continueOnError: true
- condition: eq(variables['_testKind'], 'testIntegration')
+ displayName: Build and Test $(_testKind) $(transparentCompiler)
- task: PublishTestResults@2
displayName: Publish Test Results
inputs:
testResultsFormat: 'XUnit'
- testRunTitle: WindowsCompressedMetadata $(_testKind)
+ testRunTitle: WindowsCompressedMetadata $(_testKind) $(transparentCompiler)
mergeTestResults: true
testResultsFiles: '*.xml'
searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_configuration)'
@@ -505,7 +495,7 @@ stages:
continueOnError: true
inputs:
PathToPublish: '$(Build.SourcesDirectory)\artifacts\log/$(_configuration)\Build.VisualFSharp.sln.binlog'
- ArtifactName: 'Windows $(_configuration) $(_testKind) test binlogs'
+ ArtifactName: Windows $(_configuration) $(_testKind) $(transparentCompiler) test binlogs
ArtifactType: Container
parallel: true
- task: PublishBuildArtifacts@1
@@ -521,7 +511,7 @@ stages:
displayName: Publish Test Logs
inputs:
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\TestResults\$(_configuration)'
- ArtifactName: 'Windows $(_configuration) $(_testKind) test logs'
+ ArtifactName: Windows $(_configuration) $(_testKind) $(transparentCompilerSuffix) test logs
publishLocation: Container
continueOnError: true
condition: always()
@@ -537,6 +527,84 @@ stages:
continueOnError: true
condition: failed()
+ # Windows With Compressed Metadata Desktop
+ - job: WindowsCompressedMetadata_Desktop
+ variables:
+ - name: XUNIT_LOGS
+ value: $(Build.SourcesDirectory)\artifacts\TestResults\Release
+ - name: __VSNeverShowWhatsNew
+ value: 1
+ pool:
+ # The PR build definition sets this variable:
+ # WindowsMachineQueueName=Windows.vs2022.amd64.open
+ # and there is an alternate build definition that sets this to a queue that is always scouting the
+ # next preview of Visual Studio.
+ name: $(DncEngPublicBuildPool)
+ demands: ImageOverride -equals $(WindowsMachineQueueName)
+ timeoutInMinutes: 120
+ strategy:
+ parallel: 4
+
+ steps:
+ - checkout: self
+ clean: true
+
+ - script: eng\CIBuild.cmd -compressallmetadata -configuration Release -testDesktop -testBatch $(System.JobPositionInPhase)
+ env:
+ DOTNET_DbgEnableMiniDump: 1
+ DOTNET_DbgMiniDumpType: 3 # Triage dump, 1 for mini, 2 for Heap, 3 for triage, 4 for full. Don't use 4 unless you know what you're doing.
+ DOTNET_DbgMiniDumpName: $(Build.SourcesDirectory)\artifacts\log\Release\$(Build.BuildId)-%e-%p-%t.dmp
+ NativeToolsOnMachine: true
+ displayName: Build / Test
+
+ - task: PublishTestResults@2
+ displayName: Publish Test Results
+ inputs:
+ testResultsFormat: 'XUnit'
+ testRunTitle: WindowsCompressedMetadata testDesktop batch $(System.JobPositionInPhase)
+ mergeTestResults: true
+ testResultsFiles: '*.xml'
+ searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/Release'
+ continueOnError: true
+
+ - task: PublishBuildArtifacts@1
+ displayName: Publish BinLog
+ condition: eq(variables['System.JobPositionInPhase'], 1)
+ continueOnError: true
+ inputs:
+ PathToPublish: '$(Build.SourcesDirectory)\artifacts\log/Release\Build.VisualFSharp.sln.binlog'
+ ArtifactName: 'Windows testDesktop binlogs'
+ ArtifactType: Container
+ parallel: true
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Dumps
+ condition: failed()
+ continueOnError: true
+ inputs:
+ PathToPublish: '$(Build.SourcesDirectory)\artifacts\log\Release'
+ ArtifactName: 'Windows testDesktop process dumps $(System.JobPositionInPhase)'
+ ArtifactType: Container
+ parallel: true
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Test Logs
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\TestResults\Release'
+ ArtifactName: 'Windows testDesktop test logs batch $(System.JobPositionInPhase)'
+ publishLocation: Container
+ continueOnError: true
+ condition: always()
+ - script: dotnet build $(Build.SourcesDirectory)/eng/DumpPackageRoot/DumpPackageRoot.csproj
+ displayName: Dump NuGet cache contents
+ condition: failed()
+ - task: PublishBuildArtifacts@1
+ displayName: Publish NuGet cache contents
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\NugetPackageRootContents'
+ ArtifactName: 'NuGetPackageContents Windows testDesktop $(System.JobPositionInPhase)'
+ publishLocation: Container
+ continueOnError: true
+ condition: failed()
+
# Mock official build
- job: MockOfficial
pool:
diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md
new file mode 100644
index 00000000000..067a9d56800
--- /dev/null
+++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md
@@ -0,0 +1,7 @@
+### Fixed
+
+* Fix parsing errors using anonymous records and units of measures ([PR #18543](https://github.com/dotnet/fsharp/pull/18543))
+* Fixed: Allow `return`, `return!`, `yield`, `yield!` type annotations without parentheses ([PR #18533](https://github.com/dotnet/fsharp/pull/18533))
+* Allow `let!` and `use!` type annotations without requiring parentheses ([PR #18508](https://github.com/dotnet/fsharp/pull/18508))
+* Fix find all references for F# exceptions ([PR #18565](https://github.com/dotnet/fsharp/pull/18565))
+* Shorthand lambda: fix completion for chained calls and analysis for unfinished expression ([PR #18560](https://github.com/dotnet/fsharp/pull/18560))
diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md
index 16f5721e22a..a5341551395 100644
--- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md
+++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md
@@ -16,7 +16,7 @@
* Unsafe downcast from `obj` to generic `T` no longer requires `not null` constraint on `T`([Issue #18275](https://github.com/dotnet/fsharp/issues/18275), [PR #18343](https://github.com/dotnet/fsharp/pull/18343))
* Fix "type inference problem too complicated" for SRTP with T:null and T:struct dummy constraint([Issue #18288](https://github.com/dotnet/fsharp/issues/18288), [PR #18345](https://github.com/dotnet/fsharp/pull/18345))
* Fix for missing parse diagnostics in TransparentCompiler.ParseAndCheckProject ([PR #18366](https://github.com/dotnet/fsharp/pull/18366))
-* Miscellanous parentheses analyzer fixes. ([PR #18350](https://github.com/dotnet/fsharp/pull/18350))
+* Miscellanous parentheses analyzer fixes. ([PR #18350](https://github.com/dotnet/fsharp/pull/18350), [PR #18534](https://github.com/dotnet/fsharp/pull/18534))
* Fix duplicate parse error reporting for GetBackgroundCheckResultsForFileInProject ([Issue #18379](https://github.com/dotnet/fsharp/issues/18379) [PR #18380](https://github.com/dotnet/fsharp/pull/18380))
* Fix MethodDefNotFound when compiling code invoking delegate with option parameter ([Issue #5171](https://github.com/dotnet/fsharp/issues/5171), [PR #18385](https://github.com/dotnet/fsharp/pull/18385))
* Fix #r nuget ..." downloads unneeded packages ([Issue #18231](https://github.com/dotnet/fsharp/issues/18231), [PR #18393](https://github.com/dotnet/fsharp/pull/18393))
@@ -25,7 +25,14 @@
* Fixed [#18433](https://github.com/dotnet/fsharp/issues/18433), a rare case of an internal error in xml comment processing. ([PR #18436](https://github.com/dotnet/fsharp/pull/18436))
* Fix confusing type inference error in task expression ([Issue #13789](https://github.com/dotnet/fsharp/issues/13789), [PR #18450](https://github.com/dotnet/fsharp/pull/18450))
* Fix missing `null` highlighting in tooltips ([PR #18457](https://github.com/dotnet/fsharp/pull/18457))
+* Fix range of SynPat.Named doesn't include accessibility ([PR #18526](https://github.com/dotnet/fsharp/pull/18526))
+* Allow `_` in `use!` bindings values (lift FS1228 restriction) ([PR #18487](https://github.com/dotnet/fsharp/pull/18487))
* Make `[]` combination work([PR #18444](https://github.com/dotnet/fsharp/pull/18444/))
+* Fix code completion considers types from own namespace non-imported ([PR #18518](https://github.com/dotnet/fsharp/issues/18518))
+* Code completion: fix getting qualifier expression in do statements in type decls ([PR #18524](https://github.com/dotnet/fsharp/pull/18524))
+* Fix parsing errors using anonymous records and units of measures ([PR #18543](https://github.com/dotnet/fsharp/pull/18543))
+* Fixed: [#18441](https://github.com/dotnet/fsharp/issues/18441) FSI multi-emit unstable. ([PR #18465](https://github.com/dotnet/fsharp/pull/18465))
+* Fixed: Allow `return`, `return!`, `yield`, `yield!` type annotations without parentheses ([PR #18533](https://github.com/dotnet/fsharp/pull/18533))
### Added
* Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241))
@@ -37,7 +44,8 @@
* Type parameter constraint `null` in generic code will now automatically imply `not struct` ([Issue #18320](https://github.com/dotnet/fsharp/issues/18320), [PR #18323](https://github.com/dotnet/fsharp/pull/18323))
* Add a switch to determine whether to generate a default implementation body for overridden method when completing. [PR #18341](https://github.com/dotnet/fsharp/pull/18341)
* Use a more accurate range for CE Combine methods. [PR #18394](https://github.com/dotnet/fsharp/pull/18394)
-
+* Enable TypeSubsumptionCache for IDE use. [PR #18499](https://github.com/dotnet/fsharp/pull/18499)
+* Scoped Nowarn: Add the #warnon compiler directive ([Language suggestion #278](https://github.com/fsharp/fslang-suggestions/issues/278), [RFC FS-1146 PR](https://github.com/fsharp/fslang-design/pull/782), [PR #18049](https://github.com/dotnet/fsharp/pull/18049))
### Changed
* FSharpCheckFileResults.ProjectContext.ProjectOptions will not be available when using the experimental Transparent Compiler feature. ([PR #18205](https://github.com/dotnet/fsharp/pull/18205))
@@ -48,6 +56,7 @@
* Warning for "useless null handling" works with piped syntax constructs now ([PR #18331](https://github.com/dotnet/fsharp/pull/18331))
* Make indent in generated overridden member code depend on the context, not fix to 4. ([PR #18341](https://github.com/dotnet/fsharp/pull/18341))
* Adjust caller info attribute error message range ([PR #18388](https://github.com/dotnet/fsharp/pull/18388))
+* Make attribute targets mismatch a warning and not an error ([PR #18492](https://github.com/dotnet/fsharp/pull/18492))
### Breaking Changes
* Struct unions with overlapping fields now generate mappings needed for reading via reflection ([Issue #18121](https://github.com/dotnet/fsharp/issues/17797), [PR #18274](https://github.com/dotnet/fsharp/pull/17877))
diff --git a/docs/release-notes/.FSharp.Core/10.0.100.md b/docs/release-notes/.FSharp.Core/10.0.100.md
new file mode 100644
index 00000000000..1dc471ef118
--- /dev/null
+++ b/docs/release-notes/.FSharp.Core/10.0.100.md
@@ -0,0 +1,9 @@
+### Fixed
+
+### Added
+
+### Changed
+
+* Random functions support for zero element chosen/sampled ([PR #18568](https://github.com/dotnet/fsharp/pull/18568))
+
+### Breaking Changes
\ No newline at end of file
diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md
index 905e086a163..687402597c5 100644
--- a/docs/release-notes/.Language/preview.md
+++ b/docs/release-notes/.Language/preview.md
@@ -4,7 +4,11 @@
* Deprecate places where `seq` can be omitted. ([Language suggestion #1033](https://github.com/fsharp/fslang-suggestions/issues/1033), [PR #17772](https://github.com/dotnet/fsharp/pull/17772))
* Added type conversions cache, only enabled for compiler runs ([PR#17668](https://github.com/dotnet/fsharp/pull/17668))
* Support ValueOption + Struct attribute as optional parameter for methods ([Language suggestion #1136](https://github.com/fsharp/fslang-suggestions/issues/1136), [PR #18098](https://github.com/dotnet/fsharp/pull/18098))
+* Allow `_` in `use!` bindings values (lift FS1228 restriction) ([PR #18487](https://github.com/dotnet/fsharp/pull/18487))
* Warn when `unit` is passed to an `obj`-typed argument ([PR #18330](https://github.com/dotnet/fsharp/pull/18330))
+* Fix parsing errors using anonymous records and units of measures ([PR #18543](https://github.com/dotnet/fsharp/pull/18543))
+* Scoped Nowarn: added the #warnon compiler directive ([Language suggestion #278](https://github.com/fsharp/fslang-suggestions/issues/278), [RFC FS-1146 PR](https://github.com/fsharp/fslang-design/pull/782), [PR #18049](https://github.com/dotnet/fsharp/pull/18049))
+* Allow `let!` and `use!` type annotations without requiring parentheses. ([PR #18508](https://github.com/dotnet/fsharp/pull/18508))
### Fixed
diff --git a/eng/Build.ps1 b/eng/Build.ps1
index 146372ecde6..fe2fe5731bd 100644
--- a/eng/Build.ps1
+++ b/eng/Build.ps1
@@ -73,6 +73,7 @@ param (
[switch]$compressAllMetadata,
[switch]$buildnorealsig = $true,
[switch]$verifypackageshipstatus = $false,
+ [string]$testBatch = "",
[parameter(ValueFromRemainingArguments = $true)][string[]]$properties)
Set-StrictMode -version 2.0
@@ -356,16 +357,24 @@ function VerifyAssemblyVersionsAndSymbols() {
}
}
-function TestUsingMSBuild([string] $testProject, [string] $targetFramework, [string]$testadapterpath, [boolean] $asBackgroundJob = $false, [string] $settings = "") {
+function TestUsingMSBuild([string] $testProject, [string] $targetFramework, [string] $settings = "") {
+
$dotnetPath = InitializeDotNetCli
$dotnetExe = Join-Path $dotnetPath "dotnet.exe"
$projectName = [System.IO.Path]::GetFileNameWithoutExtension($testProject)
+
+ $testBatchSuffix = ""
+ if ($testBatch) {
+ $testBatchSuffix = "_batch$testBatch"
+ }
+
# {assembly} and {framework} will expand respectively. See https://github.com/spekt/testlogger/wiki/Logger-Configuration#logfilepath
# This is useful to deconflict log filenames when there are many test assemblies, e.g. when testing a whole solution.
- $testLogPath = "$ArtifactsDir\TestResults\$configuration\{assembly}_{framework}.xml"
- $testBinLogPath = "$LogDir\${projectName}_$targetFramework.binlog"
- $args = "test $testProject -c $configuration -f $targetFramework -v n --test-adapter-path $testadapterpath --logger ""xunit;LogFilePath=$testLogPath"" /bl:$testBinLogPath"
- $args += " --blame --blame-hang-timeout 5minutes --results-directory $ArtifactsDir\TestResults\$configuration -p:vstestusemsbuildoutput=true"
+ $testLogPath = "$ArtifactsDir\TestResults\$configuration\{assembly}_{framework}$testBatchSuffix.xml"
+
+ $testBinLogPath = "$LogDir\${projectName}_$targetFramework$testBatch.binlog"
+ $args = "test $testProject -c $configuration -f $targetFramework --logger ""xunit;LogFilePath=$testLogPath"" /bl:$testBinLogPath"
+ $args += " --blame-hang-timeout 5minutes --results-directory $ArtifactsDir\TestResults\$configuration"
if (-not $noVisualStudio -or $norestore) {
$args += " --no-restore"
@@ -376,22 +385,12 @@ function TestUsingMSBuild([string] $testProject, [string] $targetFramework, [str
}
$args += " $settings"
-
- if ($asBackgroundJob) {
- Write-Host
- Write-Host("Starting on the background: $args")
- Write-Host("------------------------------------")
- Start-Job -ScriptBlock {
- $argArray = $using:args -Split " "
- & $using:dotnetExe $argArray
- if ($LASTEXITCODE -ne 0) {
- throw "Command failed to execute with exit code $($LASTEXITCODE): $using:dotnetExe $using:args"
- }
- }
- } else {
- Write-Host("$args")
- Exec-Console $dotnetExe $args
+ if ($testBatch) {
+ $args += " --filter batch=$testBatch"
}
+
+ Write-Host("$args")
+ Exec-Console $dotnetExe $args
}
function Prepare-TempDir() {
@@ -595,34 +594,12 @@ try {
$script:BuildCategory = "Test"
$script:BuildMessage = "Failure running tests"
- function Receive($job) {
- while($job.HasMoreData) {
- Receive-Job $job | Write-Host
- Start-Sleep -Seconds 1
- }
- Receive-Job $job -Wait -ErrorAction Stop
- }
-
if ($testCoreClr) {
- $cpuLimit = if ($ci) { "-m:1 -- xUnit.MaxParallelThreads=1" } else { "" }
- TestUsingMSBuild -testProject "$RepoRoot\FSharp.sln" -targetFramework $script:coreclrTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.ComponentTests\" -settings $cpuLimit
+ TestUsingMSBuild -testProject "$RepoRoot\FSharp.sln" -targetFramework $script:coreclrTargetFramework
}
- if ($testDesktop -and $ci) {
- $bgJob = TestUsingMSBuild -testProject "$RepoRoot\tests\fsharp\FSharpSuite.Tests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharpSuite.Tests\" -asBackgroundJob $true
-
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Test.Utilities\FSharp.Test.Utilities.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Test.Utilities\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.ComponentTests\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.Service.Tests\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Private.Scripting.UnitTests\FSharp.Compiler.Private.Scripting.UnitTests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.Private.Scripting.UnitTests\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Build.UnitTests\FSharp.Build.UnitTests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Build.UnitTests\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Core.UnitTests\FSharp.Core.UnitTests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Core.UnitTests\"
-
- Receive -job $bgJob
- }
-
- if ($testDesktop -and -not $ci ) {
- TestUsingMSBuild -testProject "$RepoRoot\FSharp.sln" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.ComponentTests\"
+ if ($testDesktop) {
+ TestUsingMSBuild -testProject "$RepoRoot\FSharp.sln" -targetFramework $script:desktopTargetFramework
}
if ($testFSharpQA) {
@@ -653,50 +630,49 @@ try {
}
if ($testFSharpCore) {
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Core.UnitTests\FSharp.Core.UnitTests.fsproj" -targetFramework $script:coreclrTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Core.UnitTests\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Core.UnitTests\FSharp.Core.UnitTests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Core.UnitTests\"
+ TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Core.UnitTests\FSharp.Core.UnitTests.fsproj" -targetFramework $script:coreclrTargetFramework
+ TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Core.UnitTests\FSharp.Core.UnitTests.fsproj" -targetFramework $script:desktopTargetFramework
}
if ($testCompiler) {
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $script:coreclrTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.ComponentTests\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.ComponentTests\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj" -targetFramework $script:coreclrTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.Service.Tests\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.Service.Tests\"
+ TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $script:coreclrTargetFramework
+ TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $script:desktopTargetFramework
+ TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj" -targetFramework $script:coreclrTargetFramework
+ TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj" -targetFramework $script:desktopTargetFramework
}
if ($testCompilerComponentTests) {
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $script:coreclrTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.ComponentTests\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.ComponentTests\"
+ TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $script:coreclrTargetFramework
+ TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $script:desktopTargetFramework
}
if ($testCompilerService) {
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj" -targetFramework $script:coreclrTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.Service.Tests\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.Service.Tests\"
+ TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj" -targetFramework $script:coreclrTargetFramework
+ TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj" -targetFramework $script:desktopTargetFramework
}
if ($testCambridge) {
- TestUsingMSBuild -testProject "$RepoRoot\tests\fsharp\FSharpSuite.Tests.fsproj" -targetFramework $script:coreclrTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharpSuite.Tests\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\fsharp\FSharpSuite.Tests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharpSuite.Tests\"
+ TestUsingMSBuild -testProject "$RepoRoot\tests\fsharp\FSharpSuite.Tests.fsproj" -targetFramework $script:coreclrTargetFramework
+ TestUsingMSBuild -testProject "$RepoRoot\tests\fsharp\FSharpSuite.Tests.fsproj" -targetFramework $script:desktopTargetFramework
}
if ($testScripting) {
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Private.Scripting.UnitTests\FSharp.Compiler.Private.Scripting.UnitTests.fsproj" -targetFramework $script:coreclrTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.Private.Scripting.UnitTests\"
- TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Private.Scripting.UnitTests\FSharp.Compiler.Private.Scripting.UnitTests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Compiler.Private.Scripting.UnitTests\"
+ TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Private.Scripting.UnitTests\FSharp.Compiler.Private.Scripting.UnitTests.fsproj" -targetFramework $script:coreclrTargetFramework
+ TestUsingMSBuild -testProject "$RepoRoot\tests\FSharp.Compiler.Private.Scripting.UnitTests\FSharp.Compiler.Private.Scripting.UnitTests.fsproj" -targetFramework $script:desktopTargetFramework
}
if ($testEditor -and -not $noVisualStudio) {
- TestUsingMSBuild -testProject "$RepoRoot\vsintegration\tests\FSharp.Editor.Tests\FSharp.Editor.Tests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Editor.Tests\FSharp.Editor.Tests.fsproj"
+ TestUsingMSBuild -testProject "$RepoRoot\vsintegration\tests\FSharp.Editor.Tests\FSharp.Editor.Tests.fsproj" -targetFramework $script:desktopTargetFramework
}
if ($testVs -and -not $noVisualStudio) {
- TestUsingMSBuild -testProject "$RepoRoot\vsintegration\tests\UnitTests\VisualFSharp.UnitTests.fsproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\VisualFSharp.UnitTests\"
+ TestUsingMSBuild -testProject "$RepoRoot\vsintegration\tests\UnitTests\VisualFSharp.UnitTests.fsproj" -targetFramework $script:desktopTargetFramework
}
-
if ($testIntegration) {
- TestUsingMSBuild -testProject "$RepoRoot\vsintegration\tests\FSharp.Editor.IntegrationTests\FSharp.Editor.IntegrationTests.csproj" -targetFramework $script:desktopTargetFramework -testadapterpath "$ArtifactsDir\bin\FSharp.Editor.IntegrationTests\"
+ TestUsingMSBuild -testProject "$RepoRoot\vsintegration\tests\FSharp.Editor.IntegrationTests\FSharp.Editor.IntegrationTests.csproj" -targetFramework $script:desktopTargetFramework
}
if ($testAOT) {
diff --git a/eng/DotNetBuild.props b/eng/DotNetBuild.props
index 78286b23bab..8bdf6363873 100644
--- a/eng/DotNetBuild.props
+++ b/eng/DotNetBuild.props
@@ -1,9 +1,13 @@
+
fsharptrue
+ $(DotNetBuildOrchestrator)
+ false
+ false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 612b8e5a32f..b2e391d8775 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -2,32 +2,21 @@
-
- https://github.com/dotnet/source-build-reference-packages
- 19eb5ea4e5f9c4e5256843a92805c8c9e942207d
-
-
-
-
- https://github.com/dotnet/msbuild
- 7a09d5ee44eb217e9c1ae0bab242c79c70423577
-
-
-
+ https://github.com/dotnet/msbuild
- 7a09d5ee44eb217e9c1ae0bab242c79c70423577
+ 7ad4e1c76585d0ed6e438da2d4f9394326934399
-
+ https://github.com/dotnet/msbuild
- 7a09d5ee44eb217e9c1ae0bab242c79c70423577
+ 7ad4e1c76585d0ed6e438da2d4f9394326934399
-
+ https://github.com/dotnet/msbuild
- 7a09d5ee44eb217e9c1ae0bab242c79c70423577
+ 7ad4e1c76585d0ed6e438da2d4f9394326934399
-
+ https://github.com/dotnet/msbuild
- 7a09d5ee44eb217e9c1ae0bab242c79c70423577
+ 7ad4e1c76585d0ed6e438da2d4f9394326934399https://github.com/dotnet/runtime
@@ -43,15 +32,9 @@
-
- https://github.com/dotnet/arcade
- aa61e8c20a869bcc994f8b29eb07d927d2bec6f4
-
-
-
+ https://github.com/dotnet/arcade
- aa61e8c20a869bcc994f8b29eb07d927d2bec6f4
-
+ 086a1771875b63404b4a710d27250fe384dc2810https://dev.azure.com/dnceng/internal/_git/dotnet-optimization
diff --git a/eng/Versions.props b/eng/Versions.props
index 65fd2bf80b1..ce77d493878 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -37,7 +37,7 @@
$(FSMajorVersion).$(FSMinorVersion).$(FSBuildVersion)
- 9.0.201
+ 9.0.300$(FSCorePackageVersionValue)-$(PreReleaseVersionLabel).*
@@ -102,7 +102,7 @@
17.10.4015217.10.526-pre-g1b474069f517.10.41
- 17.13.24
+ 17.13.25$(RoslynVersion)$(RoslynVersion)
@@ -138,9 +138,9 @@
15.0.25123-Dev15Preview
- 17.13.24
- 17.13.24
- 17.13.24
+ 17.13.25
+ 17.13.25
+ 17.13.25$(VisualStudioEditorPackagesVersion)
diff --git a/eng/build.sh b/eng/build.sh
index 53de7fda4c9..07c3889f33d 100755
--- a/eng/build.sh
+++ b/eng/build.sh
@@ -76,6 +76,7 @@ prepare_machine=false
source_build=false
product_build=false
buildnorealsig=true
+testbatch=""
properties=""
docker=false
@@ -104,6 +105,11 @@ while [[ $# > 0 ]]; do
args="$args $1"
shift
;;
+ --testbatch)
+ testbatch=$2
+ args="$args $1"
+ shift
+ ;;
--verbosity|-v)
verbosity=$2
args="$args $1"
@@ -224,9 +230,17 @@ function Test() {
projectname=$(basename -- "$testproject")
projectname="${projectname%.*}"
- testlogpath="$artifacts_dir/TestResults/$configuration/${projectname}_$targetframework.xml"
- args="test \"$testproject\" --no-restore --no-build -c $configuration -f $targetframework --test-adapter-path . --logger \"xunit;LogFilePath=$testlogpath\" --blame-hang-timeout 5minutes --results-directory $artifacts_dir/TestResults/$configuration -p:vstestusemsbuildoutput=false"
- args+=" -- xUnit.MaxParallelThreads=1"
+ testbatchsuffix=""
+ if [[ "$testbatch" != "" ]]; then
+ testbatchsuffix="_batch$testbatch"
+ fi
+ testlogpath="$artifacts_dir/TestResults/$configuration/${projectname}_$targetframework$testbatchsuffix.xml"
+ args="test \"$testproject\" --no-build -c $configuration -f $targetframework --logger \"xunit;LogFilePath=$testlogpath\" --blame-hang-timeout 5minutes --results-directory $artifacts_dir/TestResults/$configuration"
+
+ if [[ "$testbatch" != "" ]]; then
+ args="$args --filter batch=$testbatch"
+ fi
+
"$DOTNET_INSTALL_DIR/dotnet" $args || exit $?
}
diff --git a/eng/common/core-templates/job/source-index-stage1.yml b/eng/common/core-templates/job/source-index-stage1.yml
index 205fb5b3a39..8b833332b3e 100644
--- a/eng/common/core-templates/job/source-index-stage1.yml
+++ b/eng/common/core-templates/job/source-index-stage1.yml
@@ -1,7 +1,7 @@
parameters:
runAsPublic: false
- sourceIndexUploadPackageVersion: 2.0.0-20240522.1
- sourceIndexProcessBinlogPackageVersion: 1.0.1-20240522.1
+ sourceIndexUploadPackageVersion: 2.0.0-20250425.2
+ sourceIndexProcessBinlogPackageVersion: 1.0.1-20250425.2
sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci"
preSteps: []
diff --git a/global.json b/global.json
index dad4b18b2fa..a85e3a5fec3 100644
--- a/global.json
+++ b/global.json
@@ -1,10 +1,10 @@
{
"sdk": {
- "version": "9.0.202",
+ "version": "10.0.100-preview.3.25201.16",
"allowPrerelease": true
},
"tools": {
- "dotnet": "9.0.202",
+ "dotnet": "10.0.100-preview.3.25201.16",
"vs": {
"version": "17.8",
"components": [
@@ -17,7 +17,7 @@
"perl": "5.38.2.2"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25208.6",
+ "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25271.1",
"Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23255.2"
}
}
diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs
index 78acf62bb98..7d8a0e0764e 100644
--- a/src/Compiler/Checking/CheckDeclarations.fs
+++ b/src/Compiler/Checking/CheckDeclarations.fs
@@ -341,7 +341,7 @@ let AddNonLocalCcu g amap scopem env assemblyName (ccu: CcuThunk, internalsVisib
env
/// Adjust the TcEnv to account for a fully processed "namespace" declaration in this file
-let AddLocalRootModuleOrNamespace tcSink g amap scopem env (moduleTy: ModuleOrNamespaceType) =
+let AddLocalRootModuleOrNamespace g amap scopem env (moduleTy: ModuleOrNamespaceType) =
// Compute the top-rooted module or namespace references
let modrefs = moduleTy.ModuleAndNamespaceDefinitions |> List.map mkLocalModuleRef
// Compute the top-rooted type definitions
@@ -350,7 +350,6 @@ let AddLocalRootModuleOrNamespace tcSink g amap scopem env (moduleTy: ModuleOrNa
let env = { env with
eNameResEnv = if isNil tcrefs then env.eNameResEnv else AddTyconRefsToNameEnv BulkAdd.No false g amap env.eAccessRights scopem true env.eNameResEnv tcrefs
eUngeneralizableItems = addFreeItemOfModuleTy moduleTy env.eUngeneralizableItems }
- CallEnvSink tcSink (scopem, env.NameEnv, env.eAccessRights)
env
/// Inside "namespace X.Y.Z" there is an implicit open of "X.Y.Z"
@@ -4978,7 +4977,7 @@ let rec TcSignatureElementNonMutRec (cenv: cenv) parent typeNames endm (env: TcE
CallNameResolutionSink cenv.tcSink (moduleEntity.Range, env.NameEnv, item, emptyTyparInst, ItemOccurrence.Binding, env.AccessRights))
// For 'namespace rec' and 'module rec' we add the thing being defined
- let envNS = if isRec then AddLocalRootModuleOrNamespace cenv.tcSink g cenv.amap m envNS modTyRoot else envNS
+ let envNS = if isRec then AddLocalRootModuleOrNamespace g cenv.amap m envNS modTyRoot else envNS
let nsInfo = Some (modulNSOpt, envNS.eModuleOrNamespaceTypeAccumulator)
let mutRecNSInfo = if isRec then nsInfo else None
@@ -4990,7 +4989,7 @@ let rec TcSignatureElementNonMutRec (cenv: cenv) parent typeNames endm (env: TcE
if isNil enclosingNamespacePath then
envAtEnd
else
- let env = AddLocalRootModuleOrNamespace cenv.tcSink g cenv.amap m env modTyRoot
+ let env = AddLocalRootModuleOrNamespace g cenv.amap m env modTyRoot
// If the namespace is an interactive fragment e.g. FSI_0002, then open FSI_0002 in the subsequent environment.
let env, _openDecls =
@@ -5440,7 +5439,7 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem
CallNameResolutionSink cenv.tcSink (moduleEntity.Range, env.NameEnv, item, emptyTyparInst, ItemOccurrence.Binding, env.AccessRights))
// For 'namespace rec' and 'module rec' we add the thing being defined
- let envNS = if isRec then AddLocalRootModuleOrNamespace cenv.tcSink g cenv.amap m envNS modTyRoot else envNS
+ let envNS = if isRec then AddLocalRootModuleOrNamespace g cenv.amap m envNS modTyRoot else envNS
let nsInfo = Some (modulNSOpt, envNS.eModuleOrNamespaceTypeAccumulator)
let mutRecNSInfo = if isRec then nsInfo else None
@@ -5453,7 +5452,7 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem
if isNil enclosingNamespacePath then
envAtEnd, []
else
- let env = AddLocalRootModuleOrNamespace cenv.tcSink g cenv.amap m env modTyRoot
+ let env = AddLocalRootModuleOrNamespace g cenv.amap m env modTyRoot
// If the namespace is an interactive fragment e.g. FSI_0002, then open FSI_0002 in the subsequent environment
let env, openDecls =
@@ -5753,7 +5752,7 @@ let CheckOneImplFile
synImplFile,
diagnosticOptions) =
- let (ParsedImplFileInput (fileName, isScript, qualNameOfFile, scopedPragmas, _, implFileFrags, isLastCompiland, _, _)) = synImplFile
+ let (ParsedImplFileInput (fileName, isScript, qualNameOfFile, _, implFileFrags, isLastCompiland, _, _)) = synImplFile
let infoReader = InfoReader(g, amap)
cancellable {
@@ -5892,7 +5891,7 @@ let CheckOneImplFile
|> Array.map (fun (KeyValue(k,v)) -> (k,v))
|> Map
- let implFile = CheckedImplFile (qualNameOfFile, scopedPragmas, implFileTy, implFileContents, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)
+ let implFile = CheckedImplFile (qualNameOfFile, implFileTy, implFileContents, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)
return (topAttrs, implFile, envAtEnd, cenv.createsGeneratedProvidedTypes)
}
diff --git a/src/Compiler/Checking/CheckDeclarations.fsi b/src/Compiler/Checking/CheckDeclarations.fsi
index fb4679f2438..9b06fcc828d 100644
--- a/src/Compiler/Checking/CheckDeclarations.fsi
+++ b/src/Compiler/Checking/CheckDeclarations.fsi
@@ -13,8 +13,7 @@ open FSharp.Compiler.TcGlobals
open FSharp.Compiler.Text
open FSharp.Compiler.TypedTree
-val AddLocalRootModuleOrNamespace:
- TcResultsSink -> TcGlobals -> ImportMap -> range -> TcEnv -> ModuleOrNamespaceType -> TcEnv
+val AddLocalRootModuleOrNamespace: TcGlobals -> ImportMap -> range -> TcEnv -> ModuleOrNamespaceType -> TcEnv
val CreateInitialTcEnv:
TcGlobals * ImportMap * range * assemblyName: string * (CcuThunk * string list * string list) list ->
diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs
index a7bcc1f9f87..0d2404c5b1a 100644
--- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs
+++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs
@@ -4,6 +4,7 @@
/// with generalization at appropriate points.
module internal FSharp.Compiler.CheckComputationExpressions
+open FSharp.Compiler.TcGlobals
open Internal.Utilities.Library
open FSharp.Compiler.AccessibilityLogic
open FSharp.Compiler.AttributeChecking
@@ -863,6 +864,20 @@ let (|ExprAsUseBang|_|) expr =
trivia = { LetOrUseBangKeyword = mBind }) -> ValueSome(spBind, isFromSource, pat, rhsExpr, andBangs, innerComp, mBind)
| _ -> ValueNone
+[]
+let (|ExprAsLetBang|_|) expr =
+ match expr with
+ | SynExpr.LetOrUseBang(
+ bindDebugPoint = spBind
+ isUse = false
+ isFromSource = isFromSource
+ pat = letPat
+ rhs = letRhsExpr
+ andBangs = andBangBindings
+ body = innerComp
+ trivia = { LetOrUseBangKeyword = mBind }) -> ValueSome(spBind, isFromSource, letPat, letRhsExpr, andBangBindings, innerComp, mBind)
+ | _ -> ValueNone
+
// "cexpr; cexpr" is treated as builder.Combine(cexpr1, cexpr1)
// This is not pretty - we have to decide which range markers we use for the calls to Combine and Delay
// NOTE: we should probably suppress these sequence points altogether
@@ -1764,62 +1779,42 @@ let rec TryTranslateComputationExpression
|> addBindDebugPoint spBind
)
- // 'let! pat = expr in expr'
- // --> build.Bind(e1, (fun _argN -> match _argN with pat -> expr))
- // or
- // --> build.BindReturn(e1, (fun _argN -> match _argN with pat -> expr-without-return))
- | SynExpr.LetOrUseBang(
- bindDebugPoint = spBind
- isUse = false
- isFromSource = isFromSource
- pat = pat
- rhs = rhsExpr
- andBangs = []
- body = innerComp
- trivia = { LetOrUseBangKeyword = mBind }) ->
-
- if ceenv.isQuery then
- error (Error(FSComp.SR.tcBindMayNotBeUsedInQueries (), mBind))
-
- // Add the variables to the query variable space, on demand
- let varSpace =
- addVarsToVarSpace varSpace (fun _mCustomOp env ->
- use _holder = TemporarilySuspendReportingTypecheckResultsToSink cenv.tcSink
-
- let _, _, vspecs, envinner, _ =
- TcMatchPattern cenv (NewInferenceType cenv.g) env ceenv.tpenv pat None TcTrueMatchClause.No
-
- vspecs, envinner)
-
- let rhsExpr =
- mkSourceExprConditional isFromSource rhsExpr ceenv.sourceMethInfo ceenv.builderValName
-
- Some(
- TranslateComputationExpressionBind
- ceenv
- comp
- q
- varSpace
- mBind
- (addBindDebugPoint spBind)
- "Bind"
- [ rhsExpr ]
- pat
- innerComp
- translatedCtxt
- )
-
// 'use! pat = e1 in e2' --> build.Bind(e1, (function _argN -> match _argN with pat -> build.Using(x, (fun _argN -> match _argN with pat -> e2))))
| ExprAsUseBang(spBind, isFromSource, pat, rhsExpr, andBangs, innerComp, mBind) ->
if ceenv.isQuery then
error (Error(FSComp.SR.tcBindMayNotBeUsedInQueries (), mBind))
- match pat, andBangs with
- | (SynPat.Named(ident = SynIdent(id, _); isThisVal = false) | SynPat.LongIdent(longDotId = SynLongIdent(id = [ id ]))), [] ->
+ match andBangs with
+ | [] ->
// Valid pattern case - handle with Using + Bind
requireBuilderMethod "Using" mBind cenv ceenv.env ceenv.ad ceenv.builderTy mBind
requireBuilderMethod "Bind" mBind cenv ceenv.env ceenv.ad ceenv.builderTy mBind
+ let supportsUseBangBindingValueDiscard =
+ ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.UseBangBindingValueDiscard
+
+ let supportsTypedLetOrUseBang =
+ ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.AllowTypedLetOrUseBang
+
+ // use! x = ...
+ // use! (x) = ...
+ // use! (__) = ...
+ // use! _ = ...
+ // use! (_) = ...
+ let rec extractIdentifierFromPattern pat =
+ match pat with
+ | SynPat.Named(ident = SynIdent(id, _); isThisVal = false) -> id, pat
+ | SynPat.LongIdent(longDotId = SynLongIdent(id = [ id ])) -> id, pat
+ | SynPat.Typed(pat = pat) when supportsTypedLetOrUseBang -> extractIdentifierFromPattern pat
+ | SynPat.Wild(m) when supportsUseBangBindingValueDiscard ->
+ // To properly call the Using(disposable) CE member, we need to convert the wildcard to a SynPat.Named
+ let tmpIdent = mkSynId m "_"
+ tmpIdent, SynPat.Named(SynIdent(tmpIdent, None), false, None, m)
+ | SynPat.Paren(pat = pat) -> extractIdentifierFromPattern pat
+ | _ -> error (Error(FSComp.SR.tcInvalidUseBangBinding (), pat.Range))
+
+ let ident, pat = extractIdentifierFromPattern pat
+
let bindExpr =
let consumeExpr =
SynExpr.MatchLambda(
@@ -1840,14 +1835,14 @@ let rec TryTranslateComputationExpression
)
let consumeExpr =
- mkSynCall "Using" mBind [ SynExpr.Ident id; consumeExpr ] ceenv.builderValName
+ mkSynCall "Using" mBind [ SynExpr.Ident ident; consumeExpr ] ceenv.builderValName
let consumeExpr =
SynExpr.MatchLambda(
false,
mBind,
[
- SynMatchClause(pat, None, consumeExpr, id.idRange, DebugPointAtTarget.No, SynMatchClauseTrivia.Zero)
+ SynMatchClause(pat, None, consumeExpr, ident.idRange, DebugPointAtTarget.No, SynMatchClauseTrivia.Zero)
],
DebugPointAtBinding.NoneAtInvisible,
mBind
@@ -1860,8 +1855,7 @@ let rec TryTranslateComputationExpression
|> addBindDebugPoint spBind
Some(translatedCtxt bindExpr)
- | _pat, [] -> error (Error(FSComp.SR.tcInvalidUseBangBinding (), mBind))
- | _pat, _ands ->
+ | _ ->
// Has andBangs
let m =
match andBangs with
@@ -1870,66 +1864,21 @@ let rec TryTranslateComputationExpression
error (Error(FSComp.SR.tcInvalidUseBangBindingNoAndBangs (), m))
+ // 'let! pat = expr in expr' -->
+ // --> build.Bind(e1, (fun _argN -> match _argN with pat -> expr))
+ // or
+ // --> build.BindReturn(e1, (fun _argN -> match _argN with pat -> expr-without-return))
// 'let! pat1 = expr1 and! pat2 = expr2 in ...' -->
// build.BindN(expr1, expr2, ...)
// or
// build.BindNReturn(expr1, expr2, ...)
// or
// build.Bind(build.MergeSources(expr1, expr2), ...)
- | SynExpr.LetOrUseBang(
- bindDebugPoint = spBind
- isUse = false
- isFromSource = isFromSource
- pat = letPat
- rhs = letRhsExpr
- andBangs = andBangBindings
- body = innerComp
- trivia = { LetOrUseBangKeyword = mBind }) ->
- if not (cenv.g.langVersion.SupportsFeature LanguageFeature.AndBang) then
- let andBangRange =
- match andBangBindings with
- | [] -> comp.Range
- | h :: _ -> h.Trivia.AndBangKeyword
-
- error (Error(FSComp.SR.tcAndBangNotSupported (), andBangRange))
-
- if ceenv.isQuery then
- error (Error(FSComp.SR.tcBindMayNotBeUsedInQueries (), mBind))
-
- let sources =
- (letRhsExpr
- :: [ for SynExprAndBang(body = andExpr) in andBangBindings -> andExpr ])
- |> List.map (fun expr -> mkSourceExprConditional isFromSource expr ceenv.sourceMethInfo ceenv.builderValName)
-
- let pats =
- letPat :: [ for SynExprAndBang(pat = andPat) in andBangBindings -> andPat ]
-
- let sourcesRange = sources |> List.map (fun e -> e.Range) |> List.reduce unionRanges
-
- let numSources = sources.Length
- let bindReturnNName = "Bind" + string numSources + "Return"
- let bindNName = "Bind" + string numSources
-
- // Check if this is a Bind2Return etc.
- let hasBindReturnN =
- not (
- isNil (
- TryFindIntrinsicOrExtensionMethInfo
- ResultCollectionSettings.AtMostOneResult
- cenv
- ceenv.env
- mBind
- ceenv.ad
- bindReturnNName
- ceenv.builderTy
- )
- )
-
- if
- hasBindReturnN
- && Option.isSome (convertSimpleReturnToExpr ceenv comp varSpace innerComp)
- then
- let consumePat = SynPat.Tuple(false, pats, [], letPat.Range)
+ | ExprAsLetBang(spBind, isFromSource, letPat, letRhsExpr, andBangBindings, innerComp, mBind) ->
+ match andBangBindings with
+ | [] ->
+ if ceenv.isQuery then
+ error (Error(FSComp.SR.tcBindMayNotBeUsedInQueries (), mBind))
// Add the variables to the query variable space, on demand
let varSpace =
@@ -1937,10 +1886,13 @@ let rec TryTranslateComputationExpression
use _holder = TemporarilySuspendReportingTypecheckResultsToSink cenv.tcSink
let _, _, vspecs, envinner, _ =
- TcMatchPattern cenv (NewInferenceType cenv.g) env ceenv.tpenv consumePat None TcTrueMatchClause.No
+ TcMatchPattern cenv (NewInferenceType cenv.g) env ceenv.tpenv letPat None TcTrueMatchClause.No
vspecs, envinner)
+ let rhsExpr =
+ mkSourceExprConditional isFromSource letRhsExpr ceenv.sourceMethInfo ceenv.builderValName
+
Some(
TranslateComputationExpressionBind
ceenv
@@ -1949,17 +1901,40 @@ let rec TryTranslateComputationExpression
varSpace
mBind
(addBindDebugPoint spBind)
- bindNName
- sources
- consumePat
+ "Bind"
+ [ rhsExpr ]
+ letPat
innerComp
translatedCtxt
)
+ | _ ->
+ if not (cenv.g.langVersion.SupportsFeature LanguageFeature.AndBang) then
+ let andBangRange =
+ match andBangBindings with
+ | [] -> comp.Range
+ | h :: _ -> h.Trivia.AndBangKeyword
- else
+ error (Error(FSComp.SR.tcAndBangNotSupported (), andBangRange))
- // Check if this is a Bind2 etc.
- let hasBindN =
+ if ceenv.isQuery then
+ error (Error(FSComp.SR.tcBindMayNotBeUsedInQueries (), mBind))
+
+ let sources =
+ (letRhsExpr
+ :: [ for SynExprAndBang(body = andExpr) in andBangBindings -> andExpr ])
+ |> List.map (fun expr -> mkSourceExprConditional isFromSource expr ceenv.sourceMethInfo ceenv.builderValName)
+
+ let pats =
+ letPat :: [ for SynExprAndBang(pat = andPat) in andBangBindings -> andPat ]
+
+ let sourcesRange = sources |> List.map (fun e -> e.Range) |> List.reduce unionRanges
+
+ let numSources = sources.Length
+ let bindReturnNName = "Bind" + string numSources + "Return"
+ let bindNName = "Bind" + string numSources
+
+ // Check if this is a Bind2Return etc.
+ let hasBindReturnN =
not (
isNil (
TryFindIntrinsicOrExtensionMethInfo
@@ -1968,12 +1943,15 @@ let rec TryTranslateComputationExpression
ceenv.env
mBind
ceenv.ad
- bindNName
+ bindReturnNName
ceenv.builderTy
)
)
- if hasBindN then
+ if
+ hasBindReturnN
+ && Option.isSome (convertSimpleReturnToExpr ceenv comp varSpace innerComp)
+ then
let consumePat = SynPat.Tuple(false, pats, [], letPat.Range)
// Add the variables to the query variable space, on demand
@@ -2001,110 +1979,152 @@ let rec TryTranslateComputationExpression
translatedCtxt
)
else
+ // Check if this is a Bind2 etc.
+ let hasBindN =
+ not (
+ isNil (
+ TryFindIntrinsicOrExtensionMethInfo
+ ResultCollectionSettings.AtMostOneResult
+ cenv
+ ceenv.env
+ mBind
+ ceenv.ad
+ bindNName
+ ceenv.builderTy
+ )
+ )
- // Look for the maximum supported MergeSources, MergeSources3, ...
- let mkMergeSourcesName n =
- if n = 2 then
- "MergeSources"
- else
- "MergeSources" + (string n)
-
- let maxMergeSources =
- let rec loop (n: int) =
- let mergeSourcesName = mkMergeSourcesName n
-
- if
- isNil (
- TryFindIntrinsicOrExtensionMethInfo
- ResultCollectionSettings.AtMostOneResult
- cenv
- ceenv.env
- mBind
- ceenv.ad
- mergeSourcesName
- ceenv.builderTy
- )
- then
- (n - 1)
+ if hasBindN then
+ let consumePat = SynPat.Tuple(false, pats, [], letPat.Range)
+
+ // Add the variables to the query variable space, on demand
+ let varSpace =
+ addVarsToVarSpace varSpace (fun _mCustomOp env ->
+ use _holder = TemporarilySuspendReportingTypecheckResultsToSink cenv.tcSink
+
+ let _, _, vspecs, envinner, _ =
+ TcMatchPattern cenv (NewInferenceType cenv.g) env ceenv.tpenv consumePat None TcTrueMatchClause.No
+
+ vspecs, envinner)
+
+ Some(
+ TranslateComputationExpressionBind
+ ceenv
+ comp
+ q
+ varSpace
+ mBind
+ (addBindDebugPoint spBind)
+ bindNName
+ sources
+ consumePat
+ innerComp
+ translatedCtxt
+ )
+ else
+ // Look for the maximum supported MergeSources, MergeSources3, ...
+ let mkMergeSourcesName n =
+ if n = 2 then
+ "MergeSources"
else
- loop (n + 1)
+ "MergeSources" + (string n)
+
+ let maxMergeSources =
+ let rec loop (n: int) =
+ let mergeSourcesName = mkMergeSourcesName n
+
+ if
+ isNil (
+ TryFindIntrinsicOrExtensionMethInfo
+ ResultCollectionSettings.AtMostOneResult
+ cenv
+ ceenv.env
+ mBind
+ ceenv.ad
+ mergeSourcesName
+ ceenv.builderTy
+ )
+ then
+ (n - 1)
+ else
+ loop (n + 1)
- loop 2
+ loop 2
- if maxMergeSources = 1 then
- error (Error(FSComp.SR.tcRequireMergeSourcesOrBindN (bindNName), mBind))
+ if maxMergeSources = 1 then
+ error (Error(FSComp.SR.tcRequireMergeSourcesOrBindN (bindNName), mBind))
- let rec mergeSources (sourcesAndPats: (SynExpr * SynPat) list) =
- let numSourcesAndPats = sourcesAndPats.Length
- assert (numSourcesAndPats <> 0)
+ let rec mergeSources (sourcesAndPats: (SynExpr * SynPat) list) =
+ let numSourcesAndPats = sourcesAndPats.Length
+ assert (numSourcesAndPats <> 0)
- if numSourcesAndPats = 1 then
- sourcesAndPats[0]
+ if numSourcesAndPats = 1 then
+ sourcesAndPats[0]
- elif numSourcesAndPats <= maxMergeSources then
+ elif numSourcesAndPats <= maxMergeSources then
- // Call MergeSources2(e1, e2), MergeSources3(e1, e2, e3) etc
- let mergeSourcesName = mkMergeSourcesName numSourcesAndPats
+ // Call MergeSources2(e1, e2), MergeSources3(e1, e2, e3) etc
+ let mergeSourcesName = mkMergeSourcesName numSourcesAndPats
- requireBuilderMethod mergeSourcesName mBind cenv ceenv.env ceenv.ad ceenv.builderTy mBind
+ requireBuilderMethod mergeSourcesName mBind cenv ceenv.env ceenv.ad ceenv.builderTy mBind
- let source =
- mkSynCall mergeSourcesName sourcesRange (List.map fst sourcesAndPats) ceenv.builderValName
+ let source =
+ mkSynCall mergeSourcesName sourcesRange (List.map fst sourcesAndPats) ceenv.builderValName
- let pat = SynPat.Tuple(false, List.map snd sourcesAndPats, [], letPat.Range)
- source, pat
+ let pat = SynPat.Tuple(false, List.map snd sourcesAndPats, [], letPat.Range)
+ source, pat
- else
+ else
- // Call MergeSourcesMax(e1, e2, e3, e4, (...))
- let nowSourcesAndPats, laterSourcesAndPats =
- List.splitAt (maxMergeSources - 1) sourcesAndPats
+ // Call MergeSourcesMax(e1, e2, e3, e4, (...))
+ let nowSourcesAndPats, laterSourcesAndPats =
+ List.splitAt (maxMergeSources - 1) sourcesAndPats
- let mergeSourcesName = mkMergeSourcesName maxMergeSources
+ let mergeSourcesName = mkMergeSourcesName maxMergeSources
- requireBuilderMethod mergeSourcesName mBind cenv ceenv.env ceenv.ad ceenv.builderTy mBind
+ requireBuilderMethod mergeSourcesName mBind cenv ceenv.env ceenv.ad ceenv.builderTy mBind
- let laterSource, laterPat = mergeSources laterSourcesAndPats
+ let laterSource, laterPat = mergeSources laterSourcesAndPats
- let source =
- mkSynCall
- mergeSourcesName
- sourcesRange
- (List.map fst nowSourcesAndPats @ [ laterSource ])
- ceenv.builderValName
+ let source =
+ mkSynCall
+ mergeSourcesName
+ sourcesRange
+ (List.map fst nowSourcesAndPats @ [ laterSource ])
+ ceenv.builderValName
- let pat =
- SynPat.Tuple(false, List.map snd nowSourcesAndPats @ [ laterPat ], [], letPat.Range)
+ let pat =
+ SynPat.Tuple(false, List.map snd nowSourcesAndPats @ [ laterPat ], [], letPat.Range)
- source, pat
+ source, pat
- let mergedSources, consumePat = mergeSources (List.zip sources pats)
+ let mergedSources, consumePat = mergeSources (List.zip sources pats)
- // Add the variables to the query variable space, on demand
- let varSpace =
- addVarsToVarSpace varSpace (fun _mCustomOp env ->
- use _holder = TemporarilySuspendReportingTypecheckResultsToSink cenv.tcSink
+ // Add the variables to the query variable space, on demand
+ let varSpace =
+ addVarsToVarSpace varSpace (fun _mCustomOp env ->
+ use _holder = TemporarilySuspendReportingTypecheckResultsToSink cenv.tcSink
- let _, _, vspecs, envinner, _ =
- TcMatchPattern cenv (NewInferenceType cenv.g) env ceenv.tpenv consumePat None TcTrueMatchClause.No
+ let _, _, vspecs, envinner, _ =
+ TcMatchPattern cenv (NewInferenceType cenv.g) env ceenv.tpenv consumePat None TcTrueMatchClause.No
- vspecs, envinner)
+ vspecs, envinner)
- // Build the 'Bind' call
- Some(
- TranslateComputationExpressionBind
- ceenv
- comp
- q
- varSpace
- mBind
- (addBindDebugPoint spBind)
- "Bind"
- [ mergedSources ]
- consumePat
- innerComp
- translatedCtxt
- )
+ // Build the 'Bind' call
+ Some(
+ TranslateComputationExpressionBind
+ ceenv
+ comp
+ q
+ varSpace
+ mBind
+ (addBindDebugPoint spBind)
+ "Bind"
+ [ mergedSources ]
+ consumePat
+ innerComp
+ translatedCtxt
+ )
| SynExpr.Match(spMatch, expr, clauses, m, trivia) ->
if ceenv.isQuery then
diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs
index 5f390038e35..567e1da0310 100644
--- a/src/Compiler/Checking/Expressions/CheckExpressions.fs
+++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs
@@ -3187,6 +3187,24 @@ let BuildRecdFieldSet g m objExpr (rfinfo: RecdFieldInfo) argExpr =
let wrap, objExpr, _readonly, _writeonly = mkExprAddrOfExpr g boxity false DefinitelyMutates objExpr None m
wrap (mkRecdFieldSetViaExprAddr (objExpr, rfinfo.RecdFieldRef, rfinfo.TypeInst, argExpr, m) )
+// This is used to check the target of an attribute with the form of
+// Long Form: []
+// Short Form: []
+let (|LongFormAttrTarget|UnrecognizedLongAttrTarget|ShortFormAttributeTarget|) (targetIndicator: Ident option) =
+ match targetIndicator with
+ | Some id when id.idText = "assembly" -> LongFormAttrTarget AttributeTargets.Assembly
+ | Some id when id.idText = "module" -> LongFormAttrTarget AttributeTargets.Module
+ | Some id when id.idText = "return" -> LongFormAttrTarget AttributeTargets.ReturnValue
+ | Some id when id.idText = "field" -> LongFormAttrTarget AttributeTargets.Field
+ | Some id when id.idText = "property" -> LongFormAttrTarget AttributeTargets.Property
+ | Some id when id.idText = "method" -> LongFormAttrTarget AttributeTargets.Method
+ | Some id when id.idText = "param" -> LongFormAttrTarget AttributeTargets.Parameter
+ | Some id when id.idText = "type" -> LongFormAttrTarget AttributeTargets.TyconDecl
+ | Some id when id.idText = "constructor" -> LongFormAttrTarget AttributeTargets.Constructor
+ | Some id when id.idText = "event" -> LongFormAttrTarget AttributeTargets.Event
+ | Some id -> UnrecognizedLongAttrTarget id
+ | None -> ShortFormAttributeTarget
+
//-------------------------------------------------------------------------
// Helpers dealing with named and optional args at callsites
//-------------------------------------------------------------------------
@@ -11344,30 +11362,21 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn
(validOnDefault, inheritedDefault)
| _ ->
(validOnDefault, inheritedDefault)
- let possibleTgts = enum validOn &&& attrTgt
- let directedTgts =
+ let attributeTargets = enum validOn &&& attrTgt
+ let directedTargets =
match targetIndicator with
- | Some id when id.idText = "assembly" -> AttributeTargets.Assembly
- | Some id when id.idText = "module" -> AttributeTargets.Module
- | Some id when id.idText = "return" -> AttributeTargets.ReturnValue
- | Some id when id.idText = "field" -> AttributeTargets.Field
- | Some id when id.idText = "property" -> AttributeTargets.Property
- | Some id when id.idText = "method" -> AttributeTargets.Method
- | Some id when id.idText = "param" -> AttributeTargets.Parameter
- | Some id when id.idText = "type" -> AttributeTargets.TyconDecl
- | Some id when id.idText = "constructor" -> AttributeTargets.Constructor
- | Some id when id.idText = "event" -> AttributeTargets.Event
- | Some id ->
- errorR(Error(FSComp.SR.tcUnrecognizedAttributeTarget(), id.idRange))
- possibleTgts
- // mask explicit targets
- | _ -> possibleTgts &&& ~~~ attrEx
- let constrainedTgts = possibleTgts &&& directedTgts
- if constrainedTgts = enum 0 then
- if (directedTgts = AttributeTargets.Assembly || directedTgts = AttributeTargets.Module) then
+ | LongFormAttrTarget attrTarget -> attrTarget
+ | UnrecognizedLongAttrTarget attrTarget ->
+ errorR(Error(FSComp.SR.tcUnrecognizedAttributeTarget(), attrTarget.idRange))
+ attributeTargets
+ | ShortFormAttributeTarget -> attributeTargets &&& ~~~ attrEx
+
+ let constrainedTargets = attributeTargets &&& directedTargets
+ if constrainedTargets = enum 0 then
+ if (directedTargets = AttributeTargets.Assembly || directedTargets = AttributeTargets.Module) then
error(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElementUseDo(), mAttr))
else
- error(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElement(), mAttr))
+ warning(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElement(), mAttr))
match ResolveObjectConstructor cenv.nameResolver env.DisplayEnv mAttr ad ty with
| Exception _ when canFail = TcCanFail.IgnoreAllErrors || canFail = TcCanFail.IgnoreMemberResoutionError -> [ ], true
@@ -11428,11 +11437,11 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn
if isStruct then error (Error(FSComp.SR.tcCustomAttributeMustBeReferenceType(), m))
if args.Length <> ilMethRef.ArgTypes.Length then error (Error(FSComp.SR.tcCustomAttributeArgumentMismatch(), m))
let args = args |> List.map mkAttribExpr
- Attrib(tcref, ILAttrib ilMethRef, args, namedAttribArgMap, isAppliedToGetterOrSetter, Some constrainedTgts, m)
+ Attrib(tcref, ILAttrib ilMethRef, args, namedAttribArgMap, isAppliedToGetterOrSetter, Some constrainedTargets, m)
| Expr.App (InnerExprPat(ExprValWithPossibleTypeInst(vref, _, _, _)), _, _, args, _) ->
let args = args |> List.collect (function Expr.Const (Const.Unit, _, _) -> [] | expr -> tryDestRefTupleExpr expr) |> List.map mkAttribExpr
- Attrib(tcref, FSAttrib vref, args, namedAttribArgMap, isAppliedToGetterOrSetter, Some constrainedTgts, mAttr)
+ Attrib(tcref, FSAttrib vref, args, namedAttribArgMap, isAppliedToGetterOrSetter, Some constrainedTargets, mAttr)
| _ ->
error (Error(FSComp.SR.tcCustomAttributeMustInvokeConstructor(), mAttr))
@@ -11440,7 +11449,7 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn
| _ ->
error(Error(FSComp.SR.tcAttributeExpressionsMustBeConstructorCalls(), mAttr))
- [ (constrainedTgts, attrib) ], false
+ [ (constrainedTargets, attrib) ], false
and TcAttributesWithPossibleTargetsEx canFail (cenv: cenv) env attrTgt attrEx synAttribs =
diff --git a/src/Compiler/Checking/TypeRelations.fs b/src/Compiler/Checking/TypeRelations.fs
index 2cb5dd4057a..fddf6027875 100644
--- a/src/Compiler/Checking/TypeRelations.fs
+++ b/src/Compiler/Checking/TypeRelations.fs
@@ -102,7 +102,7 @@ let TypesFeasiblyEquivStripMeasures g amap m ty1 ty2 =
TypesFeasiblyEquivalent true 0 g amap m ty1 ty2
let inline TryGetCachedTypeSubsumption (g: TcGlobals) (amap: ImportMap) key =
- if g.compilationMode = CompilationMode.OneOff && g.langVersion.SupportsFeature LanguageFeature.UseTypeSubsumptionCache then
+ if g.langVersion.SupportsFeature LanguageFeature.UseTypeSubsumptionCache then
match amap.TypeSubsumptionCache.TryGetValue(key) with
| true, subsumes ->
ValueSome subsumes
@@ -112,8 +112,8 @@ let inline TryGetCachedTypeSubsumption (g: TcGlobals) (amap: ImportMap) key =
ValueNone
let inline UpdateCachedTypeSubsumption (g: TcGlobals) (amap: ImportMap) key subsumes : unit =
- if g.compilationMode = CompilationMode.OneOff && g.langVersion.SupportsFeature LanguageFeature.UseTypeSubsumptionCache then
- amap.TypeSubsumptionCache[key] <- subsumes
+ if g.langVersion.SupportsFeature LanguageFeature.UseTypeSubsumptionCache then
+ amap.TypeSubsumptionCache.TryAdd(key, subsumes) |> ignore
/// The feasible coercion relation. Part of the language spec.
let rec TypeFeasiblySubsumesType ndeep (g: TcGlobals) (amap: ImportMap) m (ty1: TType) (canCoerce: CanCoerce) (ty2: TType) =
@@ -125,7 +125,7 @@ let rec TypeFeasiblySubsumesType ndeep (g: TcGlobals) (amap: ImportMap) m (ty1:
let ty2 = stripTyEqns g ty2
// Check if language feature supported
- let key = TTypeCacheKey.FromStrippedTypes (ty1, ty2, canCoerce, g)
+ let key = TTypeCacheKey.FromStrippedTypes (ty1, ty2, canCoerce)
match TryGetCachedTypeSubsumption g amap key with
| ValueSome subsumes ->
diff --git a/src/Compiler/Checking/import.fs b/src/Compiler/Checking/import.fs
index c87d6cdad03..f1f44090f19 100644
--- a/src/Compiler/Checking/import.fs
+++ b/src/Compiler/Checking/import.fs
@@ -6,22 +6,25 @@ module internal FSharp.Compiler.Import
open System.Collections.Concurrent
open System.Collections.Generic
open System.Collections.Immutable
-open FSharp.Compiler.Text.Range
+open System.Diagnostics
+
open Internal.Utilities.Library
open Internal.Utilities.Library.Extras
open Internal.Utilities.TypeHashing
-open Internal.Utilities.TypeHashing.HashTypes
+
open FSharp.Compiler
open FSharp.Compiler.AbstractIL.IL
open FSharp.Compiler.CompilerGlobalState
open FSharp.Compiler.DiagnosticsLogger
open FSharp.Compiler.SyntaxTreeOps
open FSharp.Compiler.Text
+open FSharp.Compiler.Text.Range
open FSharp.Compiler.Xml
open FSharp.Compiler.TypedTree
open FSharp.Compiler.TypedTreeBasics
open FSharp.Compiler.TypedTreeOps
open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.Caches
#if !NO_TYPEPROVIDERS
open FSharp.Compiler.TypeProviders
@@ -52,18 +55,18 @@ type CanCoerce =
| CanCoerce
| NoCoerce
-type [] TTypeCacheKey =
+[]
+type TTypeCacheKey =
val ty1: TType
val ty2: TType
val canCoerce: CanCoerce
- val tcGlobals: TcGlobals
- private new (ty1, ty2, canCoerce, tcGlobals) =
- { ty1 = ty1; ty2 = ty2; canCoerce = canCoerce; tcGlobals = tcGlobals }
+ private new (ty1, ty2, canCoerce) =
+ { ty1 = ty1; ty2 = ty2; canCoerce = canCoerce }
- static member FromStrippedTypes (ty1, ty2, canCoerce, tcGlobals) =
- TTypeCacheKey(ty1, ty2, canCoerce, tcGlobals)
+ static member FromStrippedTypes (ty1, ty2, canCoerce) =
+ TTypeCacheKey(ty1, ty2, canCoerce)
interface System.IEquatable with
member this.Equals other =
@@ -72,23 +75,24 @@ type [] TTypeCacheKey =
elif this.ty1 === other.ty1 && this.ty2 === other.ty2 then
true
else
- stampEquals this.tcGlobals this.ty1 other.ty1
- && stampEquals this.tcGlobals this.ty2 other.ty2
+ HashStamps.stampEquals this.ty1 other.ty1
+ && HashStamps.stampEquals this.ty2 other.ty2
override this.Equals(other:objnull) =
match other with
| :? TTypeCacheKey as p -> (this :> System.IEquatable).Equals p
| _ -> false
- override this.GetHashCode() : int =
- let g = this.tcGlobals
-
- let ty1Hash = combineHash (hashStamp g this.ty1) (hashTType g this.ty1)
- let ty2Hash = combineHash (hashStamp g this.ty2) (hashTType g this.ty2)
+ override this.GetHashCode () : int =
+ HashStamps.hashTType this.ty1
+ |> pipeToHash (HashStamps.hashTType this.ty2)
+ |> pipeToHash (hash this.canCoerce)
- let combined = combineHash (combineHash ty1Hash ty2Hash) (hash this.canCoerce)
+ override this.ToString () = $"{this.ty1.DebugText}-{this.ty2.DebugText}"
- combined
+let typeSubsumptionCache =
+ // Leave most of the capacity in reserve for bursts.
+ lazy Cache.Create({ TotalCapacity = 131072; HeadroomPercentage = 75 }, name = "TypeSubsumptionCache")
//-------------------------------------------------------------------------
// Import an IL types as F# types.
@@ -106,15 +110,13 @@ type [] TTypeCacheKey =
type ImportMap(g: TcGlobals, assemblyLoader: AssemblyLoader) =
let typeRefToTyconRefCache = ConcurrentDictionary()
- let typeSubsumptionCache = ConcurrentDictionary(System.Environment.ProcessorCount, 1024)
-
member _.g = g
member _.assemblyLoader = assemblyLoader
member _.ILTypeRefToTyconRefCache = typeRefToTyconRefCache
- member _.TypeSubsumptionCache = typeSubsumptionCache
+ member val TypeSubsumptionCache: Cache = typeSubsumptionCache.Value
let CanImportILScopeRef (env: ImportMap) m scoref =
diff --git a/src/Compiler/Checking/import.fsi b/src/Compiler/Checking/import.fsi
index c387558fcba..72611e12bf7 100644
--- a/src/Compiler/Checking/import.fsi
+++ b/src/Compiler/Checking/import.fsi
@@ -5,13 +5,12 @@ module internal FSharp.Compiler.Import
open Internal.Utilities.Library
open FSharp.Compiler.AbstractIL.IL
+open FSharp.Compiler.Caches
open FSharp.Compiler.TcGlobals
open FSharp.Compiler.Text
open FSharp.Compiler.Xml
open FSharp.Compiler.TypedTree
-open System.Collections.Concurrent
-
#if !NO_TYPEPROVIDERS
open FSharp.Compiler.TypeProviders
#endif
@@ -45,15 +44,14 @@ type CanCoerce =
[]
type TTypeCacheKey =
interface System.IEquatable
- private new: ty1: TType * ty2: TType * canCoerce: CanCoerce * tcGlobals: TcGlobals -> TTypeCacheKey
+ private new: ty1: TType * ty2: TType * canCoerce: CanCoerce -> TTypeCacheKey
- static member FromStrippedTypes:
- ty1: TType * ty2: TType * canCoerce: CanCoerce * tcGlobals: TcGlobals -> TTypeCacheKey
+ static member FromStrippedTypes: ty1: TType * ty2: TType * canCoerce: CanCoerce -> TTypeCacheKey
val ty1: TType
val ty2: TType
val canCoerce: CanCoerce
- val tcGlobals: TcGlobals
+
override GetHashCode: unit -> int
/// Represents a context used for converting AbstractIL .NET and provided types to F# internal compiler data structures.
@@ -73,7 +71,7 @@ type ImportMap =
member g: TcGlobals
/// Type subsumption cache
- member TypeSubsumptionCache: ConcurrentDictionary
+ member TypeSubsumptionCache: Cache
module Nullness =
diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs
index 1be3b7be3a2..258346b9104 100644
--- a/src/Compiler/CodeGen/IlxGen.fs
+++ b/src/Compiler/CodeGen/IlxGen.fs
@@ -10391,7 +10391,7 @@ and GenModuleBinding cenv (cgbuf: CodeGenBuffer) (qname: QualifiedNameOfFile) la
/// Generate the namespace fragments in a single file
and GenImplFile cenv (mgbuf: AssemblyBuilder) mainInfoOpt eenv (implFile: CheckedImplFileAfterOptimization) =
- let (CheckedImplFile(qname, _, signature, contents, hasExplicitEntryPoint, isScript, anonRecdTypes, _)) =
+ let (CheckedImplFile(qname, signature, contents, hasExplicitEntryPoint, isScript, anonRecdTypes, _)) =
implFile.ImplFile
let optimizeDuringCodeGen = implFile.OptimizeDuringCodeGen
diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs
index 68813e69a83..5f96b1f58c8 100644
--- a/src/Compiler/Driver/CompilerDiagnostics.fs
+++ b/src/Compiler/Driver/CompilerDiagnostics.fs
@@ -379,7 +379,7 @@ type PhasedDiagnostic with
// Level 2
| _ -> 2
- member x.IsEnabled(severity, options) =
+ member private x.IsEnabled(severity, options) =
let level = options.WarnLevel
let specificWarnOn = options.WarnOn
let n = x.Number
@@ -412,19 +412,25 @@ type PhasedDiagnostic with
member x.AdjustSeverity(options, severity) =
let n = x.Number
- let warnOff () = List.contains n options.WarnOff
+ let localWarnon () = WarnScopes.IsWarnon options n x.Range
+
+ let localNowarn () = WarnScopes.IsNowarn options n x.Range
+
+ let warnOff () =
+ List.contains n options.WarnOff && not (localWarnon ()) || localNowarn ()
match severity with
| FSharpDiagnosticSeverity.Error -> FSharpDiagnosticSeverity.Error
| FSharpDiagnosticSeverity.Warning when
x.IsEnabled(severity, options)
&& ((options.GlobalWarnAsError && not (warnOff ()))
- || List.contains n options.WarnAsError)
+ || List.contains n options.WarnAsError && not (localNowarn ()))
&& not (List.contains n options.WarnAsWarn)
->
FSharpDiagnosticSeverity.Error
+ | FSharpDiagnosticSeverity.Info when List.contains n options.WarnAsError && not (localNowarn ()) -> FSharpDiagnosticSeverity.Error
| FSharpDiagnosticSeverity.Warning when x.IsEnabled(severity, options) && not (warnOff ()) -> FSharpDiagnosticSeverity.Warning
- | FSharpDiagnosticSeverity.Info when List.contains n options.WarnAsError -> FSharpDiagnosticSeverity.Error
+ | FSharpDiagnosticSeverity.Warning when localWarnon () -> FSharpDiagnosticSeverity.Warning
| FSharpDiagnosticSeverity.Info when List.contains n options.WarnOn && not (warnOff ()) -> FSharpDiagnosticSeverity.Warning
| FSharpDiagnosticSeverity.Info when x.IsEnabled(severity, options) && not (warnOff ()) -> FSharpDiagnosticSeverity.Info
| _ -> FSharpDiagnosticSeverity.Hidden
@@ -1135,6 +1141,7 @@ type Exception with
| Parser.TOKEN_COLON_EQUALS -> SR.GetString("Parser.TOKEN.COLON.EQUALS")
| Parser.TOKEN_LARROW -> SR.GetString("Parser.TOKEN.LARROW")
| Parser.TOKEN_EQUALS -> SR.GetString("Parser.TOKEN.EQUALS")
+ | Parser.TOKEN_GREATER_BAR_RBRACE -> SR.GetString("Parser.TOKEN.GREATER.BAR.RBRACE")
| Parser.TOKEN_GREATER_BAR_RBRACK -> SR.GetString("Parser.TOKEN.GREATER.BAR.RBRACK")
| Parser.TOKEN_MINUS -> SR.GetString("Parser.TOKEN.MINUS")
| Parser.TOKEN_ADJACENT_PREFIX_OP -> SR.GetString("Parser.TOKEN.ADJACENT.PREFIX.OP")
@@ -2274,51 +2281,25 @@ type PhasedDiagnostic with
diagnostic.OutputContext(buf, prefix, fileLineFunction)
diagnostic.Output(buf, tcConfig, severity))
-//----------------------------------------------------------------------------
-// Scoped #nowarn pragmas
-
-/// Build an DiagnosticsLogger that delegates to another DiagnosticsLogger but filters warnings turned off by the given pragma declarations
-//
-// NOTE: we allow a flag to turn of strict file checking. This is because file names sometimes don't match due to use of
-// #line directives, e.g. for pars.fs/pars.fsy. In this case we just test by line number - in most cases this is sufficient
-// because we install a filtering error handler on a file-by-file basis for parsing and type-checking.
-// However this is indicative of a more systematic problem where source-line
-// sensitive operations (lexfilter and warning filtering) do not always
-// interact well with #line directives.
-type DiagnosticsLoggerFilteringByScopedPragmas
- (checkFile, scopedPragmas, diagnosticOptions: FSharpDiagnosticOptions, diagnosticsLogger: DiagnosticsLogger) =
- inherit DiagnosticsLogger("DiagnosticsLoggerFilteringByScopedPragmas")
+/// Build an DiagnosticsLogger that delegates to another DiagnosticsLogger but filters warnings
+type DiagnosticsLoggerFilteringByScopedNowarn(diagnosticOptions: FSharpDiagnosticOptions, diagnosticsLogger: DiagnosticsLogger) =
+ inherit DiagnosticsLogger("DiagnosticsLoggerFilteringByScopedNowarn")
let mutable realErrorPresent = false
override _.DiagnosticSink(diagnostic: PhasedDiagnostic, severity) =
+
if severity = FSharpDiagnosticSeverity.Error then
realErrorPresent <- true
diagnosticsLogger.DiagnosticSink(diagnostic, severity)
else
- let report =
- let warningNum = diagnostic.Number
-
- match diagnostic.Range with
- | Some m ->
- scopedPragmas
- |> List.exists (fun pragma ->
- let (ScopedPragma.WarningOff(pragmaRange, warningNumFromPragma)) = pragma
-
- warningNum = warningNumFromPragma
- && (not checkFile || m.FileIndex = pragmaRange.FileIndex)
- && posGeq m.Start pragmaRange.Start)
- |> not
- | None -> true
-
- if report then
- match diagnostic.AdjustSeverity(diagnosticOptions, severity) with
- | FSharpDiagnosticSeverity.Hidden -> ()
- | s -> diagnosticsLogger.DiagnosticSink(diagnostic, s)
+ match diagnostic.AdjustSeverity(diagnosticOptions, severity) with
+ | FSharpDiagnosticSeverity.Hidden -> ()
+ | s -> diagnosticsLogger.DiagnosticSink(diagnostic, s)
override _.ErrorCount = diagnosticsLogger.ErrorCount
override _.CheckForRealErrorsIgnoringWarnings = realErrorPresent
-let GetDiagnosticsLoggerFilteringByScopedPragmas (checkFile, scopedPragmas, diagnosticOptions, diagnosticsLogger) =
- DiagnosticsLoggerFilteringByScopedPragmas(checkFile, scopedPragmas, diagnosticOptions, diagnosticsLogger) :> DiagnosticsLogger
+let GetDiagnosticsLoggerFilteringByScopedNowarn (diagnosticOptions, diagnosticsLogger) =
+ DiagnosticsLoggerFilteringByScopedNowarn(diagnosticOptions, diagnosticsLogger) :> DiagnosticsLogger
diff --git a/src/Compiler/Driver/CompilerDiagnostics.fsi b/src/Compiler/Driver/CompilerDiagnostics.fsi
index cdf559c301a..1f6e91d0012 100644
--- a/src/Compiler/Driver/CompilerDiagnostics.fsi
+++ b/src/Compiler/Driver/CompilerDiagnostics.fsi
@@ -77,12 +77,8 @@ type PhasedDiagnostic with
unit
/// Get a diagnostics logger that filters the reporting of warnings based on scoped pragma information
-val GetDiagnosticsLoggerFilteringByScopedPragmas:
- checkFile: bool *
- scopedPragmas: ScopedPragma list *
- diagnosticOptions: FSharpDiagnosticOptions *
- diagnosticsLogger: DiagnosticsLogger ->
- DiagnosticsLogger
+val GetDiagnosticsLoggerFilteringByScopedNowarn:
+ diagnosticOptions: FSharpDiagnosticOptions * diagnosticsLogger: DiagnosticsLogger -> DiagnosticsLogger
/// Remove 'implicitIncludeDir' from a file name before output
val SanitizeFileName: fileName: string -> implicitIncludeDir: string -> string
diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs
index 6b7171b5697..1ce85b734fa 100644
--- a/src/Compiler/Driver/ParseAndCheckInputs.fs
+++ b/src/Compiler/Driver/ParseAndCheckInputs.fs
@@ -4,7 +4,6 @@
module internal FSharp.Compiler.ParseAndCheckInputs
open System
-open System.Diagnostics
open System.IO
open System.Threading
open System.Collections.Generic
@@ -41,7 +40,6 @@ open FSharp.Compiler.Text.Range
open FSharp.Compiler.Xml
open FSharp.Compiler.TypedTree
open FSharp.Compiler.TypedTreeOps
-open FSharp.Compiler.TypedTreeBasics
open FSharp.Compiler.TcGlobals
let CanonicalizeFilename fileName =
@@ -96,13 +94,13 @@ let PrependPathToSpec x (SynModuleOrNamespaceSig(longId, isRecursive, kind, decl
let PrependPathToInput x inp =
match inp with
- | ParsedInput.ImplFile(ParsedImplFileInput(b, c, q, d, hd, impls, e, trivia, i)) ->
+ | ParsedInput.ImplFile(ParsedImplFileInput(b, c, q, hd, impls, e, trivia, i)) ->
ParsedInput.ImplFile(
- ParsedImplFileInput(b, c, PrependPathToQualFileName x q, d, hd, List.map (PrependPathToImpl x) impls, e, trivia, i)
+ ParsedImplFileInput(b, c, PrependPathToQualFileName x q, hd, List.map (PrependPathToImpl x) impls, e, trivia, i)
)
- | ParsedInput.SigFile(ParsedSigFileInput(b, q, d, hd, specs, trivia, i)) ->
- ParsedInput.SigFile(ParsedSigFileInput(b, PrependPathToQualFileName x q, d, hd, List.map (PrependPathToSpec x) specs, trivia, i))
+ | ParsedInput.SigFile(ParsedSigFileInput(b, q, hd, specs, trivia, i)) ->
+ ParsedInput.SigFile(ParsedSigFileInput(b, PrependPathToQualFileName x q, hd, List.map (PrependPathToSpec x) specs, trivia, i))
let IsValidAnonModuleName (modname: string) =
modname |> String.forall (fun c -> Char.IsLetterOrDigit c || c = '_')
@@ -217,36 +215,55 @@ let PostParseModuleSpec (_i, defaultNamespace, isLastCompiland, fileName, intf)
SynModuleOrNamespaceSig(lid, isRecursive, kind, decls, xmlDoc, attributes, None, range, trivia)
-let GetScopedPragmasForHashDirective hd (langVersion: LanguageVersion) =
- [
- match hd with
- | ParsedHashDirective("nowarn", args, _) ->
- for arg in args do
- let rangeAndDescription =
- match arg with
- | ParsedHashDirectiveArgument.Int32(n, m) -> Some(m, WarningDescription.Int32 n)
- | ParsedHashDirectiveArgument.Ident(ident, m) -> Some(m, WarningDescription.Ident ident)
- | ParsedHashDirectiveArgument.String(s, _, m) -> Some(m, WarningDescription.String s)
- | _ -> None
-
- match rangeAndDescription with
- | None -> ()
- | Some(m, description) ->
- match GetWarningNumber(m, description, langVersion, WarningNumberSource.CompilerDirective) with
- | None -> ()
- | Some n -> ScopedPragma.WarningOff(m, n)
- | _ -> ()
- ]
+let private collectCodeComments (lexbuf: UnicodeLexing.Lexbuf) =
+ let tripleSlashComments = XmlDocStore.ReportInvalidXmlDocPositions(lexbuf)
-let private collectCodeComments (lexbuf: UnicodeLexing.Lexbuf) (tripleSlashComments: range list) =
[
yield! CommentStore.GetComments(lexbuf)
yield! (List.map CommentTrivia.LineComment tripleSlashComments)
+ yield! WarnScopes.getCommentTrivia lexbuf
]
|> List.sortBy (function
| CommentTrivia.LineComment r
| CommentTrivia.BlockComment r -> r.StartLine, r.StartColumn)
+let private collectParsedInputTrivia lexbuf diagnosticOptions isScript submoduleRanges =
+ WarnScopes.MergeInto diagnosticOptions isScript submoduleRanges lexbuf
+
+ {
+ ConditionalDirectives = IfdefStore.GetTrivia(lexbuf)
+ WarnDirectives = WarnScopes.getDirectiveTrivia (lexbuf)
+ CodeComments = collectCodeComments lexbuf
+ }
+
+let private getImplSubmoduleRanges (impls: ParsedImplFileFragment list) =
+ let getDecls (impl: ParsedImplFileFragment) =
+ match impl with
+ | ParsedImplFileFragment.AnonModule(decls, _) -> decls
+ | ParsedImplFileFragment.NamedModule(SynModuleOrNamespace(decls = decls)) -> decls
+ | ParsedImplFileFragment.NamespaceFragment(decls = decls) -> decls
+
+ let getSubmoduleRange decl =
+ match decl with
+ | SynModuleDecl.NestedModule(range = m) -> Some m
+ | _ -> None
+
+ impls |> List.collect getDecls |> List.choose getSubmoduleRange
+
+let private getSpecSubmoduleRanges (specs: ParsedSigFileFragment list) =
+ let getDecls (spec: ParsedSigFileFragment) =
+ match spec with
+ | ParsedSigFileFragment.AnonModule(decls, _) -> decls
+ | ParsedSigFileFragment.NamedModule(SynModuleOrNamespaceSig(decls = decls)) -> decls
+ | ParsedSigFileFragment.NamespaceFragment(decls = decls) -> decls
+
+ let getSubmoduleRange decl =
+ match decl with
+ | SynModuleSigDecl.NestedModule(range = m) -> Some m
+ | _ -> None
+
+ specs |> List.collect getDecls |> List.choose getSubmoduleRange
+
let PostParseModuleImpls
(
defaultNamespace,
@@ -254,9 +271,15 @@ let PostParseModuleImpls
isLastCompiland,
ParsedImplFile(hashDirectives, impls),
lexbuf: UnicodeLexing.Lexbuf,
- tripleSlashComments: range list,
+ diagnosticOptions: FSharpDiagnosticOptions,
identifiers: Set
) =
+
+ let isScript = IsScript fileName
+
+ let trivia =
+ collectParsedInputTrivia lexbuf diagnosticOptions isScript (getImplSubmoduleRanges impls)
+
let othersWithSameName =
impls
|> List.rev
@@ -273,31 +296,8 @@ let PostParseModuleImpls
|> List.mapi (fun i x -> PostParseModuleImpl(i, defaultNamespace, isLastCompiland, fileName, x))
let qualName = QualFileNameOfImpls fileName impls
- let isScript = IsScript fileName
- let scopedPragmas =
- [
- for SynModuleOrNamespace(decls = decls) in impls do
- for d in decls do
- match d with
- | SynModuleDecl.HashDirective(hd, _) -> yield! GetScopedPragmasForHashDirective hd lexbuf.LanguageVersion
- | _ -> ()
- for hd in hashDirectives do
- yield! GetScopedPragmasForHashDirective hd lexbuf.LanguageVersion
- ]
-
- let conditionalDirectives = IfdefStore.GetTrivia(lexbuf)
- let codeComments = collectCodeComments lexbuf tripleSlashComments
-
- let trivia: ParsedImplFileInputTrivia =
- {
- ConditionalDirectives = conditionalDirectives
- CodeComments = codeComments
- }
-
- ParsedInput.ImplFile(
- ParsedImplFileInput(fileName, isScript, qualName, scopedPragmas, hashDirectives, impls, isLastCompiland, trivia, identifiers)
- )
+ ParsedInput.ImplFile(ParsedImplFileInput(fileName, isScript, qualName, hashDirectives, impls, isLastCompiland, trivia, identifiers))
let PostParseModuleSpecs
(
@@ -306,9 +306,13 @@ let PostParseModuleSpecs
isLastCompiland,
ParsedSigFile(hashDirectives, specs),
lexbuf: UnicodeLexing.Lexbuf,
- tripleSlashComments: range list,
+ diagnosticOptions: FSharpDiagnosticOptions,
identifiers: Set
) =
+
+ let trivia =
+ collectParsedInputTrivia lexbuf diagnosticOptions false (getSpecSubmoduleRanges specs)
+
let othersWithSameName =
specs
|> List.rev
@@ -326,27 +330,7 @@ let PostParseModuleSpecs
let qualName = QualFileNameOfSpecs fileName specs
- let scopedPragmas =
- [
- for SynModuleOrNamespaceSig(decls = decls) in specs do
- for d in decls do
- match d with
- | SynModuleSigDecl.HashDirective(hd, _) -> yield! GetScopedPragmasForHashDirective hd lexbuf.LanguageVersion
- | _ -> ()
- for hd in hashDirectives do
- yield! GetScopedPragmasForHashDirective hd lexbuf.LanguageVersion
- ]
-
- let conditionalDirectives = IfdefStore.GetTrivia(lexbuf)
- let codeComments = collectCodeComments lexbuf tripleSlashComments
-
- let trivia: ParsedSigFileInputTrivia =
- {
- ConditionalDirectives = conditionalDirectives
- CodeComments = codeComments
- }
-
- ParsedInput.SigFile(ParsedSigFileInput(fileName, qualName, scopedPragmas, hashDirectives, specs, trivia, identifiers))
+ ParsedInput.SigFile(ParsedSigFileInput(fileName, qualName, hashDirectives, specs, trivia, identifiers))
type ModuleNamesDict = Map>
@@ -391,26 +375,26 @@ let DeduplicateModuleName (moduleNamesDict: ModuleNamesDict) (fileName: string)
let DeduplicateParsedInputModuleName (moduleNamesDict: ModuleNamesDict) input =
match input with
| ParsedInput.ImplFile implFile ->
- let (ParsedImplFileInput(fileName, isScript, qualNameOfFile, scopedPragmas, hashDirectives, modules, flags, trivia, identifiers)) =
+ let (ParsedImplFileInput(fileName, isScript, qualNameOfFile, hashDirectives, modules, flags, trivia, identifiers)) =
implFile
let qualNameOfFileR, moduleNamesDictR =
DeduplicateModuleName moduleNamesDict fileName qualNameOfFile
let implFileR =
- ParsedImplFileInput(fileName, isScript, qualNameOfFileR, scopedPragmas, hashDirectives, modules, flags, trivia, identifiers)
+ ParsedImplFileInput(fileName, isScript, qualNameOfFileR, hashDirectives, modules, flags, trivia, identifiers)
let inputR = ParsedInput.ImplFile implFileR
inputR, moduleNamesDictR
| ParsedInput.SigFile sigFile ->
- let (ParsedSigFileInput(fileName, qualNameOfFile, scopedPragmas, hashDirectives, modules, trivia, identifiers)) =
+ let (ParsedSigFileInput(fileName, qualNameOfFile, hashDirectives, modules, trivia, identifiers)) =
sigFile
let qualNameOfFileR, moduleNamesDictR =
DeduplicateModuleName moduleNamesDict fileName qualNameOfFile
let sigFileR =
- ParsedSigFileInput(fileName, qualNameOfFileR, scopedPragmas, hashDirectives, modules, trivia, identifiers)
+ ParsedSigFileInput(fileName, qualNameOfFileR, hashDirectives, modules, trivia, identifiers)
let inputT = ParsedInput.SigFile sigFileR
inputT, moduleNamesDictR
@@ -449,66 +433,54 @@ let ParseInput
use _ = UseDiagnosticsLogger delayLogger
use _ = UseBuildPhase BuildPhase.Parse
- let mutable scopedPragmas = []
-
try
- let input =
- let identStore = HashSet()
-
- let lexer =
- if identCapture then
- (fun x ->
- let token = lexer x
-
- match token with
- | Parser.token.PERCENT_OP ident
- | Parser.token.FUNKY_OPERATOR_NAME ident
- | Parser.token.ADJACENT_PREFIX_OP ident
- | Parser.token.PLUS_MINUS_OP ident
- | Parser.token.INFIX_AMP_OP ident
- | Parser.token.INFIX_STAR_DIV_MOD_OP ident
- | Parser.token.PREFIX_OP ident
- | Parser.token.INFIX_BAR_OP ident
- | Parser.token.INFIX_AT_HAT_OP ident
- | Parser.token.INFIX_COMPARE_OP ident
- | Parser.token.INFIX_STAR_STAR_OP ident
- | Parser.token.IDENT ident -> identStore.Add ident |> ignore
- | _ -> ()
-
- token)
- else
- lexer
-
- if FSharpMLCompatFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) then
- if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then
- errorR (Error(FSComp.SR.buildInvalidSourceFileExtensionML fileName, rangeStartup))
- else
- mlCompatWarning (FSComp.SR.buildCompilingExtensionIsForML ()) rangeStartup
-
- // Call the appropriate parser - for signature files or implementation files
- if FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) then
- let impl = Parser.implementationFile lexer lexbuf
-
- let tripleSlashComments = XmlDocStore.ReportInvalidXmlDocPositions(lexbuf)
-
- PostParseModuleImpls(defaultNamespace, fileName, isLastCompiland, impl, lexbuf, tripleSlashComments, Set identStore)
- elif FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) then
- let intfs = Parser.signatureFile lexer lexbuf
-
- let tripleSlashComments = XmlDocStore.ReportInvalidXmlDocPositions(lexbuf)
+ let identStore = HashSet()
+
+ let lexer =
+ if identCapture then
+ (fun x ->
+ let token = lexer x
+
+ match token with
+ | Parser.token.PERCENT_OP ident
+ | Parser.token.FUNKY_OPERATOR_NAME ident
+ | Parser.token.ADJACENT_PREFIX_OP ident
+ | Parser.token.PLUS_MINUS_OP ident
+ | Parser.token.INFIX_AMP_OP ident
+ | Parser.token.INFIX_STAR_DIV_MOD_OP ident
+ | Parser.token.PREFIX_OP ident
+ | Parser.token.INFIX_BAR_OP ident
+ | Parser.token.INFIX_AT_HAT_OP ident
+ | Parser.token.INFIX_COMPARE_OP ident
+ | Parser.token.INFIX_STAR_STAR_OP ident
+ | Parser.token.IDENT ident -> identStore.Add ident |> ignore
+ | _ -> ()
- PostParseModuleSpecs(defaultNamespace, fileName, isLastCompiland, intfs, lexbuf, tripleSlashComments, Set identStore)
- else if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then
- error (Error(FSComp.SR.buildInvalidSourceFileExtensionUpdated fileName, rangeStartup))
+ token)
else
- error (Error(FSComp.SR.buildInvalidSourceFileExtension fileName, rangeStartup))
+ lexer
- scopedPragmas <- input.ScopedPragmas
- input
+ if FSharpMLCompatFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) then
+ if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then
+ errorR (Error(FSComp.SR.buildInvalidSourceFileExtensionML fileName, rangeStartup))
+ else
+ mlCompatWarning (FSComp.SR.buildCompilingExtensionIsForML ()) rangeStartup
+
+ // Call the appropriate parser - for signature files or implementation files
+ if FSharpImplFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) then
+ let impl = Parser.implementationFile lexer lexbuf
+ PostParseModuleImpls(defaultNamespace, fileName, isLastCompiland, impl, lexbuf, diagnosticOptions, Set identStore)
+ elif FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) then
+ let intfs = Parser.signatureFile lexer lexbuf
+ PostParseModuleSpecs(defaultNamespace, fileName, isLastCompiland, intfs, lexbuf, diagnosticOptions, Set identStore)
+ else if lexbuf.SupportsFeature LanguageFeature.MLCompatRevisions then
+ error (Error(FSComp.SR.buildInvalidSourceFileExtensionUpdated fileName, rangeStartup))
+ else
+ error (Error(FSComp.SR.buildInvalidSourceFileExtension fileName, rangeStartup))
finally
// OK, now commit the errors, since the ScopedPragmas will (hopefully) have been scraped
let filteringDiagnosticsLogger =
- GetDiagnosticsLoggerFilteringByScopedPragmas(false, scopedPragmas, diagnosticOptions, diagnosticsLogger)
+ GetDiagnosticsLoggerFilteringByScopedNowarn(diagnosticOptions, diagnosticsLogger)
delayLogger.CommitDelayedDiagnostics filteringDiagnosticsLogger
@@ -572,20 +544,7 @@ let ReportParsingStatistics res =
let EmptyParsedInput (fileName, isLastCompiland) =
if FSharpSigFileSuffixes |> List.exists (FileSystemUtils.checkSuffix fileName) then
- ParsedInput.SigFile(
- ParsedSigFileInput(
- fileName,
- QualFileNameOfImpls fileName [],
- [],
- [],
- [],
- {
- ConditionalDirectives = []
- CodeComments = []
- },
- Set.empty
- )
- )
+ ParsedInput.SigFile(ParsedSigFileInput(fileName, QualFileNameOfImpls fileName [], [], [], ParsedInputTrivia.Empty, Set.empty))
else
ParsedInput.ImplFile(
ParsedImplFileInput(
@@ -594,12 +553,8 @@ let EmptyParsedInput (fileName, isLastCompiland) =
QualFileNameOfImpls fileName [],
[],
[],
- [],
isLastCompiland,
- {
- ConditionalDirectives = []
- CodeComments = []
- },
+ ParsedInputTrivia.Empty,
Set.empty
)
)
@@ -836,11 +791,7 @@ let ParseInputFiles (tcConfig: TcConfig, lexResourceManager, sourceFiles, diagno
tcConfig.exiter.Exit 1
let ProcessMetaCommandsFromInput
- (
- nowarnF: 'state -> range * string -> 'state,
- hashReferenceF: 'state -> range * string * Directive -> 'state,
- loadSourceF: 'state -> range * string -> unit
- )
+ (hashReferenceF: 'state -> range * string * Directive -> 'state, loadSourceF: 'state -> range * string -> unit)
(tcConfig: TcConfigBuilder, inp: ParsedInput, pathOfMetaCommandSource, state0)
=
@@ -884,11 +835,6 @@ let ProcessMetaCommandsFromInput
state
- | ParsedHashDirective("nowarn", hashArguments, m) ->
- let arguments = parsedHashDirectiveArgumentsNoCheck hashArguments
-
- List.fold (fun state d -> nowarnF state (m, d)) state arguments
-
| ParsedHashDirective(("reference" | "r") as c, [], m) ->
if not canHaveScriptMetaCommands then
errorR (HashDirectiveNotAllowedInNonScript m)
@@ -1009,19 +955,9 @@ let ProcessMetaCommandsFromInput
let state = List.fold ProcessMetaCommandsFromModuleImpl state implFile.Contents
state
-let ApplyNoWarnsToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource) =
- // Clone
- let tcConfigB = tcConfig.CloneToBuilder()
- let addNoWarn = fun () (m, s) -> tcConfigB.TurnWarningOff(m, s)
- let addReference = fun () (_m, _s, _) -> ()
- let addLoadedSource = fun () (_m, _s) -> ()
- ProcessMetaCommandsFromInput (addNoWarn, addReference, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ())
- TcConfig.Create(tcConfigB, validate = false)
-
let ApplyMetaCommandsFromInputToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource, dependencyProvider) =
// Clone
let tcConfigB = tcConfig.CloneToBuilder()
- let getWarningNumber = fun () _ -> ()
let addReferenceDirective =
fun () (m, path, directive) -> tcConfigB.AddReferenceDirective(dependencyProvider, m, path, directive)
@@ -1029,7 +965,7 @@ let ApplyMetaCommandsFromInputToTcConfig (tcConfig: TcConfig, inp: ParsedInput,
let addLoadedSource =
fun () (m, s) -> tcConfigB.AddLoadedSource(m, s, pathOfMetaCommandSource)
- ProcessMetaCommandsFromInput (getWarningNumber, addReferenceDirective, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ())
+ ProcessMetaCommandsFromInput (addReferenceDirective, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ())
TcConfig.Create(tcConfigB, validate = false)
/// Build the initial type checking environment
@@ -1198,14 +1134,14 @@ let AddCheckResultsToTcState
// Add the implementation as to the implementation env
let tcImplEnv =
- AddLocalRootModuleOrNamespace TcResultsSink.NoSink tcGlobals amap m tcImplEnv implFileSigType
+ AddLocalRootModuleOrNamespace tcGlobals amap m tcImplEnv implFileSigType
// Add the implementation as to the signature env (unless it had an explicit signature)
let tcSigEnv =
if hadSig then
tcState.tcsTcSigEnv
else
- AddLocalRootModuleOrNamespace TcResultsSink.NoSink tcGlobals amap m tcState.tcsTcSigEnv implFileSigType
+ AddLocalRootModuleOrNamespace tcGlobals amap m tcState.tcsTcSigEnv implFileSigType
// Open the prefixPath for fsi.exe (tcImplEnv)
let tcImplEnv, openDecls =
@@ -1269,7 +1205,7 @@ let SkippedImplFilePlaceholder (tcConfig: TcConfig, tcImports: TcImports, tcGlob
tcState
let emptyImplFile =
- CheckedImplFile(qualNameOfFile, [], rootSigTy, ModuleOrNamespaceContents.TMDefs [], false, false, StampMap [], Map.empty)
+ CheckedImplFile(qualNameOfFile, rootSigTy, ModuleOrNamespaceContents.TMDefs [], false, false, StampMap [], Map.empty)
let tcEnvAtEnd = tcStateForImplFile.TcEnvFromImpls
Some((tcEnvAtEnd, EmptyTopAttrs, Some emptyImplFile, ccuSigForFile), tcState)
@@ -1402,15 +1338,15 @@ let CheckOneInput
}
// Within a file, equip loggers to locally filter w.r.t. scope pragmas in each input
-let DiagnosticsLoggerForInput (tcConfig: TcConfig, input: ParsedInput, oldLogger) =
- GetDiagnosticsLoggerFilteringByScopedPragmas(false, input.ScopedPragmas, tcConfig.diagnosticsOptions, oldLogger)
+let DiagnosticsLoggerForInput (tcConfig: TcConfig, oldLogger) =
+ GetDiagnosticsLoggerFilteringByScopedNowarn(tcConfig.diagnosticsOptions, oldLogger)
/// Typecheck a single file (or interactive entry into F# Interactive)
let CheckOneInputEntry (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt) tcState input =
cancellable {
// Equip loggers to locally filter w.r.t. scope pragmas in each input
use _ =
- UseTransformedDiagnosticsLogger(fun oldLogger -> DiagnosticsLoggerForInput(tcConfig, input, oldLogger))
+ UseTransformedDiagnosticsLogger(fun oldLogger -> DiagnosticsLoggerForInput(tcConfig, oldLogger))
use _ = UseBuildPhase BuildPhase.TypeCheck
@@ -1563,7 +1499,7 @@ let CheckOneInputWithCallback
let rootSigs = Zmap.add qualNameOfFile sigFileType tcState.tcsRootSigs
let tcSigEnv =
- AddLocalRootModuleOrNamespace TcResultsSink.NoSink tcGlobals amap m tcState.tcsTcSigEnv sigFileType
+ AddLocalRootModuleOrNamespace tcGlobals amap m tcState.tcsTcSigEnv sigFileType
// Add the signature to the signature env (unless it had an explicit signature)
let ccuSigForFile = CombineCcuContentFragments [ sigFileType; tcState.tcsCcuSig ]
@@ -1915,7 +1851,7 @@ let CheckMultipleInputsUsingGraphMode
inputsWithLoggers
|> List.toArray
|> Array.map (fun (input, oldLogger) ->
- let logger = DiagnosticsLoggerForInput(tcConfig, input, oldLogger)
+ let logger = DiagnosticsLoggerForInput(tcConfig, oldLogger)
input, logger)
let processFile (node: NodeToTypeCheck) (state: State) : Finisher =
diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fsi b/src/Compiler/Driver/ParseAndCheckInputs.fsi
index fb32a4557cd..281638b5685 100644
--- a/src/Compiler/Driver/ParseAndCheckInputs.fsi
+++ b/src/Compiler/Driver/ParseAndCheckInputs.fsi
@@ -7,12 +7,12 @@ open System.IO
open Internal.Utilities.Library
open FSharp.Compiler.CheckBasics
open FSharp.Compiler.CheckDeclarations
-open FSharp.Compiler.CompilerGlobalState
open FSharp.Compiler.CompilerConfig
open FSharp.Compiler.CompilerImports
open FSharp.Compiler.Diagnostics
open FSharp.Compiler.DependencyManager
open FSharp.Compiler.DiagnosticsLogger
+open FSharp.Compiler.Features
open FSharp.Compiler.GraphChecking
open FSharp.Compiler.NameResolution
open FSharp.Compiler.Syntax
@@ -78,16 +78,13 @@ val ParseInput:
/// A general routine to process hash directives
val ProcessMetaCommandsFromInput:
- ('T -> range * string -> 'T) * ('T -> range * string * Directive -> 'T) * ('T -> range * string -> unit) ->
+ ('T -> range * string * Directive -> 'T) * ('T -> range * string -> unit) ->
TcConfigBuilder * ParsedInput * string * 'T ->
'T
-/// Process all the #r, #I etc. in an input. For non-scripts report warnings about ignored directives.
+/// Process all the #r, #I etc. in an input.
val ApplyMetaCommandsFromInputToTcConfig: TcConfig * ParsedInput * string * DependencyProvider -> TcConfig
-/// Process the #nowarn in an input and integrate them into the TcConfig
-val ApplyNoWarnsToTcConfig: TcConfig * ParsedInput * string -> TcConfig
-
/// Parse one input stream
val ParseOneInputStream:
tcConfig: TcConfig *
diff --git a/src/Compiler/Driver/ScriptClosure.fs b/src/Compiler/Driver/ScriptClosure.fs
index b45049627cf..a9dd5442626 100644
--- a/src/Compiler/Driver/ScriptClosure.fs
+++ b/src/Compiler/Driver/ScriptClosure.fs
@@ -63,9 +63,6 @@ type LoadClosure =
/// The #load, including those that didn't resolve
OriginalLoadReferences: (range * string * string) list
- /// The #nowarns
- NoWarns: (string * range list) list
-
/// Diagnostics seen while processing resolutions
ResolutionDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list
@@ -95,8 +92,7 @@ module ScriptPreprocessClosure =
range: range *
parsedInput: ParsedInput option *
parseDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list *
- metaDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list *
- nowarns: (string * range) list
+ metaDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list
type Observed() =
let seen = Dictionary<_, bool>()
@@ -262,13 +258,9 @@ module ScriptPreprocessClosure =
errorRecovery exn m
[]
- let ApplyMetaCommandsFromInputToTcConfigAndGatherNoWarn
- (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource, dependencyProvider)
- =
+ let ApplyMetaCommandsFromInputToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource, dependencyProvider) =
let tcConfigB = tcConfig.CloneToBuilder()
- let mutable nowarns = []
- let getWarningNumber () (m, s) = nowarns <- (s, m) :: nowarns
let addReferenceDirective () (m, s, directive) =
tcConfigB.AddReferenceDirective(dependencyProvider, m, s, directive)
@@ -277,19 +269,17 @@ module ScriptPreprocessClosure =
tcConfigB.AddLoadedSource(m, s, pathOfMetaCommandSource)
try
- ProcessMetaCommandsFromInput
- (getWarningNumber, addReferenceDirective, addLoadedSource)
- (tcConfigB, inp, pathOfMetaCommandSource, ())
+ ProcessMetaCommandsFromInput (addReferenceDirective, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ())
with ReportedError _ ->
// Recover by using whatever did end up in the tcConfig
()
try
- TcConfig.Create(tcConfigB, validate = false), nowarns
+ TcConfig.Create(tcConfigB, validate = false)
with ReportedError _ ->
// Recover by using a default TcConfig.
let tcConfigB = tcConfig.CloneToBuilder()
- TcConfig.Create(tcConfigB, validate = false), nowarns
+ TcConfig.Create(tcConfigB, validate = false)
let getDirective d =
match d with
@@ -474,13 +464,8 @@ module ScriptPreprocessClosure =
let pathOfMetaCommandSource = !!Path.GetDirectoryName(fileName)
let preSources = tcConfig.GetAvailableLoadedSources()
- let tcConfigResult, noWarns =
- ApplyMetaCommandsFromInputToTcConfigAndGatherNoWarn(
- tcConfig,
- parseResult,
- pathOfMetaCommandSource,
- dependencyProvider
- )
+ let tcConfigResult =
+ ApplyMetaCommandsFromInputToTcConfig(tcConfig, parseResult, pathOfMetaCommandSource, dependencyProvider)
tcConfig <- tcConfigResult // We accumulate the tcConfig in order to collect assembly references
@@ -501,14 +486,14 @@ module ScriptPreprocessClosure =
for subSource in ClosureSourceOfFilename(subFile, m, tcConfigResult.inputCodePage, false) do
yield! processClosureSource subSource
else
- ClosureFile(subFile, m, None, [], [], [])
+ ClosureFile(subFile, m, None, [], [])
- ClosureFile(fileName, m, Some parseResult, parseDiagnostics, diagnosticsLogger.Diagnostics, noWarns)
+ ClosureFile(fileName, m, Some parseResult, parseDiagnostics, diagnosticsLogger.Diagnostics)
else
// Don't traverse into .fs leafs.
printfn "yielding non-script source %s" fileName
- ClosureFile(fileName, m, None, [], [], [])
+ ClosureFile(fileName, m, None, [], [])
]
let sources = closureSources |> List.collect processClosureSource
@@ -520,32 +505,22 @@ module ScriptPreprocessClosure =
/// Mark the last file as isLastCompiland.
let MarkLastCompiland (tcConfig: TcConfig, lastClosureFile) =
- let (ClosureFile(fileName, m, lastParsedInput, parseDiagnostics, metaDiagnostics, nowarns)) =
+ let (ClosureFile(fileName, m, lastParsedInput, parseDiagnostics, metaDiagnostics)) =
lastClosureFile
match lastParsedInput with
| Some(ParsedInput.ImplFile lastParsedImplFile) ->
- let (ParsedImplFileInput(name, isScript, qualNameOfFile, scopedPragmas, hashDirectives, implFileFlags, _, trivia, identifiers)) =
+ let (ParsedImplFileInput(name, isScript, qualNameOfFile, hashDirectives, implFileFlags, _, trivia, identifiers)) =
lastParsedImplFile
let isLastCompiland = (true, tcConfig.target.IsExe)
let lastParsedImplFileR =
- ParsedImplFileInput(
- name,
- isScript,
- qualNameOfFile,
- scopedPragmas,
- hashDirectives,
- implFileFlags,
- isLastCompiland,
- trivia,
- identifiers
- )
+ ParsedImplFileInput(name, isScript, qualNameOfFile, hashDirectives, implFileFlags, isLastCompiland, trivia, identifiers)
let lastClosureFileR =
- ClosureFile(fileName, m, Some(ParsedInput.ImplFile lastParsedImplFileR), parseDiagnostics, metaDiagnostics, nowarns)
+ ClosureFile(fileName, m, Some(ParsedInput.ImplFile lastParsedImplFileR), parseDiagnostics, metaDiagnostics)
lastClosureFileR
| _ -> lastClosureFile
@@ -563,12 +538,12 @@ module ScriptPreprocessClosure =
// Get all source files.
let sourceFiles =
- [ for ClosureFile(fileName, m, _, _, _, _) in closureFiles -> (fileName, m) ]
+ [ for ClosureFile(fileName, m, _, _, _) in closureFiles -> (fileName, m) ]
let sourceInputs =
[
for closureFile in closureFiles ->
- let (ClosureFile(fileName, _, input, parseDiagnostics, metaDiagnostics, _nowarns)) =
+ let (ClosureFile(fileName, _, input, parseDiagnostics, metaDiagnostics)) =
closureFile
let closureInput: LoadClosureInput =
@@ -582,10 +557,6 @@ module ScriptPreprocessClosure =
closureInput
]
- let globalNoWarns =
- closureFiles
- |> List.collect (fun (ClosureFile(_, _, _, _, _, noWarns)) -> noWarns)
-
// Resolve all references.
let references, unresolvedReferences, resolutionDiagnostics =
let diagnosticsLogger = CapturingDiagnosticsLogger("GetLoadClosure")
@@ -601,7 +572,7 @@ module ScriptPreprocessClosure =
// Root errors and warnings - look at the last item in the closureFiles list
let loadClosureRootDiagnostics, allRootDiagnostics =
match List.rev closureFiles with
- | ClosureFile(_, _, _, parseDiagnostics, metaDiagnostics, _) :: _ ->
+ | ClosureFile(_, _, _, parseDiagnostics, metaDiagnostics) :: _ ->
(earlierDiagnostics @ metaDiagnostics @ resolutionDiagnostics),
(parseDiagnostics @ earlierDiagnostics @ metaDiagnostics @ resolutionDiagnostics)
| _ -> [], [] // When no file existed.
@@ -632,7 +603,6 @@ module ScriptPreprocessClosure =
SdkDirOverride = tcConfig.sdkDirOverride
UnresolvedReferences = unresolvedReferences
Inputs = sourceInputs
- NoWarns = List.groupBy fst globalNoWarns |> List.map (map2Of2 (List.map snd))
OriginalLoadReferences = tcConfig.loadedSources
ResolutionDiagnostics = resolutionDiagnostics
AllRootFileDiagnostics = allRootDiagnostics
diff --git a/src/Compiler/Driver/ScriptClosure.fsi b/src/Compiler/Driver/ScriptClosure.fsi
index 249885036cd..b54b9b2f0d0 100644
--- a/src/Compiler/Driver/ScriptClosure.fsi
+++ b/src/Compiler/Driver/ScriptClosure.fsi
@@ -60,9 +60,6 @@ type LoadClosure =
/// The original #load references, including those that didn't resolve
OriginalLoadReferences: (range * string * string) list
- /// The #nowarns
- NoWarns: (string * range list) list
-
/// Diagnostics seen while processing resolutions
ResolutionDiagnostics: (PhasedDiagnostic * FSharpDiagnosticSeverity) list
diff --git a/src/Compiler/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs
index 3518d9d4884..2ef07e66e6b 100644
--- a/src/Compiler/Driver/fsc.fs
+++ b/src/Compiler/Driver/fsc.fs
@@ -77,7 +77,7 @@ type DiagnosticsLoggerUpToMaxErrors(tcConfigB: TcConfigBuilder, exiter: Exiter,
override x.DiagnosticSink(diagnostic, severity) =
let tcConfig = TcConfig.Create(tcConfigB, validate = false)
- match diagnostic.AdjustSeverity(tcConfigB.diagnosticsOptions, severity) with
+ match diagnostic.AdjustSeverity(tcConfig.diagnosticsOptions, severity) with
| FSharpDiagnosticSeverity.Error ->
if errors >= tcConfig.maxErrors then
x.HandleTooManyErrors(FSComp.SR.fscTooManyErrors ())
@@ -225,11 +225,6 @@ let AdjustForScriptCompile (tcConfigB: TcConfigBuilder, commandLineSourceFiles,
references
|> List.iter (fun r -> tcConfigB.AddReferencedAssemblyByPath(r.originalReference.Range, r.resolvedPath))
- // Also record the other declarations from the script.
- closure.NoWarns
- |> List.collect (fun (n, ms) -> ms |> List.map (fun m -> m, n))
- |> List.iter (fun (x, m) -> tcConfigB.TurnWarningOff(x, m))
-
closure.SourceFiles |> List.map fst |> List.iter AddIfNotPresent
closure.AllRootFileDiagnostics |> List.iter diagnosticSink
@@ -644,7 +639,6 @@ let main1
if not tcConfig.continueAfterParseFailure then
AbortOnError(diagnosticsLogger, exiter)
- // Apply any nowarn flags
let tcConfig =
(tcConfig, inputs)
||> List.fold (fun z (input, sourceFileDirectory) ->
@@ -735,13 +729,7 @@ let main2
let oldLogger = diagnosticsLogger
let diagnosticsLogger =
- let scopedPragmas =
- [
- for CheckedImplFile(pragmas = pragmas) in typedImplFiles do
- yield! pragmas
- ]
-
- GetDiagnosticsLoggerFilteringByScopedPragmas(true, scopedPragmas, tcConfig.diagnosticsOptions, oldLogger)
+ GetDiagnosticsLoggerFilteringByScopedNowarn(tcConfig.diagnosticsOptions, oldLogger)
SetThreadDiagnosticsLoggerNoUnwind diagnosticsLogger
diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt
index 9bfa12ce963..969b40ae4ff 100644
--- a/src/Compiler/FSComp.txt
+++ b/src/Compiler/FSComp.txt
@@ -1798,3 +1798,11 @@ featureDontWarnOnUppercaseIdentifiersInBindingPatterns,"Don't warn on uppercase
featureDeprecatePlacesWhereSeqCanBeOmitted,"Deprecate places where 'seq' can be omitted"
featureSupportValueOptionsAsOptionalParameters,"Support ValueOption as valid type for optional member parameters"
featureSupportWarnWhenUnitPassedToObjArg,"Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`."
+featureUseBangBindingValueDiscard,"Allows use! _ = ... in computation expressions"
+featureBetterAnonymousRecordParsing,"Support for better anonymous record parsing"
+featureScopedNowarn,"Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules"
+featureAllowLetOrUseBangTypeAnnotationWithoutParens,"Allow let! and use! type annotations without requiring parentheses"
+3874,lexWarnDirectiveMustBeFirst,"#nowarn/#warnon directives must appear as the first non-whitespace characters on a line"
+3875,lexWarnDirectiveMustHaveArgs,"Warn directives must have warning number(s) as argument(s)"
+3876,lexWarnDirectivesMustMatch,"There is another %s for this warning already in line %d."
+3877,lexLineDirectiveMappingIsNotUnique,"The file '%s' was also pointed to in a line directive in '%s'. Proper warn directive application may not be possible."
\ No newline at end of file
diff --git a/src/Compiler/FSStrings.resx b/src/Compiler/FSStrings.resx
index abb2bb57f55..8453259ea1b 100644
--- a/src/Compiler/FSStrings.resx
+++ b/src/Compiler/FSStrings.resx
@@ -357,6 +357,9 @@
symbol '='
+
+ symbol '>|}'
+
symbol '>|]'
diff --git a/src/Compiler/FSharp.Compiler.Service.fsproj b/src/Compiler/FSharp.Compiler.Service.fsproj
index 74e59954e8f..6c087fa99fe 100644
--- a/src/Compiler/FSharp.Compiler.Service.fsproj
+++ b/src/Compiler/FSharp.Compiler.Service.fsproj
@@ -146,6 +146,8 @@
+
+
@@ -278,6 +280,8 @@
+
+
diff --git a/src/Compiler/Facilities/CompilerLocation.fs b/src/Compiler/Facilities/CompilerLocation.fs
index abd436647ae..03251f2109a 100644
--- a/src/Compiler/Facilities/CompilerLocation.fs
+++ b/src/Compiler/Facilities/CompilerLocation.fs
@@ -123,6 +123,7 @@ module internal FSharpEnvironment =
|]
elif typeof.Assembly.GetName().Name = "System.Private.CoreLib" then
[|
+ "net10.0"
"net9.0"
"net8.0"
"net7.0"
diff --git a/src/Compiler/Facilities/DiagnosticOptions.fs b/src/Compiler/Facilities/DiagnosticOptions.fs
index 2a3a6ffe742..b5f87d482ad 100644
--- a/src/Compiler/Facilities/DiagnosticOptions.fs
+++ b/src/Compiler/Facilities/DiagnosticOptions.fs
@@ -20,6 +20,7 @@ type FSharpDiagnosticOptions =
WarnOn: int list
WarnAsError: int list
WarnAsWarn: int list
+ mutable WarnScopeData: obj option
}
static member Default =
@@ -30,6 +31,7 @@ type FSharpDiagnosticOptions =
WarnOn = []
WarnAsError = []
WarnAsWarn = []
+ WarnScopeData = None
}
member x.CheckXmlDocs =
diff --git a/src/Compiler/Facilities/DiagnosticOptions.fsi b/src/Compiler/Facilities/DiagnosticOptions.fsi
index 8ff6b3d2f88..a6f041c7ed9 100644
--- a/src/Compiler/Facilities/DiagnosticOptions.fsi
+++ b/src/Compiler/Facilities/DiagnosticOptions.fsi
@@ -19,7 +19,8 @@ type FSharpDiagnosticOptions =
WarnOff: int list
WarnOn: int list
WarnAsError: int list
- WarnAsWarn: int list }
+ WarnAsWarn: int list
+ mutable WarnScopeData: obj option }
static member Default: FSharpDiagnosticOptions
diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs
index 7a9a14b8602..246ec741d67 100644
--- a/src/Compiler/Facilities/LanguageFeatures.fs
+++ b/src/Compiler/Facilities/LanguageFeatures.fs
@@ -99,6 +99,10 @@ type LanguageFeature =
| DeprecatePlacesWhereSeqCanBeOmitted
| SupportValueOptionsAsOptionalParameters
| WarnWhenUnitPassedToObjArg
+ | UseBangBindingValueDiscard
+ | BetterAnonymousRecordParsing
+ | ScopedNowarn
+ | AllowTypedLetOrUseBang
/// LanguageVersion management
type LanguageVersion(versionText) =
@@ -229,6 +233,10 @@ type LanguageVersion(versionText) =
LanguageFeature.DeprecatePlacesWhereSeqCanBeOmitted, previewVersion
LanguageFeature.SupportValueOptionsAsOptionalParameters, previewVersion
LanguageFeature.WarnWhenUnitPassedToObjArg, previewVersion
+ LanguageFeature.UseBangBindingValueDiscard, previewVersion
+ LanguageFeature.BetterAnonymousRecordParsing, previewVersion
+ LanguageFeature.ScopedNowarn, previewVersion
+ LanguageFeature.AllowTypedLetOrUseBang, previewVersion
]
static let defaultLanguageVersion = LanguageVersion("default")
@@ -391,6 +399,10 @@ type LanguageVersion(versionText) =
| LanguageFeature.DeprecatePlacesWhereSeqCanBeOmitted -> FSComp.SR.featureDeprecatePlacesWhereSeqCanBeOmitted ()
| LanguageFeature.SupportValueOptionsAsOptionalParameters -> FSComp.SR.featureSupportValueOptionsAsOptionalParameters ()
| LanguageFeature.WarnWhenUnitPassedToObjArg -> FSComp.SR.featureSupportWarnWhenUnitPassedToObjArg ()
+ | LanguageFeature.UseBangBindingValueDiscard -> FSComp.SR.featureUseBangBindingValueDiscard ()
+ | LanguageFeature.BetterAnonymousRecordParsing -> FSComp.SR.featureBetterAnonymousRecordParsing ()
+ | LanguageFeature.ScopedNowarn -> FSComp.SR.featureScopedNowarn ()
+ | LanguageFeature.AllowTypedLetOrUseBang -> FSComp.SR.featureAllowLetOrUseBangTypeAnnotationWithoutParens ()
/// Get a version string associated with the given feature.
static member GetFeatureVersionString feature =
diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi
index 410a8b193c9..c9e70ce1567 100644
--- a/src/Compiler/Facilities/LanguageFeatures.fsi
+++ b/src/Compiler/Facilities/LanguageFeatures.fsi
@@ -90,6 +90,10 @@ type LanguageFeature =
| DeprecatePlacesWhereSeqCanBeOmitted
| SupportValueOptionsAsOptionalParameters
| WarnWhenUnitPassedToObjArg
+ | UseBangBindingValueDiscard
+ | BetterAnonymousRecordParsing
+ | ScopedNowarn
+ | AllowTypedLetOrUseBang
/// LanguageVersion management
type LanguageVersion =
diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs
index 78d5cb94dcd..662ba9752e7 100644
--- a/src/Compiler/Interactive/fsi.fs
+++ b/src/Compiler/Interactive/fsi.fs
@@ -41,11 +41,8 @@ open FSharp.Compiler.CompilerOptions
open FSharp.Compiler.CompilerConfig
open FSharp.Compiler.CompilerDiagnostics
open FSharp.Compiler.CompilerImports
-open FSharp.Compiler.CompilerGlobalState
-open FSharp.Compiler.CreateILModule
open FSharp.Compiler.DependencyManager
open FSharp.Compiler.Diagnostics
-open FSharp.Compiler.EditorServices
open FSharp.Compiler.DiagnosticsLogger
open FSharp.Compiler.Features
open FSharp.Compiler.IlxGen
@@ -70,7 +67,6 @@ open FSharp.Compiler.Xml
open FSharp.Compiler.Tokenization
open FSharp.Compiler.TypedTree
open FSharp.Compiler.TypedTreeOps
-open FSharp.Compiler.BuildGraph
open FSharp.Compiler.CheckExpressionsOps
//----------------------------------------------------------------------------
@@ -1671,9 +1667,10 @@ let internal mkBoundValueTypedImpl tcGlobals m moduleName name ty =
let contents = TMDefs([ TMDefs[TMDefRec(false, [], [], [ mbinding ], m)] ])
let qname = QualifiedNameOfFile.QualifiedNameOfFile(Ident(moduleName, m))
- entity, v, CheckedImplFile.CheckedImplFile(qname, [], mty, contents, false, false, StampMap.Empty, Map.empty)
+ entity, v, CheckedImplFile.CheckedImplFile(qname, mty, contents, false, false, StampMap.Empty, Map.empty)
-let dynamicCcuName = "FSI-ASSEMBLY"
+let dynamicCcuName (isEmitMulti) =
+ $"""FSI-ASSEMBLY{if isEmitMulti then "-MULTI" else ""}"""
/// Encapsulates the coordination of the typechecking, optimization and code generation
/// components of the F# compiler for interactively executed fragments of code.
@@ -1723,7 +1720,11 @@ type internal FsiDynamicCompiler
None
else
let assemBuilder, moduleBuilder =
- mkDynamicAssemblyAndModule (dynamicCcuName, tcConfigB.optSettings.LocalOptimizationsEnabled, fsiCollectible)
+ mkDynamicAssemblyAndModule (
+ dynamicCcuName (tcConfigB.fsiMultiAssemblyEmit),
+ tcConfigB.optSettings.LocalOptimizationsEnabled,
+ fsiCollectible
+ )
dynamicAssemblies.Add(assemBuilder)
Some(assemBuilder, moduleBuilder)
@@ -1813,7 +1814,7 @@ type internal FsiDynamicCompiler
let attrs =
[
- tcGlobals.MakeInternalsVisibleToAttribute(dynamicCcuName)
+ tcGlobals.MakeInternalsVisibleToAttribute(dynamicCcuName (tcConfigB.fsiMultiAssemblyEmit))
yield! manifest.CustomAttrs.AsList()
]
@@ -1960,7 +1961,9 @@ type internal FsiDynamicCompiler
diagnosticsLogger.AbortOnError(fsiConsoleOutput)
ReportTime tcConfig "Linking"
- let ilxMainModule = CreateModuleFragment(tcConfigB, dynamicCcuName, codegenResults)
+
+ let ilxMainModule =
+ CreateModuleFragment(tcConfigB, dynamicCcuName (tcConfigB.fsiMultiAssemblyEmit), codegenResults)
diagnosticsLogger.AbortOnError(fsiConsoleOutput)
@@ -2475,13 +2478,9 @@ type internal FsiDynamicCompiler
true,
ComputeQualifiedNameOfFileFromUniquePath(m, prefixPath),
[],
- [],
[ impl ],
(isLastCompiland, isExe),
- {
- ConditionalDirectives = []
- CodeComments = []
- },
+ ParsedInputTrivia.Empty,
Set.empty
)
)
@@ -2652,7 +2651,7 @@ type internal FsiDynamicCompiler
let tcEnv, asms =
try
- RequireReferences(ctok, tcImports, tcState.TcEnvFromImpls, dynamicCcuName, resolutions)
+ RequireReferences(ctok, tcImports, tcState.TcEnvFromImpls, dynamicCcuName (tcConfigB.fsiMultiAssemblyEmit), resolutions)
with _ ->
for (path, _, _, m) in refs do
tcConfigB.RemoveReferencedAssemblyByPath(m, path)
@@ -2822,14 +2821,11 @@ type internal FsiDynamicCompiler
=
WithImplicitHome (tcConfigB, directoryName sourceFile) (fun () ->
ProcessMetaCommandsFromInput
- ((fun st (m, nm) ->
- tcConfigB.TurnWarningOff(m, nm)
- st),
- (fun st (m, path, directive) ->
- let st, _ =
- fsiDynamicCompiler.PartiallyProcessReferenceOrPackageIncludePathDirective(ctok, st, directive, path, false, m)
+ ((fun st (m, path, directive) ->
+ let st, _ =
+ fsiDynamicCompiler.PartiallyProcessReferenceOrPackageIncludePathDirective(ctok, st, directive, path, false, m)
- st),
+ st),
(fun _ _ -> ()))
(tcConfigB, input, !!Path.GetDirectoryName(sourceFile), istate))
@@ -2868,10 +2864,6 @@ type internal FsiDynamicCompiler
fsiConsoleOutput.uprintfn "]"
- for (warnNum, ranges) in closure.NoWarns do
- for m in ranges do
- tcConfigB.TurnWarningOff(m, warnNum)
-
// Play errors and warnings from resolution
closure.ResolutionDiagnostics |> List.iter diagnosticSink
@@ -3025,7 +3017,7 @@ type internal FsiDynamicCompiler
let emEnv0 =
if tcConfigB.fsiMultiAssemblyEmit then
let emEnv =
- ILMultiInMemoryAssemblyEmitEnv(ilGlobals, resolveAssemblyRef, dynamicCcuName)
+ ILMultiInMemoryAssemblyEmitEnv(ilGlobals, resolveAssemblyRef, dynamicCcuName (tcConfigB.fsiMultiAssemblyEmit))
MultipleInMemoryAssemblies emEnv
else
@@ -3041,10 +3033,10 @@ type internal FsiDynamicCompiler
let emEnv = ILDynamicAssemblyWriter.emEnv0
SingleRefEmitAssembly(cenv, emEnv)
- let tcEnv, openDecls0 =
- GetInitialTcEnv(dynamicCcuName, rangeStdin0, tcConfig, tcImports, tcGlobals)
+ let ccuName = dynamicCcuName (tcConfigB.fsiMultiAssemblyEmit)
- let ccuName = dynamicCcuName
+ let tcEnv, openDecls0 =
+ GetInitialTcEnv(ccuName, rangeStdin0, tcConfig, tcImports, tcGlobals)
let tcState =
GetInitialTcState(rangeStdin0, ccuName, tcConfig, tcGlobals, tcImports, tcEnv, openDecls0)
@@ -3679,7 +3671,7 @@ type FsiInteractionProcessor
error (Error(FSIstrings.SR.fsiDirectoryDoesNotExist (path), m))
/// Parse one interaction. Called on the parser thread.
- let ParseInteraction (tokenizer: LexFilter.LexFilter) =
+ let ParseInteraction diagnosticOptions (tokenizer: LexFilter.LexFilter) =
let mutable lastToken = Parser.ELSE // Any token besides SEMICOLON_SEMICOLON will do for initial value
try
@@ -3695,6 +3687,8 @@ type FsiInteractionProcessor
Parser.interaction lexerWhichSavesLastToken tokenizer.LexBuffer)
+ WarnScopes.MergeInto diagnosticOptions false [] tokenizer.LexBuffer
+
Some input
with e ->
// On error, consume tokens until to ;; or EOF.
@@ -3723,7 +3717,7 @@ type FsiInteractionProcessor
let tokenizer =
fsiStdinLexerProvider.CreateBufferLexer("hdummy.fsx", lexbuf, diagnosticsLogger)
- let parsedInteraction = ParseInteraction tokenizer
+ let parsedInteraction = ParseInteraction tcConfigB.diagnosticsOptions tokenizer
match parsedInteraction with
| Some(ParsedScriptInteraction.Definitions([ SynModuleDecl.Expr(e, _) ], _)) ->
@@ -3832,12 +3826,6 @@ type FsiInteractionProcessor
istate, Completed None
- | ParsedHashDirective("nowarn", nowarnArguments, m) ->
- let numbers = (parsedHashDirectiveArgumentsNoCheck nowarnArguments)
-
- List.iter (fun (d: string) -> tcConfigB.TurnWarningOff(m, d)) numbers
- istate, Completed None
-
| ParsedHashDirective("terms", [], _) ->
tcConfigB.showTerms <- not tcConfigB.showTerms
istate, Completed None
@@ -4140,6 +4128,7 @@ type FsiInteractionProcessor
runCodeOnMainThread,
istate: FsiDynamicCompilerState,
tokenizer: LexFilter.LexFilter,
+ diagnosticOptions,
diagnosticsLogger,
?cancellationToken: CancellationToken
) =
@@ -4166,7 +4155,7 @@ type FsiInteractionProcessor
// Parse the interaction. When FSI.EXE is waiting for input from the console the
// parser thread is blocked somewhere deep this call.
- let action = ParseInteraction tokenizer
+ let action = ParseInteraction diagnosticOptions tokenizer
if progress then
fprintfn fsiConsoleOutput.Out "returned from ParseInteraction...calling runCodeOnMainThread..."
@@ -4204,7 +4193,13 @@ type FsiInteractionProcessor
let rec run istate =
let status =
- processor.ParseAndExecuteInteractionFromLexbuf((fun f istate -> f ctok istate), istate, tokenizer, diagnosticsLogger)
+ processor.ParseAndExecuteInteractionFromLexbuf(
+ (fun f istate -> f ctok istate),
+ istate,
+ tokenizer,
+ tcConfigB.diagnosticsOptions,
+ diagnosticsLogger
+ )
ProcessStepStatus status None (fun _ istate -> run istate)
@@ -4284,7 +4279,7 @@ type FsiInteractionProcessor
currState
|> InteractiveCatch diagnosticsLogger (fun istate ->
- let expr = ParseInteraction tokenizer
+ let expr = ParseInteraction tcConfigB.diagnosticsOptions tokenizer
ExecuteParsedInteractionOnMainThread(ctok, diagnosticsLogger, expr, istate, cancellationToken))
|> commitResult
@@ -4337,7 +4332,7 @@ type FsiInteractionProcessor
// mainForm.Invoke to pipe a message back through the form's main event loop. (The message
// is a delegate to execute on the main Thread)
//
- member processor.StartStdinReadAndProcessThread diagnosticsLogger =
+ member processor.StartStdinReadAndProcessThread(diagnosticOptions, diagnosticsLogger) =
if progress then
fprintfn fsiConsoleOutput.Out "creating stdinReaderThread"
@@ -4371,6 +4366,7 @@ type FsiInteractionProcessor
runCodeOnMainThread,
currState,
currTokenizer,
+ diagnosticOptions,
diagnosticsLogger
)
@@ -4978,7 +4974,7 @@ type FsiEvaluationSession
| _ -> ())
fsiInteractionProcessor.LoadInitialFiles(ctokRun, diagnosticsLogger)
- fsiInteractionProcessor.StartStdinReadAndProcessThread(diagnosticsLogger)
+ fsiInteractionProcessor.StartStdinReadAndProcessThread(tcConfigB.diagnosticsOptions, diagnosticsLogger)
DriveFsiEventLoop(fsi, fsiInterruptController, fsiConsoleOutput)
diff --git a/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs b/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs
index f03db8f5e6f..0b1f58713ba 100644
--- a/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs
+++ b/src/Compiler/Optimize/InnerLambdasToTopLevelFuncs.fs
@@ -330,8 +330,8 @@ type ReqdItem =
let reqdItemOrder =
let rep = function
- | ReqdSubEnv v -> true, v
- | ReqdVal v -> false, v
+ | ReqdSubEnv v -> struct (true, v)
+ | ReqdVal v -> struct (false, v)
Order.orderOn rep (Pair.order (Bool.order, valOrder))
@@ -1332,9 +1332,9 @@ module Pass4_RewriteAssembly =
let rhs, z = TransModuleContents penv z rhs
ModuleOrNamespaceBinding.Module(nm, rhs), z
- let TransImplFile penv z (CheckedImplFile (fragName, pragmas, signature, contents, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)) =
+ let TransImplFile penv z (CheckedImplFile (fragName, signature, contents, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)) =
let contentsR, z = TransModuleContents penv z contents
- (CheckedImplFile (fragName, pragmas, signature, contentsR, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)), z
+ (CheckedImplFile (fragName, signature, contentsR, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)), z
//-------------------------------------------------------------------------
// pass5: copyExpr
diff --git a/src/Compiler/Optimize/Optimizer.fs b/src/Compiler/Optimize/Optimizer.fs
index 2840331f54b..52e404cea3e 100644
--- a/src/Compiler/Optimize/Optimizer.fs
+++ b/src/Compiler/Optimize/Optimizer.fs
@@ -4367,7 +4367,7 @@ and OptimizeModuleDefs cenv (env, bindInfosColl) defs =
(defs, UnionOptimizationInfos minfos), (env, bindInfosColl)
and OptimizeImplFileInternal cenv env isIncrementalFragment hidden implFile =
- let (CheckedImplFile (qname, pragmas, signature, contents, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)) = implFile
+ let (CheckedImplFile (qname, signature, contents, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)) = implFile
let env, contentsR, minfo, hidden =
// FSI compiles interactive fragments as if you're typing incrementally into one module.
//
@@ -4389,7 +4389,7 @@ and OptimizeImplFileInternal cenv env isIncrementalFragment hidden implFile =
let env = BindValsInModuleOrNamespace cenv minfo env
env, mexprR, minfoExternal, hidden
- let implFileR = CheckedImplFile (qname, pragmas, signature, contentsR, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)
+ let implFileR = CheckedImplFile (qname, signature, contentsR, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)
env, implFileR, minfo, hidden
diff --git a/src/Compiler/Service/BackgroundCompiler.fs b/src/Compiler/Service/BackgroundCompiler.fs
index 5eb8bd35f99..29d73f63617 100644
--- a/src/Compiler/Service/BackgroundCompiler.fs
+++ b/src/Compiler/Service/BackgroundCompiler.fs
@@ -1350,8 +1350,6 @@ type internal BackgroundCompiler
yield! otherFlags
for r in loadClosure.References do
yield "-r:" + fst r
- for code, _ in loadClosure.NoWarns do
- yield "--nowarn:" + code
|]
let options =
@@ -1479,7 +1477,7 @@ type internal BackgroundCompiler
member _.BeforeBackgroundFileCheck = self.BeforeBackgroundFileCheck
- member _.CheckFileInProject
+ member this.CheckFileInProject
(
parseResults: FSharpParseFileResults,
fileName: string,
@@ -1488,7 +1486,13 @@ type internal BackgroundCompiler
options: FSharpProjectOptions,
userOpName: string
) : Async =
- self.CheckFileInProject(parseResults, fileName, fileVersion, sourceText, options, userOpName)
+ async {
+ ignore parseResults
+
+ let! _, result = this.ParseAndCheckFileInProject(fileName, fileVersion, sourceText, options, userOpName)
+
+ return result
+ }
member _.CheckFileInProjectAllowingStaleCachedResults
(
diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs
index 57d322c81a8..a169b4a6a56 100644
--- a/src/Compiler/Service/FSharpCheckerResults.fs
+++ b/src/Compiler/Service/FSharpCheckerResults.fs
@@ -3102,8 +3102,14 @@ module internal ParseAndCheckFile =
errHandler.CollectedDiagnostics(None), parseResult, errHandler.AnyErrors
let ApplyLoadClosure
- (tcConfig, parsedMainInput, mainInputFileName: string, loadClosure: LoadClosure option, tcImports: TcImports, backgroundDiagnostics)
- =
+ (
+ tcConfig: TcConfig,
+ parsedMainInput,
+ mainInputFileName: string,
+ loadClosure: LoadClosure option,
+ tcImports: TcImports,
+ backgroundDiagnostics
+ ) =
// If additional references were brought in by the preprocessor then we need to process them
match loadClosure with
@@ -3240,13 +3246,6 @@ module internal ParseAndCheckFile =
use _unwindBP = UseBuildPhase BuildPhase.TypeCheck
- // Apply nowarns to tcConfig (may generate errors, so ensure diagnosticsLogger is installed)
- let tcConfig =
- ApplyNoWarnsToTcConfig(tcConfig, parsedMainInput, !!Path.GetDirectoryName(mainInputFileName))
-
- // update the error handler with the modified tcConfig
- errHandler.DiagnosticOptions <- tcConfig.diagnosticsOptions
-
// If additional references were brought in by the preprocessor then we need to process them
ApplyLoadClosure(tcConfig, parsedMainInput, mainInputFileName, loadClosure, tcImports, backgroundDiagnostics)
@@ -3293,7 +3292,9 @@ module internal ParseAndCheckFile =
// Play background errors and warnings for this file.
do
for err, severity in backgroundDiagnostics do
- diagnosticSink (err, severity)
+ match err.AdjustSeverity(tcConfig.diagnosticsOptions, severity) with
+ | FSharpDiagnosticSeverity.Hidden -> ()
+ | s -> diagnosticSink (err, s)
let (tcEnvAtEnd, _, implFiles, ccuSigsForFiles), tcState = resOpt
diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs
index 0cdc4b9235e..f98ccd09a12 100644
--- a/src/Compiler/Service/IncrementalBuild.fs
+++ b/src/Compiler/Service/IncrementalBuild.fs
@@ -30,6 +30,7 @@ open FSharp.Compiler.NameResolution
open FSharp.Compiler.ParseAndCheckInputs
open FSharp.Compiler.ScriptClosure
open FSharp.Compiler.Syntax
+open FSharp.Compiler.SyntaxTrivia
open FSharp.Compiler.TcGlobals
open FSharp.Compiler.Text
open FSharp.Compiler.Text.Range
@@ -128,9 +129,8 @@ module IncrementalBuildSyntaxTree =
sigName,
[],
[],
- [],
isLastCompiland,
- { ConditionalDirectives = []; CodeComments = [] },
+ ParsedInputTrivia.Empty,
Set.empty
)
), sourceRange, fileName, [||]
@@ -254,7 +254,7 @@ type BoundModel private (
IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBETypechecked fileName)
let capturingDiagnosticsLogger = CapturingDiagnosticsLogger("TypeCheck")
- let diagnosticsLogger = GetDiagnosticsLoggerFilteringByScopedPragmas(false, input.ScopedPragmas, tcConfig.diagnosticsOptions, capturingDiagnosticsLogger)
+ let diagnosticsLogger = GetDiagnosticsLoggerFilteringByScopedNowarn(tcConfig.diagnosticsOptions, capturingDiagnosticsLogger)
use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck)
beforeFileChecked.Trigger fileName
diff --git a/src/Compiler/Service/ServiceLexing.fs b/src/Compiler/Service/ServiceLexing.fs
index 8e97816290f..fb2af965f76 100644
--- a/src/Compiler/Service/ServiceLexing.fs
+++ b/src/Compiler/Service/ServiceLexing.fs
@@ -283,6 +283,7 @@ module internal TokenClassifications =
| LBRACE_BAR -> (FSharpTokenColorKind.Punctuation, FSharpTokenCharKind.Delimiter, FSharpTokenTriggerClass.MatchBraces)
| GREATER_RBRACK
+ | GREATER_BAR_RBRACE
| GREATER_BAR_RBRACK -> (FSharpTokenColorKind.Punctuation, FSharpTokenCharKind.Delimiter, FSharpTokenTriggerClass.None)
| RQUOTE _
@@ -404,6 +405,7 @@ module internal TokenClassifications =
| HASH_LIGHT _
| HASH_LINE _
+ | WARN_DIRECTIVE _
| HASH_IF _
| HASH_ELSE _
| HASH_ENDIF _ -> (FSharpTokenColorKind.PreprocessorKeyword, FSharpTokenCharKind.WhiteSpace, FSharpTokenTriggerClass.None)
@@ -935,6 +937,21 @@ type FSharpLineTokenizer(lexbuf: UnicodeLexing.Lexbuf, maxLength: int option, fi
let offset = beforeIdent + identLength
processWhiteAndComment str offset delay cont)
+ let processWarnDirective (str: string) leftc rightc cont =
+ let hashIdx = str.IndexOf("#", StringComparison.Ordinal)
+ let commentIdx = str.IndexOf("//", StringComparison.Ordinal)
+
+ if commentIdx > 0 then
+ delayToken (COMMENT cont, leftc + commentIdx - 1, rightc)
+
+ let rightc = if commentIdx > 0 then leftc + commentIdx else rightc
+
+ if (hashIdx > 0) then
+ delayToken (WARN_DIRECTIVE(range0, "", cont), hashIdx, rightc)
+ WHITESPACE cont, leftc, leftc + hashIdx - 1
+ else
+ WARN_DIRECTIVE(range0, "", cont), leftc, rightc
+
// Set up the initial file position
do
match fileName with
@@ -1035,7 +1052,8 @@ type FSharpLineTokenizer(lexbuf: UnicodeLexing.Lexbuf, maxLength: int option, fi
| HASH_IF(m, lineStr, cont) when lineStr <> "" -> false, processHashIfLine m.StartColumn lineStr cont
| HASH_ELSE(m, lineStr, cont) when lineStr <> "" -> false, processHashEndElse m.StartColumn lineStr 4 cont
| HASH_ENDIF(m, lineStr, cont) when lineStr <> "" -> false, processHashEndElse m.StartColumn lineStr 5 cont
- | HASH_IDENT(ident) ->
+ | WARN_DIRECTIVE(_, s, cont) -> false, processWarnDirective s leftc rightc cont
+ | HASH_IDENT ident ->
delayToken (IDENT ident, leftc + 1, rightc)
false, (HASH, leftc, leftc)
| RQUOTE_DOT(s, raw) ->
@@ -1173,9 +1191,7 @@ type FSharpLineTokenizer(lexbuf: UnicodeLexing.Lexbuf, maxLength: int option, fi
| true, "silentCd"
| true, "q"
| true, "quit"
- | true, "help"
- // These are for script and non-script
- | _, "nowarn" ->
+ | true, "help" ->
// Merge both tokens into one.
let lexcontFinal =
if isCached then
@@ -1286,6 +1302,7 @@ type FSharpTokenKind =
| HashIf
| HashElse
| HashEndIf
+ | WarnDirective
| CommentTrivia
| WhitespaceTrivia
| HashLine
@@ -1371,6 +1388,7 @@ type FSharpTokenKind =
| Comma
| RightArrow
| GreaterBarRightBracket
+ | GreaterBarRightBrace
| LeftParenthesisStarRightParenthesis
| Open
| Or
@@ -1497,6 +1515,7 @@ type FSharpToken =
| HASH_IF _ -> FSharpTokenKind.HashIf
| HASH_ELSE _ -> FSharpTokenKind.HashElse
| HASH_ENDIF _ -> FSharpTokenKind.HashEndIf
+ | WARN_DIRECTIVE _ -> FSharpTokenKind.WarnDirective
| COMMENT _ -> FSharpTokenKind.CommentTrivia
| WHITESPACE _ -> FSharpTokenKind.WhitespaceTrivia
| HASH_LINE _ -> FSharpTokenKind.HashLine
@@ -1581,6 +1600,7 @@ type FSharpToken =
| STAR -> FSharpTokenKind.Star
| COMMA -> FSharpTokenKind.Comma
| RARROW -> FSharpTokenKind.RightArrow
+ | GREATER_BAR_RBRACE -> FSharpTokenKind.GreaterBarRightBrace
| GREATER_BAR_RBRACK -> FSharpTokenKind.GreaterBarRightBracket
| LPAREN_STAR_RPAREN -> FSharpTokenKind.LeftParenthesisStarRightParenthesis
| OPEN -> FSharpTokenKind.Open
diff --git a/src/Compiler/Service/ServiceLexing.fsi b/src/Compiler/Service/ServiceLexing.fsi
index ee2ab7411d5..1efcf59269d 100755
--- a/src/Compiler/Service/ServiceLexing.fsi
+++ b/src/Compiler/Service/ServiceLexing.fsi
@@ -371,6 +371,7 @@ type public FSharpTokenKind =
| HashIf
| HashElse
| HashEndIf
+ | WarnDirective
| CommentTrivia
| WhitespaceTrivia
| HashLine
@@ -456,6 +457,7 @@ type public FSharpTokenKind =
| Comma
| RightArrow
| GreaterBarRightBracket
+ | GreaterBarRightBrace
| LeftParenthesisStarRightParenthesis
| Open
| Or
diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fs b/src/Compiler/Service/ServiceParseTreeWalk.fs
index 659f4c4bc60..33734db9a62 100644
--- a/src/Compiler/Service/ServiceParseTreeWalk.fs
+++ b/src/Compiler/Service/ServiceParseTreeWalk.fs
@@ -1014,6 +1014,8 @@ module SyntaxTraversal =
let path = SyntaxNode.SynBinding b :: origPath
match b with
+ | SynBinding(kind = SynBindingKind.Do; expr = expr) -> traverseSynExpr path expr
+
| SynBinding(headPat = synPat; expr = synExpr; attributes = attributes; range = m) ->
[
yield! attributeApplicationDives path attributes
diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs
index f5b15936902..b8ffe0d030f 100644
--- a/src/Compiler/Service/ServiceParsedInputOps.fs
+++ b/src/Compiler/Service/ServiceParsedInputOps.fs
@@ -320,6 +320,13 @@ module ParsedInput =
let _, r = CheckLongIdent longIdent
Some r
+ | SynExpr.DotLambda(SynExpr.LongIdent _, range, _) -> Some range
+ | SynExpr.DotLambda(synExpr, range, _) ->
+ let result = traverseSynExpr synExpr
+
+ result
+ |> Option.map (fun r -> if posEq r.Start synExpr.Range.Start then range else r)
+
| SynExpr.DotGet(synExpr, _dotm, lid, _) ->
let (SynLongIdent(longIdent, _, _)) = lid
diff --git a/src/Compiler/Service/SynExpr.fs b/src/Compiler/Service/SynExpr.fs
index 5981dd5b286..52c10e8a7a5 100644
--- a/src/Compiler/Service/SynExpr.fs
+++ b/src/Compiler/Service/SynExpr.fs
@@ -1078,6 +1078,14 @@ module SynExpr =
| SynExpr.Sequential(expr1 = SynExpr.Paren(expr = Is inner); expr2 = expr2), _ when innerBindingsWouldShadowOuter inner expr2 ->
true
+ // $"{({ A = 3 })}"
+ // $"{({| A = 3 |})}"
+ // $"{({1..10})}"
+ // $"{(();1)}"
+ // $"{(1,2)}"
+ | SynExpr.InterpolatedString _, SynExpr.Record _
+ | SynExpr.InterpolatedString _, SynExpr.AnonRecd _
+ | SynExpr.InterpolatedString _, SynExpr.ComputationExpr _
| SynExpr.InterpolatedString _, SynExpr.Sequential _
| SynExpr.InterpolatedString _, SynExpr.Tuple(isStruct = false) -> true
diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs
index 4385ca4f1e3..57bf639a224 100644
--- a/src/Compiler/Service/TransparentCompiler.fs
+++ b/src/Compiler/Service/TransparentCompiler.fs
@@ -299,7 +299,9 @@ type CacheSizes =
{
ParseFileKeepStrongly = 50 * sizeFactor
- ParseFileKeepWeakly = 20 * sizeFactor
+ // Since ParseFile version is just a content hash, we keep only one version
+ // in order to ensure that we re-parse after undo for the sake of WarnScopes
+ ParseFileKeepWeakly = 0 // 20 * sizeFactor
ParseFileWithoutProjectKeepStrongly = 5 * sizeFactor
ParseFileWithoutProjectKeepWeakly = 2 * sizeFactor
ParseAndCheckFileInProjectKeepStrongly = sizeFactor
@@ -341,7 +343,9 @@ type internal CompilerCaches(cacheSizes: CacheSizes) =
member _.CacheSizes = cs
- member val ParseFile = AsyncMemoize(keepStrongly = cs.ParseFileKeepStrongly, keepWeakly = cs.ParseFileKeepWeakly, name = "ParseFile")
+ member val ParseFile =
+ AsyncMemoize(keepStrongly = cs.ParseFileKeepStrongly, keepWeakly = cs.ParseFileKeepWeakly, name = "ParseFile")
+ : AsyncMemoize<(FSharpProjectIdentifier * string), (string * string * bool), ProjectSnapshot.FSharpParsedFile>
member val ParseFileWithoutProject =
AsyncMemoize(
@@ -1379,7 +1383,6 @@ type internal TransparentCompiler
let mainInputFileName = file.FileName
let sourceText = file.SourceText
- let parsedMainInput = file.ParsedInput
// Initialize the error handler
let errHandler =
@@ -1392,14 +1395,10 @@ type internal TransparentCompiler
tcConfig.flatErrors
)
- // Apply nowarns to tcConfig (may generate errors, so ensure diagnosticsLogger is installed)
- let tcConfig =
- ApplyNoWarnsToTcConfig(tcConfig, parsedMainInput, !!Path.GetDirectoryName(mainInputFileName))
-
let diagnosticsLogger = errHandler.DiagnosticsLogger
let diagnosticsLogger =
- GetDiagnosticsLoggerFilteringByScopedPragmas(false, input.ScopedPragmas, tcConfig.diagnosticsOptions, diagnosticsLogger)
+ GetDiagnosticsLoggerFilteringByScopedNowarn(tcConfig.diagnosticsOptions, diagnosticsLogger)
use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck)
@@ -1644,9 +1643,7 @@ type internal TransparentCompiler
let extraLogger = CapturingDiagnosticsLogger("DiagnosticsWhileCreatingDiagnostics")
use _ = new CompilationGlobalsScope(extraLogger, BuildPhase.TypeCheck)
- // Apply nowarns to tcConfig (may generate errors, so ensure diagnosticsLogger is installed)
- let tcConfig =
- ApplyNoWarnsToTcConfig(bootstrapInfo.TcConfig, parseResults.ParseTree, Path.GetDirectoryName fileName |> (!!))
+ let tcConfig = bootstrapInfo.TcConfig
let diagnosticsOptions = tcConfig.diagnosticsOptions
@@ -2077,22 +2074,20 @@ type internal TransparentCompiler
// TODO: might need to deal with exceptions here:
use _ = new CompilationGlobalsScope(DiscardErrorsLogger, BuildPhase.Parse)
- let! tcConfigB, sourceFileNames, _ = ComputeTcConfigBuilder projectSnapshot
-
- let tcConfig = TcConfig.Create(tcConfigB, validate = true)
- let _index, fileSnapshot =
- projectSnapshot.SourceFiles
- |> Seq.mapi pair
- |> Seq.tryFind (fun (_, f) -> f.FileName = fileName)
- |> Option.defaultWith (fun () -> failwith $"File not found: {fileName}")
+ match! ComputeBootstrapInfo projectSnapshot with
+ | None, creationDiags -> return emptyParseResult fileName creationDiags
+ | Some bootstrapInfo, _ ->
+ let tcConfig = bootstrapInfo.TcConfig
- let isExe = tcConfig.target.IsExe
- let isLastCompiland = fileName = (sourceFileNames |> List.last)
+ let fileSnapshot =
+ projectSnapshot.SourceFiles |> List.find (fun f -> f.FileName = fileName)
- let! file = LoadSource fileSnapshot isExe isLastCompiland
- let! parseResult = getParseResult projectSnapshot Seq.empty file tcConfig
- return parseResult
+ let isExe = tcConfig.target.IsExe
+ let isLastCompiland = fileName = List.last projectSnapshot.SourceFileNames
+ let! file = LoadSource fileSnapshot isExe isLastCompiland
+ let! parseResult = getParseResult projectSnapshot Seq.empty file tcConfig
+ return parseResult
}
member _.ParseFileWithoutProject
@@ -2417,14 +2412,7 @@ type internal TransparentCompiler
assumeDotNetFramework
otherFlags
- let otherFlags =
- [
- yield "--noframework"
- yield "--warn:3"
- yield! otherFlags
- for code, _ in loadClosure.NoWarns do
- yield "--nowarn:" + code
- ]
+ let otherFlags = [ yield "--noframework"; yield "--warn:3"; yield! otherFlags ]
// Once we do have the script closure, we can populate the cache to re-use can later.
let loadClosureKey =
diff --git a/src/Compiler/Symbols/Exprs.fs b/src/Compiler/Symbols/Exprs.fs
index 5ec81f6861d..33c87edb597 100644
--- a/src/Compiler/Symbols/Exprs.fs
+++ b/src/Compiler/Symbols/Exprs.fs
@@ -1353,7 +1353,7 @@ and FSharpImplementationFileDeclaration =
and FSharpImplementationFileContents(cenv, mimpl) =
let g = cenv.g
- let (CheckedImplFile (qname, _pragmas, _, contents, hasExplicitEntryPoint, isScript, _anonRecdTypes, _)) = mimpl
+ let (CheckedImplFile (qname, _, contents, hasExplicitEntryPoint, isScript, _anonRecdTypes, _)) = mimpl
let rec getBind (bind: Binding) =
let v = bind.Var
assert v.IsCompiledAsTopLevel
diff --git a/src/Compiler/Symbols/Symbols.fs b/src/Compiler/Symbols/Symbols.fs
index 48acdf03dae..5e20f00b48b 100644
--- a/src/Compiler/Symbols/Symbols.fs
+++ b/src/Compiler/Symbols/Symbols.fs
@@ -360,7 +360,8 @@ type FSharpEntity(cenv: SymbolEnv, entity: EntityRef, tyargs: TType list) =
inherit FSharpSymbol(cenv,
(fun () ->
checkEntityIsResolved entity
- if entity.IsModuleOrNamespace then Item.ModuleOrNamespaces [entity]
+ if entity.IsModuleOrNamespace then Item.ModuleOrNamespaces [entity]
+ elif entity.IsFSharpException then Item.ExnCase entity
else Item.UnqualifiedType [entity]),
(fun _this thisCcu2 ad ->
checkForCrossProjectAccessibility cenv.g.ilg (thisCcu2, ad) (cenv.thisCcu, getApproxFSharpAccessibilityOfEntity entity))
diff --git a/src/Compiler/SyntaxTree/LexFilter.fs b/src/Compiler/SyntaxTree/LexFilter.fs
index 20af46524b0..a97fb94d5e4 100644
--- a/src/Compiler/SyntaxTree/LexFilter.fs
+++ b/src/Compiler/SyntaxTree/LexFilter.fs
@@ -1093,7 +1093,7 @@ type LexFilterImpl (
scanAhead nParen
else
false
- | GREATER _ | GREATER_RBRACK | GREATER_BAR_RBRACK ->
+ | GREATER _ | GREATER_RBRACK | GREATER_BAR_RBRACK | GREATER_BAR_RBRACE ->
let nParen = nParen - 1
let hasAfterOp = (match lookaheadToken with GREATER _ -> false | _ -> true)
if nParen > 0 then
@@ -1201,6 +1201,11 @@ type LexFilterImpl (
delayToken (pool.UseShiftedLocation(tokenTup, INFIX_AT_HAT_OP "@", 1, 0))
delayToken (pool.UseShiftedLocation(tokenTup, LESS res, 0, -1))
pool.Return tokenTup
+ | GREATER_BAR_RBRACE ->
+ lexbuf.CheckLanguageFeatureAndRecover LanguageFeature.BetterAnonymousRecordParsing lexbuf.LexemeRange
+ delayToken (pool.UseShiftedLocation(tokenTup, BAR_RBRACE, 1, 0))
+ delayToken (pool.UseShiftedLocation(tokenTup, GREATER res, 0, -2))
+ pool.Return tokenTup
| GREATER_BAR_RBRACK ->
delayToken (pool.UseShiftedLocation(tokenTup, BAR_RBRACK, 1, 0))
delayToken (pool.UseShiftedLocation(tokenTup, GREATER res, 0, -2))
diff --git a/src/Compiler/SyntaxTree/LexHelpers.fs b/src/Compiler/SyntaxTree/LexHelpers.fs
index faf85ad811d..dddaaa37a94 100644
--- a/src/Compiler/SyntaxTree/LexHelpers.fs
+++ b/src/Compiler/SyntaxTree/LexHelpers.fs
@@ -9,17 +9,16 @@ open Internal.Utilities
open Internal.Utilities.Library
open Internal.Utilities.Text.Lexing
-open FSharp.Compiler.IO
open FSharp.Compiler.DiagnosticsLogger
open FSharp.Compiler.Features
-open FSharp.Compiler.LexerStore
+open FSharp.Compiler.IO
open FSharp.Compiler.ParseHelpers
-open FSharp.Compiler.UnicodeLexing
open FSharp.Compiler.Parser
open FSharp.Compiler.Syntax
open FSharp.Compiler.Syntax.PrettyNaming
open FSharp.Compiler.Text
open FSharp.Compiler.Text.Range
+open FSharp.Compiler.UnicodeLexing
/// The "mock" file name used by fsi.exe when reading from stdin.
/// Has special treatment by the lexer, i.e. __SOURCE_DIRECTORY__ becomes GetCurrentDirectory()
diff --git a/src/Compiler/SyntaxTree/LexerStore.fs b/src/Compiler/SyntaxTree/LexerStore.fs
index 2914d944c20..e2c6010a561 100644
--- a/src/Compiler/SyntaxTree/LexerStore.fs
+++ b/src/Compiler/SyntaxTree/LexerStore.fs
@@ -4,40 +4,18 @@ module internal FSharp.Compiler.LexerStore
open FSharp.Compiler.SyntaxTreeOps
open FSharp.Compiler.SyntaxTrivia
-open FSharp.Compiler.UnicodeLexing
open FSharp.Compiler.Text
open FSharp.Compiler.Text.Position
open FSharp.Compiler.Text.Range
+open FSharp.Compiler.UnicodeLexing
open FSharp.Compiler.Xml
-//------------------------------------------------------------------------
-// Lexbuf.BufferLocalStore is used during lexing/parsing of a file for different purposes.
-// All access happens through the functions and modules below.
-//------------------------------------------------------------------------
-
-let private getStoreData<'T when 'T: not null> (lexbuf: Lexbuf) key (getInitialData: unit -> 'T) =
- let store = lexbuf.BufferLocalStore
-
- match store.TryGetValue key with
- | true, data -> data :?> 'T
- | _ ->
- let data = getInitialData ()
- store[key] <- data
- data
-
-let private tryGetStoreData<'T when 'T: not null> (lexbuf: Lexbuf) key =
- let store = lexbuf.BufferLocalStore
-
- match store.TryGetValue key with
- | true, data -> Some(data :?> 'T)
- | _ -> None
-
//------------------------------------------------------------------------
// A SynArgNameGenerator for the current file, used by the parser
//------------------------------------------------------------------------
let getSynArgNameGenerator (lexbuf: Lexbuf) =
- getStoreData lexbuf "SynArgNameGenerator" SynArgNameGenerator
+ lexbuf.GetLocalData("SynArgNameGenerator", SynArgNameGenerator)
//------------------------------------------------------------------------
// A XmlDocCollector, used to hold the current accumulated Xml doc lines, and related access functions
@@ -47,8 +25,8 @@ let getSynArgNameGenerator (lexbuf: Lexbuf) =
module XmlDocStore =
let private xmlDocKey = "XmlDoc"
- let private getCollector (lexbuf: Lexbuf) =
- getStoreData lexbuf xmlDocKey XmlDocCollector
+ let private getCollector (lexbuf: Lexbuf) : XmlDocCollector =
+ lexbuf.GetLocalData(xmlDocKey, XmlDocCollector)
/// Called from the lexer to save a single line of XML doc comment.
let SaveXmlDocLine (lexbuf: Lexbuf, lineText, range: range) =
@@ -78,9 +56,9 @@ module XmlDocStore =
/// Called from the parser each time we parse a construct that marks the end of an XML doc comment range,
/// e.g. a 'type' declaration. The markerRange is the range of the keyword that delimits the construct.
let GrabXmlDocBeforeMarker (lexbuf: Lexbuf, markerRange: range) =
- match tryGetStoreData lexbuf xmlDocKey with
+ match lexbuf.TryGetLocalData xmlDocKey with
| Some collector -> PreXmlDoc.CreateFromGrabPoint(collector, markerRange.Start)
- | _ -> PreXmlDoc.Empty
+ | None -> PreXmlDoc.Empty
let ReportInvalidXmlDocPositions (lexbuf: Lexbuf) =
let collector = getCollector lexbuf
@@ -106,7 +84,7 @@ let rec LexerIfdefEval (lookup: string -> bool) =
[]
module IfdefStore =
let private getStore (lexbuf: Lexbuf) =
- getStoreData lexbuf "Ifdef" ResizeArray
+ lexbuf.GetLocalData("Ifdef", ResizeArray)
let private mkRangeWithoutLeadingWhitespace (lexed: string) (m: range) : range =
let startColumn = lexed.Length - lexed.TrimStart().Length
@@ -150,7 +128,7 @@ module IfdefStore =
[]
module CommentStore =
let private getStore (lexbuf: Lexbuf) =
- getStoreData lexbuf "Comments" ResizeArray
+ lexbuf.GetLocalData("Comments", ResizeArray)
let SaveSingleLineComment (lexbuf: Lexbuf, startRange: range, endRange: range) =
let store = getStore lexbuf
diff --git a/src/Compiler/SyntaxTree/LexerStore.fsi b/src/Compiler/SyntaxTree/LexerStore.fsi
index 952a0cc6f81..e6bda944438 100644
--- a/src/Compiler/SyntaxTree/LexerStore.fsi
+++ b/src/Compiler/SyntaxTree/LexerStore.fsi
@@ -4,8 +4,8 @@ module internal FSharp.Compiler.LexerStore
open FSharp.Compiler.SyntaxTreeOps
open FSharp.Compiler.SyntaxTrivia
-open FSharp.Compiler.UnicodeLexing
open FSharp.Compiler.Text
+open FSharp.Compiler.UnicodeLexing
open FSharp.Compiler.Xml
val getSynArgNameGenerator: Lexbuf -> SynArgNameGenerator
diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fs b/src/Compiler/SyntaxTree/ParseHelpers.fs
index a8a8724f58b..62eb2159081 100644
--- a/src/Compiler/SyntaxTree/ParseHelpers.fs
+++ b/src/Compiler/SyntaxTree/ParseHelpers.fs
@@ -85,7 +85,7 @@ type LexerIfdefStack = LexerIfdefStackEntries
/// Specifies how the 'endline' function in the lexer should continue after
/// it reaches end of line or eof. The options are to continue with 'token' function
-/// or to continue with 'skip' function.
+/// or to continue with 'ifdefSkip' function.
[]
type LexerEndlineContinuation =
| Token
diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs
index bd918e8848a..978a75ab6cc 100644
--- a/src/Compiler/SyntaxTree/SyntaxTree.fs
+++ b/src/Compiler/SyntaxTree/SyntaxTree.fs
@@ -1759,9 +1759,6 @@ type ParsedImplFile = ParsedImplFile of hashDirectives: ParsedHashDirective list
[]
type ParsedSigFile = ParsedSigFile of hashDirectives: ParsedHashDirective list * fragments: ParsedSigFileFragment list
-[]
-type ScopedPragma = WarningOff of range: range * warningNumber: int
-
[]
type QualifiedNameOfFile =
| QualifiedNameOfFile of Ident
@@ -1778,19 +1775,15 @@ type ParsedImplFileInput =
fileName: string *
isScript: bool *
qualifiedNameOfFile: QualifiedNameOfFile *
- scopedPragmas: ScopedPragma list *
hashDirectives: ParsedHashDirective list *
contents: SynModuleOrNamespace list *
flags: (bool * bool) *
- trivia: ParsedImplFileInputTrivia *
+ trivia: ParsedInputTrivia *
identifiers: Set
member x.QualifiedName =
(let (ParsedImplFileInput(qualifiedNameOfFile = qualNameOfFile)) = x in qualNameOfFile)
- member x.ScopedPragmas =
- (let (ParsedImplFileInput(scopedPragmas = scopedPragmas)) = x in scopedPragmas)
-
member x.HashDirectives =
(let (ParsedImplFileInput(hashDirectives = hashDirectives)) = x in hashDirectives)
@@ -1812,18 +1805,14 @@ type ParsedSigFileInput =
| ParsedSigFileInput of
fileName: string *
qualifiedNameOfFile: QualifiedNameOfFile *
- scopedPragmas: ScopedPragma list *
hashDirectives: ParsedHashDirective list *
contents: SynModuleOrNamespaceSig list *
- trivia: ParsedSigFileInputTrivia *
+ trivia: ParsedInputTrivia *
identifiers: Set
member x.QualifiedName =
(let (ParsedSigFileInput(qualifiedNameOfFile = qualNameOfFile)) = x in qualNameOfFile)
- member x.ScopedPragmas =
- (let (ParsedSigFileInput(scopedPragmas = scopedPragmas)) = x in scopedPragmas)
-
member x.HashDirectives =
(let (ParsedSigFileInput(hashDirectives = hashDirectives)) = x in hashDirectives)
@@ -1844,11 +1833,6 @@ type ParsedInput =
| ParsedInput.ImplFile file -> file.FileName
| ParsedInput.SigFile file -> file.FileName
- member inp.ScopedPragmas =
- match inp with
- | ParsedInput.ImplFile file -> file.ScopedPragmas
- | ParsedInput.SigFile file -> file.ScopedPragmas
-
member inp.QualifiedName =
match inp with
| ParsedInput.ImplFile file -> file.QualifiedName
diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fsi b/src/Compiler/SyntaxTree/SyntaxTree.fsi
index f50adfa289d..30ecc56c166 100644
--- a/src/Compiler/SyntaxTree/SyntaxTree.fsi
+++ b/src/Compiler/SyntaxTree/SyntaxTree.fsi
@@ -1933,12 +1933,6 @@ type ParsedImplFile =
[]
type ParsedSigFile = ParsedSigFile of hashDirectives: ParsedHashDirective list * fragments: ParsedSigFileFragment list
-/// Represents a scoped pragma
-[]
-type ScopedPragma =
- /// A pragma to turn a warning off
- | WarningOff of range: range * warningNumber: int
-
/// Represents a qualifying name for anonymous module specifications and implementations,
[]
type QualifiedNameOfFile =
@@ -1960,11 +1954,10 @@ type ParsedImplFileInput =
fileName: string *
isScript: bool *
qualifiedNameOfFile: QualifiedNameOfFile *
- scopedPragmas: ScopedPragma list *
hashDirectives: ParsedHashDirective list *
contents: SynModuleOrNamespace list *
flags: (bool * bool) *
- trivia: ParsedImplFileInputTrivia *
+ trivia: ParsedInputTrivia *
identifiers: Set
member FileName: string
@@ -1973,13 +1966,11 @@ type ParsedImplFileInput =
member QualifiedName: QualifiedNameOfFile
- member ScopedPragmas: ScopedPragma list
-
member HashDirectives: ParsedHashDirective list
member Contents: SynModuleOrNamespace list
- member Trivia: ParsedImplFileInputTrivia
+ member Trivia: ParsedInputTrivia
member IsLastCompiland: bool
@@ -1991,23 +1982,20 @@ type ParsedSigFileInput =
| ParsedSigFileInput of
fileName: string *
qualifiedNameOfFile: QualifiedNameOfFile *
- scopedPragmas: ScopedPragma list *
hashDirectives: ParsedHashDirective list *
contents: SynModuleOrNamespaceSig list *
- trivia: ParsedSigFileInputTrivia *
+ trivia: ParsedInputTrivia *
identifiers: Set
member FileName: string
member QualifiedName: QualifiedNameOfFile
- member ScopedPragmas: ScopedPragma list
-
member HashDirectives: ParsedHashDirective list
member Contents: SynModuleOrNamespaceSig list
- member Trivia: ParsedSigFileInputTrivia
+ member Trivia: ParsedInputTrivia
/// Represents the syntax tree for a parsed implementation or signature file
[]
@@ -2027,8 +2015,5 @@ type ParsedInput =
/// Gets the qualified name used to help match signature and implementation files
member QualifiedName: QualifiedNameOfFile
- /// Gets the #nowarn and other scoped pragmas
- member ScopedPragmas: ScopedPragma list
-
/// Gets a set of all identifiers used in this parsed input. Only populated if captureIdentifiersWhenParsing option was used.
member Identifiers: Set
diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs
index 6633dab2408..616191c9b5a 100644
--- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs
+++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs
@@ -103,6 +103,8 @@ let rec pushUnaryArg expr arg =
SynExpr.TypeApp(innerExpr, mLess, tyargs, mCommas, mGreater, mTypars, m)
| SynExpr.ArbitraryAfterError(_, m) when m.Start = m.End ->
SynExpr.DiscardAfterMissingQualificationAfterDot(SynExpr.Ident arg, m.StartRange, unionRanges arg.idRange m)
+ | SynExpr.DiscardAfterMissingQualificationAfterDot(synExpr, dotRange, m) ->
+ SynExpr.DiscardAfterMissingQualificationAfterDot(pushUnaryArg synExpr arg, dotRange, unionRanges arg.idRange m)
| _ ->
errorR (Error(FSComp.SR.tcDotLambdaAtNotSupportedExpression (), expr.Range))
expr
diff --git a/src/Compiler/SyntaxTree/SyntaxTrivia.fs b/src/Compiler/SyntaxTree/SyntaxTrivia.fs
index 2cd42701e70..2137ffe4275 100644
--- a/src/Compiler/SyntaxTree/SyntaxTrivia.fs
+++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fs
@@ -22,24 +22,30 @@ and [] IfDirectiveExpression =
| Not of IfDirectiveExpression
| Ident of string
+[]
+type WarnDirectiveTrivia =
+ | Nowarn of warnNumbers: int list * range
+ | Warnon of warnNumbers: int list * range
+
[]
type CommentTrivia =
| LineComment of range: range
| BlockComment of range: range
[]
-type ParsedImplFileInputTrivia =
+type ParsedInputTrivia =
{
ConditionalDirectives: ConditionalDirectiveTrivia list
+ WarnDirectives: WarnDirectiveTrivia list
CodeComments: CommentTrivia list
}
-[]
-type ParsedSigFileInputTrivia =
- {
- ConditionalDirectives: ConditionalDirectiveTrivia list
- CodeComments: CommentTrivia list
- }
+ static member Empty =
+ {
+ ConditionalDirectives = []
+ WarnDirectives = []
+ CodeComments = []
+ }
[]
type SynExprTryWithTrivia =
diff --git a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi
index ab6525bc010..9d4e50ce1f4 100644
--- a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi
+++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi
@@ -34,33 +34,32 @@ type IfDirectiveExpression =
| Not of IfDirectiveExpression
| Ident of string
+[]
+type WarnDirectiveTrivia =
+ | Nowarn of warnNumbers: int list * range
+ | Warnon of warnNumbers: int list * range
+
[]
type CommentTrivia =
| LineComment of range: range
| BlockComment of range: range
-/// Represents additional information for ParsedImplFileInput
+/// Represents additional information for ParsedInput
[]
-type ParsedImplFileInputTrivia =
+type ParsedInputTrivia =
{
/// Preprocessor directives of type #if, #else or #endif
ConditionalDirectives: ConditionalDirectiveTrivia list
- /// Represent code comments found in the source file
- CodeComments: CommentTrivia list
- }
-
-/// Represents additional information for ParsedSigFileInputTrivia
-[]
-type ParsedSigFileInputTrivia =
- {
- /// Preprocessor directives of type #if, #else or #endif
- ConditionalDirectives: ConditionalDirectiveTrivia list
+ /// Warn directives (#nowarn / #warnon)
+ WarnDirectives: WarnDirectiveTrivia list
/// Represent code comments found in the source file
CodeComments: CommentTrivia list
}
+ static member internal Empty: ParsedInputTrivia
+
/// Represents additional information for SynExpr.TryWith
[]
type SynExprTryWithTrivia =
diff --git a/src/Compiler/SyntaxTree/UnicodeLexing.fs b/src/Compiler/SyntaxTree/UnicodeLexing.fs
index abb3d0e3d83..4ea41cbcf84 100644
--- a/src/Compiler/SyntaxTree/UnicodeLexing.fs
+++ b/src/Compiler/SyntaxTree/UnicodeLexing.fs
@@ -8,6 +8,21 @@ open Internal.Utilities.Text.Lexing
type Lexbuf = LexBuffer
+type LexBuffer<'char> with
+
+ member lexbuf.GetLocalData<'T when 'T: not null>(key: string, initializer) =
+ match lexbuf.BufferLocalStore.TryGetValue key with
+ | true, data -> data :?> 'T
+ | _ ->
+ let data = initializer ()
+ lexbuf.BufferLocalStore[key] <- data
+ data
+
+ member lexbuf.TryGetLocalData<'T when 'T: not null>(key: string) =
+ match lexbuf.BufferLocalStore.TryGetValue key with
+ | true, data -> Some(data :?> 'T)
+ | _ -> None
+
let StringAsLexbuf (reportLibraryOnlyFeatures, langVersion, strictIndentation, s: string) =
LexBuffer.FromChars(reportLibraryOnlyFeatures, langVersion, strictIndentation, s.ToCharArray())
diff --git a/src/Compiler/SyntaxTree/UnicodeLexing.fsi b/src/Compiler/SyntaxTree/UnicodeLexing.fsi
index 80d772e03e1..ee722ee08c3 100644
--- a/src/Compiler/SyntaxTree/UnicodeLexing.fsi
+++ b/src/Compiler/SyntaxTree/UnicodeLexing.fsi
@@ -9,6 +9,10 @@ open Internal.Utilities.Text.Lexing
type Lexbuf = LexBuffer
+type LexBuffer<'char> with
+ member GetLocalData<'T when 'T: not null> : key: string * initializer: (unit -> 'T) -> 'T
+ member TryGetLocalData<'T when 'T: not null> : key: string -> 'T option
+
val StringAsLexbuf:
reportLibraryOnlyFeatures: bool * langVersion: LanguageVersion * strictIndentation: bool option * string -> Lexbuf
diff --git a/src/Compiler/SyntaxTree/WarnScopes.fs b/src/Compiler/SyntaxTree/WarnScopes.fs
new file mode 100644
index 00000000000..2efab44f5de
--- /dev/null
+++ b/src/Compiler/SyntaxTree/WarnScopes.fs
@@ -0,0 +1,441 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace FSharp.Compiler
+
+open FSharp.Compiler.Diagnostics
+open FSharp.Compiler.DiagnosticsLogger
+open FSharp.Compiler.Features
+open FSharp.Compiler.SyntaxTrivia
+open FSharp.Compiler.Text
+open FSharp.Compiler.Text.Position
+open FSharp.Compiler.Text.Range
+open FSharp.Compiler.UnicodeLexing
+open Internal.Utilities.Library
+open System.Text.RegularExpressions
+
+[]
+module internal WarnScopes =
+
+ // *************************************
+ // Temporary storage (during lexing one file) for warn scope related data
+ // *************************************
+
+ type private FileIndex = int
+ type private WarningNumber = int
+ type private LineNumber = int
+
+ []
+ type private WarnCmd =
+ | Nowarn of WarningNumber * range
+ | Warnon of WarningNumber * range
+
+ member w.WarningNumber =
+ match w with
+ | Nowarn(n, _)
+ | Warnon(n, _) -> n
+
+ type private WarnDirective =
+ {
+ DirectiveRange: range
+ CommentRange: range option
+ WarnCmds: WarnCmd list
+ }
+
+ let private isWarnonDirective (w: WarnDirective) =
+ match w.WarnCmds with
+ | [] -> false
+ | h :: _ -> h.IsWarnon
+
+ type private LineDirective =
+ {
+ SurrogateFileIndex: FileIndex
+ SurrogateLine: LineNumber
+ OriginalLine: LineNumber
+ }
+
+ type private LexbufData =
+ {
+ OriginalFileIndex: int
+ mutable WarnDirectives: WarnDirective list
+ mutable LineDirectives: LineDirective list
+ }
+
+ let private initialData (lexbuf: Lexbuf) =
+ {
+ OriginalFileIndex = lexbuf.StartPos.FileIndex
+ WarnDirectives = []
+ LineDirectives = []
+ }
+
+ let private getLexbufData (lexbuf: Lexbuf) =
+ lexbuf.GetLocalData("WarnScopeData", (fun () -> initialData lexbuf))
+
+ // *************************************
+ // Collect the line directives during lexing
+ // *************************************
+
+ let RegisterLineDirective (lexbuf, fileIndex, line: int) = //TODO: send OriginalLine i.o. lexbuf
+ let data = getLexbufData lexbuf
+
+ let lineDirective =
+ {
+ SurrogateFileIndex = fileIndex
+ SurrogateLine = line
+ OriginalLine = lexbuf.StartPos.OriginalLine + 1
+ }
+
+ data.LineDirectives <- lineDirective :: data.LineDirectives
+
+ // *************************************
+ // Collect the warn scopes during lexing
+ // *************************************
+
+ let private getNumber (langVersion: LanguageVersion) m (ns: string) =
+ let argFeature = LanguageFeature.ParsedHashDirectiveArgumentNonQuotes
+
+ let removeQuotes (s: string) =
+ if s.StartsWithOrdinal "\"" && s.EndsWithOrdinal "\"" then
+ if s.StartsWithOrdinal "\"\"\"" && s.EndsWithOrdinal "\"\"\"" then
+ Some(s.Substring(3, s.Length - 6))
+ else
+ Some(s.Substring(1, s.Length - 2))
+ elif tryCheckLanguageFeatureAndRecover langVersion argFeature m then
+ Some s
+ else
+ None
+
+ let removePrefix (s: string) =
+ match s.StartsWithOrdinal "FS", langVersion.SupportsFeature argFeature with
+ | true, true -> Some(s.Substring 2, s)
+ | true, false ->
+ warning (Error(FSComp.SR.buildInvalidWarningNumber s, m))
+ None
+ | false, _ -> Some(s, s)
+
+ let parseInt (intString: string, argString) =
+ match System.Int32.TryParse intString with
+ | true, i -> Some i
+ | false, _ ->
+ if langVersion.SupportsFeature LanguageFeature.ScopedNowarn then
+ errorR (Error(FSComp.SR.buildInvalidWarningNumber argString, m))
+ elif langVersion.SupportsFeature argFeature then
+ warning (Error(FSComp.SR.buildInvalidWarningNumber argString, m))
+
+ None
+
+ ns |> removeQuotes |> Option.bind removePrefix |> Option.bind parseInt
+
+ let private regex =
+ // This regex is matching the following lexer pattern that brought us here:
+ // anywhite* ("#nowarn" | "#warnon") anystring newline
+ // while extracting from "anystring" the directive arguments and the comment.
+ // A directive argument is any group of characters that is not a space, a newline, a slash or a semicolon.
+ // Both the presence and syntactic correctness of the directive arguments are checked later.
+ // For compatibility reasons, the arguments are allowed to be followed by a double semicolon.
+ // The comment is optional and starts with "//".
+ // The "(?: ...)?" is just a way to make the arguments optional while not interfering with the capturing.
+ // Matching a directive with this regex creates 5 groups (next to the full match):
+ // 1. The leading whitespace.
+ // 2. The directive identifier ("nowarn" or "warnon", possibly followed by additional characters).
+ // 3. The directive arguments (if any), with each argument in a separate capture.
+ // 4. The trailing whitespace.
+ // 5. The comment (if any).
+
+ Regex("""( *)#(\S+)(?: +([^ \r\n/;]+))*(?:;;)?( *)(\/\/.*)?$""", RegexOptions.CultureInvariant)
+
+ let private parseDirective originalFileIndex lexbuf =
+ let text = Lexbuf.LexemeString lexbuf
+ let startPos = lexbuf.StartPos
+
+ let mGroups = (regex.Match text).Groups
+ let dIdentGroup = mGroups[2]
+ let dIdent = dIdentGroup.Value
+ let argsGroup = mGroups[3]
+ let argCaptures = [ for c in argsGroup.Captures -> c ]
+ let commentGroup = mGroups[5]
+
+ let positions line offset length =
+ mkPos line (startPos.Column + offset), mkPos line (startPos.Column + offset + length)
+ // "normal" ranges (i.e. taking #line directives into account), for errors in the warn directive
+ let mkRange offset length =
+ positions lexbuf.StartPos.Line offset length
+ ||> mkFileIndexRange startPos.FileIndex
+ // "original" ranges, for the warn scopes
+ let mkOriginalRange offset length =
+ positions lexbuf.StartPos.OriginalLine offset length
+ ||> mkFileIndexRange originalFileIndex
+
+ let directiveLength =
+ if argsGroup.Success then
+ argsGroup.Index - (dIdentGroup.Index - 1) + argsGroup.Length
+ else
+ dIdentGroup.Length + 1
+
+ let directiveRange = mkRange (dIdentGroup.Index - 1) directiveLength
+
+ let commentRange =
+ if commentGroup.Success then
+ Some(mkRange commentGroup.Index commentGroup.Length)
+ else
+ None
+
+ if argCaptures.IsEmpty then
+ errorR (Error(FSComp.SR.lexWarnDirectiveMustHaveArgs (), directiveRange))
+
+ let mkDirective ctor (c: Capture) =
+ getNumber lexbuf.LanguageVersion (mkRange c.Index c.Length) c.Value
+ |> Option.map (fun n -> ctor (n, mkOriginalRange c.Index c.Length))
+
+ let warnCmds =
+ match dIdent with
+ | "warnon" -> argCaptures |> List.choose (mkDirective WarnCmd.Warnon)
+ | "nowarn" -> argCaptures |> List.choose (mkDirective WarnCmd.Nowarn)
+ | _ ->
+ errorR (Error(FSComp.SR.fsiInvalidDirective ($"#{dIdent}", ""), directiveRange))
+ []
+
+ {
+ DirectiveRange = directiveRange
+ CommentRange = commentRange
+ WarnCmds = warnCmds
+ }
+
+ let ParseAndRegisterWarnDirective (lexbuf: Lexbuf) =
+ let data = getLexbufData lexbuf
+ let warnDirective = parseDirective data.OriginalFileIndex lexbuf
+ data.WarnDirectives <- warnDirective :: data.WarnDirectives
+
+ // *************************************
+ // After lexing, the (processed) warn scope data are kept in diagnosticOptions
+ // *************************************
+
+ []
+ type private WarnScope =
+ | Off of range
+ | On of range
+ | OpenOff of range
+ | OpenOn of range
+
+ /// Information about the mapping implied by the #line directives.
+ /// The Map key is the file index of the surrogate source (the source file pointed to by the line directive).
+ /// The Map value contains the file index of the original source (the one just being parsed) and
+ /// a list of mapped sections (surrogate and original start lines).
+ type private LineMaps = Map
+
+ type private WarnScopeData =
+ {
+ ScopedNowarnFeatureIsSupported: bool
+ ScriptNowarns: WarningNumber list // only needed to avoid breaking changes for previous language versions
+ WarnScopes: Map>
+ LineMaps: LineMaps
+ }
+
+ let private getWarnScopeData (diagnosticOptions: FSharpDiagnosticOptions) =
+ match diagnosticOptions.WarnScopeData with
+ | None ->
+ {
+ ScopedNowarnFeatureIsSupported = true
+ ScriptNowarns = []
+ WarnScopes = Map.empty
+ LineMaps = Map.empty
+ }
+ | Some data -> data :?> WarnScopeData
+
+ let private setWarnScopeData (diagnosticOptions: FSharpDiagnosticOptions) data =
+ diagnosticOptions.WarnScopeData <- Some data
+
+ // *************************************
+ // Create the warn scopes from the directives and store them in diagnosticOptions.
+ // *************************************
+
+ let MergeInto diagnosticOptions isScript subModuleRanges lexbuf =
+ let lexbufData = getLexbufData lexbuf
+ let fileIndex = lexbufData.OriginalFileIndex
+
+ let scopedNowarnFeatureIsSupported =
+ lexbuf.LanguageVersion.SupportsFeature LanguageFeature.ScopedNowarn
+
+ let fileWarnCmds, fileScriptNowarns =
+ let warnDirectives = lexbufData.WarnDirectives |> List.rev
+
+ if scopedNowarnFeatureIsSupported then
+ List.collect _.WarnCmds warnDirectives, []
+ else
+ let isInSubmodule (warnDirective: WarnDirective) =
+ List.exists (fun mRange -> rangeContainsRange mRange warnDirective.DirectiveRange) subModuleRanges
+
+ let subModuleWarnDirectives, topLevelWarnDirectives =
+ List.partition isInSubmodule warnDirectives
+
+ // Warn about and ignore directives in submodules
+ subModuleWarnDirectives
+ |> List.iter (fun wd -> warning (Error(FSComp.SR.buildDirectivesInModulesAreIgnored (), wd.DirectiveRange)))
+
+ let topLevelWarnonDirectives, topLevelNowarnDirectives =
+ List.partition isWarnonDirective topLevelWarnDirectives
+
+ // "feature not available in this language version" error for top-level #nowarn
+ topLevelWarnonDirectives
+ |> List.iter (fun wd -> errorR (languageFeatureError lexbuf.LanguageVersion LanguageFeature.ScopedNowarn wd.DirectiveRange))
+
+ let nowarnCmds = List.collect _.WarnCmds topLevelNowarnDirectives
+
+ nowarnCmds,
+ if isScript then
+ nowarnCmds |> List.map _.WarningNumber
+ else
+ []
+
+ let processWarnCmd warnScopeMap warnCmd =
+ let getScopes warningNumber warnScopes =
+ Map.tryFind warningNumber warnScopes |> Option.defaultValue []
+
+ let mkScope (m1: range) (m2: range) =
+ mkFileIndexRange m1.FileIndex m1.Start m2.End
+
+ match warnCmd with
+ | WarnCmd.Nowarn(n, m) ->
+ match getScopes n warnScopeMap with
+ | WarnScope.OpenOn m' :: t -> warnScopeMap.Add(n, WarnScope.On(mkScope m' m) :: t)
+ | WarnScope.OpenOff m' :: _
+ | WarnScope.On m' :: _ ->
+ if scopedNowarnFeatureIsSupported then
+ informationalWarning (Error(FSComp.SR.lexWarnDirectivesMustMatch ("#nowarn", m'.StartLine), m))
+
+ warnScopeMap
+ | scopes -> warnScopeMap.Add(n, WarnScope.OpenOff(mkScope m m) :: scopes)
+ | WarnCmd.Warnon(n, m) ->
+ match getScopes n warnScopeMap with
+ | WarnScope.OpenOff m' :: t -> warnScopeMap.Add(n, WarnScope.Off(mkScope m' m) :: t)
+ | WarnScope.OpenOn m' :: _
+ | WarnScope.Off m' :: _ ->
+ warning (Error(FSComp.SR.lexWarnDirectivesMustMatch ("#warnon", m'.EndLine), m))
+ warnScopeMap
+ | scopes -> warnScopeMap.Add(n, WarnScope.OpenOn(mkScope m m) :: scopes)
+
+ let fileWarnScopes = fileWarnCmds |> List.fold processWarnCmd Map.empty
+
+ let fileLineMaps: LineMaps =
+ let sortedSectionMaps =
+ List.map (fun ld -> ld.SurrogateLine, ld.OriginalLine) >> List.sortBy fst
+
+ lexbufData.LineDirectives
+ |> List.groupBy _.SurrogateFileIndex
+ |> List.map (fun (surrIdx, lineDirectives) -> surrIdx, (fileIndex, sortedSectionMaps lineDirectives))
+ |> Map
+
+ let merge () =
+ let projectData = getWarnScopeData diagnosticOptions
+
+ // If the same file is parsed again (same fileIndex), we replace the warn scopes.
+ let projectWarnScopes = projectData.WarnScopes.Add(fileIndex, fileWarnScopes)
+
+ // If the same surrogate file has entries already (from another parse), we replace the line maps.
+ // However, if it was referred to from a different original file before, we issue a warning.
+ // (Because it means the maps are not reliable.)
+ let projectLineMaps =
+ let checkAndAdd previousLinemaps surrIdx (newOrigIdx, linePairList as newLinemaps) =
+ match Map.tryFind surrIdx previousLinemaps with
+ | Some(origIdx, _) when origIdx <> newOrigIdx ->
+ let _, origLine = List.head linePairList
+ let m = mkFileIndexRange origIdx (mkPos origLine 0) (mkPos origLine 4)
+
+ let getName idx =
+ FileIndex.fileOfFileIndex idx |> System.IO.Path.GetFileName |> string
+
+ warning (Error(FSComp.SR.lexLineDirectiveMappingIsNotUnique (getName surrIdx, getName origIdx), m))
+ | _ -> ()
+
+ Map.add surrIdx newLinemaps previousLinemaps
+
+ Map.fold checkAndAdd projectData.LineMaps fileLineMaps
+
+ let newWarnScopeData =
+ {
+ ScopedNowarnFeatureIsSupported = scopedNowarnFeatureIsSupported
+ ScriptNowarns = List.distinct (projectData.ScriptNowarns @ fileScriptNowarns)
+ WarnScopes = projectWarnScopes
+ LineMaps = projectLineMaps
+ }
+
+ setWarnScopeData diagnosticOptions newWarnScopeData
+
+ lock diagnosticOptions merge
+
+ let getDirectiveTrivia (lexbuf: Lexbuf) =
+ let mkTrivia d =
+ if isWarnonDirective d then
+ WarnDirectiveTrivia.Warnon(d.WarnCmds |> List.map _.WarningNumber, d.DirectiveRange)
+ else
+ WarnDirectiveTrivia.Nowarn(d.WarnCmds |> List.map _.WarningNumber, d.DirectiveRange)
+
+ (getLexbufData lexbuf).WarnDirectives |> List.rev |> List.map mkTrivia
+
+ let getCommentTrivia (lexbuf: Lexbuf) =
+ (getLexbufData lexbuf).WarnDirectives
+ |> List.rev
+ |> List.choose _.CommentRange
+ |> List.map CommentTrivia.LineComment
+
+ // *************************************
+ // Apply the warn scopes after lexing
+ // *************************************
+
+ let private getScopes fileIndex warningNumber warnScopes =
+ Map.tryFind fileIndex warnScopes
+ |> Option.bind (Map.tryFind warningNumber)
+ |> Option.defaultValue []
+
+ let private originalRange lineMaps (m: range) =
+ match Map.tryFind m.FileIndex lineMaps with
+ | None -> m
+ | Some(origFileIndex, sectionMaps) ->
+ let surrLine, origLine =
+ if List.isEmpty sectionMaps || m.StartLine < fst sectionMaps.Head then
+ (1, 1)
+ else
+ sectionMaps |> List.skipWhile (fun (s, _) -> m.StartLine < s) |> List.head
+
+ let origStart = mkPos (m.StartLine + origLine - surrLine) m.StartColumn
+ let origEnd = mkPos (m.EndLine + origLine - surrLine) m.EndColumn
+ mkFileIndexRange origFileIndex origStart origEnd
+
+ // true if m1 contains the *start* of m2
+ // i.e. if the error range encloses the closing warn directive, we still say it is in scope
+ let private contains (m2: range) (m1: range) =
+ m2.StartLine > m1.StartLine && m2.StartLine < m1.EndLine
+
+ let private isEnclosingWarnonScope m scope =
+ match scope with
+ | WarnScope.On wm when contains m wm -> true
+ | WarnScope.OpenOn wm when m.StartLine > wm.StartLine -> true
+ | _ -> false
+
+ let private isEnclosingNowarnScope m scope =
+ match scope with
+ | WarnScope.Off wm when contains m wm -> true
+ | WarnScope.OpenOff wm when m.StartLine > wm.StartLine -> true
+ | _ -> false
+
+ let IsWarnon (diagnosticOptions: FSharpDiagnosticOptions) warningNumber (mo: range option) =
+ let data = getWarnScopeData diagnosticOptions
+
+ match mo, data.ScopedNowarnFeatureIsSupported with
+ | Some m, true ->
+ let mOrig = originalRange data.LineMaps m
+ let scopes = getScopes mOrig.FileIndex warningNumber data.WarnScopes
+ List.exists (isEnclosingWarnonScope mOrig) scopes
+ | _ -> false
+
+ let IsNowarn (diagnosticOptions: FSharpDiagnosticOptions) warningNumber (mo: range option) =
+ let data = getWarnScopeData diagnosticOptions
+
+ if List.contains warningNumber data.ScriptNowarns then // this happens only for legacy language versions
+ true
+ else
+ match mo with
+ | Some m ->
+ let mOrig = originalRange data.LineMaps m
+ let scopes = getScopes mOrig.FileIndex warningNumber data.WarnScopes
+ List.exists (isEnclosingNowarnScope mOrig) scopes
+ | None -> false
diff --git a/src/Compiler/SyntaxTree/WarnScopes.fsi b/src/Compiler/SyntaxTree/WarnScopes.fsi
new file mode 100644
index 00000000000..1cdecc76149
--- /dev/null
+++ b/src/Compiler/SyntaxTree/WarnScopes.fsi
@@ -0,0 +1,33 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace FSharp.Compiler
+
+open FSharp.Compiler.Diagnostics
+open FSharp.Compiler.SyntaxTrivia
+open FSharp.Compiler.Text
+open FSharp.Compiler.UnicodeLexing
+
+module internal WarnScopes =
+
+ /// To be called during lexing to register the line directives for warn scope processing.
+ val internal RegisterLineDirective: lexbuf: Lexbuf * fileIndex: int * line: int -> unit
+
+ /// To be called during lexing to save #nowarn / #warnon directives.
+ val ParseAndRegisterWarnDirective: lexbuf: Lexbuf -> unit
+
+ /// To be called after lexing a file to create warn scopes from the stored line and
+ /// warn directives and to add them to the warn scopes from other files in the diagnostics options.
+ /// Note that isScript and subModuleRanges are needed only to avoid breaking changes for previous language versions.
+ val MergeInto: FSharpDiagnosticOptions -> isScript: bool -> subModuleRanges: range list -> Lexbuf -> unit
+
+ /// Get the collected ranges of the warn directives
+ val getDirectiveTrivia: Lexbuf -> WarnDirectiveTrivia list
+
+ /// Get the ranges of comments after warn directives
+ val getCommentTrivia: Lexbuf -> CommentTrivia list
+
+ /// Check if the range is inside a "warnon" scope for the given warning number.
+ val IsWarnon: FSharpDiagnosticOptions -> warningNumber: int -> mo: range option -> bool
+
+ /// Check if the range is inside a "nowarn" scope for the given warning number.
+ val IsNowarn: FSharpDiagnosticOptions -> warningNumber: int -> mo: range option -> bool
diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs
index 817730ec6ea..47815bed680 100644
--- a/src/Compiler/TypedTree/TypedTree.fs
+++ b/src/Compiler/TypedTree/TypedTree.fs
@@ -5609,7 +5609,6 @@ type NamedDebugPointKey =
type CheckedImplFile =
| CheckedImplFile of
qualifiedNameOfFile: QualifiedNameOfFile *
- pragmas: ScopedPragma list *
signature: ModuleOrNamespaceType *
contents: ModuleOrNamespaceContents *
hasExplicitEntryPoint: bool *
@@ -5623,8 +5622,6 @@ type CheckedImplFile =
member x.QualifiedNameOfFile = let (CheckedImplFile (qualifiedNameOfFile=res)) = x in res
- member x.Pragmas = let (CheckedImplFile (pragmas=res)) = x in res
-
member x.HasExplicitEntryPoint = let (CheckedImplFile (hasExplicitEntryPoint=res)) = x in res
member x.IsScript = let (CheckedImplFile (isScript=res)) = x in res
diff --git a/src/Compiler/TypedTree/TypedTree.fsi b/src/Compiler/TypedTree/TypedTree.fsi
index 28ef5776e5a..d9216efbe5e 100644
--- a/src/Compiler/TypedTree/TypedTree.fsi
+++ b/src/Compiler/TypedTree/TypedTree.fsi
@@ -4059,7 +4059,6 @@ type NamedDebugPointKey =
type CheckedImplFile =
| CheckedImplFile of
qualifiedNameOfFile: Syntax.QualifiedNameOfFile *
- pragmas: Syntax.ScopedPragma list *
signature: ModuleOrNamespaceType *
contents: ModuleOrNamespaceContents *
hasExplicitEntryPoint: bool *
@@ -4078,8 +4077,6 @@ type CheckedImplFile =
member IsScript: bool
- member Pragmas: Syntax.ScopedPragma list
-
member QualifiedNameOfFile: Syntax.QualifiedNameOfFile
member Signature: ModuleOrNamespaceType
diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs
index 4b41db72349..a1258657e78 100644
--- a/src/Compiler/TypedTree/TypedTreeOps.fs
+++ b/src/Compiler/TypedTree/TypedTreeOps.fs
@@ -6495,10 +6495,10 @@ and remapAndRenameModBind ctxt compgen tmenv x =
ModuleOrNamespaceBinding.Module(mspec, def)
and remapImplFile ctxt compgen tmenv implFile =
- let (CheckedImplFile (fragName, pragmas, signature, contents, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)) = implFile
+ let (CheckedImplFile (fragName, signature, contents, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)) = implFile
let contentsR = copyAndRemapModDef ctxt compgen tmenv contents
let signatureR, tmenv = copyAndRemapAndBindModTy ctxt compgen tmenv signature
- let implFileR = CheckedImplFile (fragName, pragmas, signatureR, contentsR, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)
+ let implFileR = CheckedImplFile (fragName, signatureR, contentsR, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)
implFileR, tmenv
// Entry points
@@ -9868,9 +9868,9 @@ and rewriteModuleOrNamespaceBindings env mbinds =
List.map (rewriteModuleOrNamespaceBinding env) mbinds
and RewriteImplFile env implFile =
- let (CheckedImplFile (fragName, pragmas, signature, contents, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)) = implFile
+ let (CheckedImplFile (fragName, signature, contents, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)) = implFile
let contentsR = rewriteModuleOrNamespaceContents env contents
- let implFileR = CheckedImplFile (fragName, pragmas, signature, contentsR, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)
+ let implFileR = CheckedImplFile (fragName, signature, contentsR, hasExplicitEntryPoint, isScript, anonRecdTypes, namedDebugPointsForInlinedCode)
implFileR
//--------------------------------------------------------------------------
diff --git a/src/Compiler/Utilities/Caches.fs b/src/Compiler/Utilities/Caches.fs
new file mode 100644
index 00000000000..a3cebd93161
--- /dev/null
+++ b/src/Compiler/Utilities/Caches.fs
@@ -0,0 +1,304 @@
+// LinkedList uses nulls, so we need to disable the nullability warnings for this file.
+namespace FSharp.Compiler.Caches
+
+open System
+open System.Collections.Generic
+open System.Collections.Concurrent
+open System.Threading
+open System.Diagnostics
+open System.Diagnostics.Metrics
+
+[]
+type CacheOptions =
+ {
+ /// Total capacity, determines the size of the underlying store.
+ TotalCapacity: int
+
+ /// Safety margin size as a percentage of TotalCapacity.
+ HeadroomPercentage: int
+ }
+
+ static member Default =
+ {
+ TotalCapacity = 128
+ HeadroomPercentage = 50
+ }
+
+// It is important that this is not a struct, because LinkedListNode holds a reference to it,
+// and it holds the reference to that Node, in a circular way.
+[]
+[]
+type CachedEntity<'Key, 'Value> =
+ val mutable private key: 'Key
+ val mutable private value: 'Value
+
+ []
+ val mutable private node: LinkedListNode>
+
+ private new(key, value) = { key = key; value = value }
+
+ member this.Node = this.node
+ member this.Key = this.key
+ member this.Value = this.value
+
+ static member Create(key: 'Key, value: 'Value) =
+ let entity = CachedEntity(key, value)
+ // The contract is that each CachedEntity produced by the EntityPool always has Node referencing itself.
+ entity.node <- LinkedListNode(entity)
+ entity
+
+ member this.ReUse(key, value) =
+ this.key <- key
+ this.value <- value
+ this
+
+ override this.ToString() = $"{this.Key}"
+
+// Currently the Cache itself exposes Metrics.Counters that count raw cache events: hits, misses, evictions etc.
+// This class observes those counters and keeps a snapshot of readings. For now this is used only to print cache stats in debug mode.
+// TODO: We could add some System.Diagnostics.Metrics.Gauge instruments to this class, to get computed stats also exposed as metrics.
+type CacheMetrics(cacheId) =
+ static let meter = new Meter("FSharp.Compiler.Cache")
+
+ static let observedCaches = ConcurrentDictionary()
+
+ let readings = ConcurrentDictionary()
+
+ let listener = new MeterListener()
+
+ do
+ listener.InstrumentPublished <-
+ fun i l ->
+ if i.Meter = meter && i.Description = cacheId then
+ l.EnableMeasurementEvents(i)
+
+ listener.SetMeasurementEventCallback(fun k v _ _ -> Interlocked.Add(readings.GetOrAdd(k.Name, ref 0L), v) |> ignore)
+ listener.Start()
+
+ member this.Dispose() = listener.Dispose()
+
+ member val CacheId = cacheId
+
+ static member val Meter = meter
+
+ member val RecentStats = "-" with get, set
+
+ member this.TryUpdateStats(clearCounts) =
+ let ratio =
+ try
+ float readings["hits"].Value
+ / float (readings["hits"].Value + readings["misses"].Value)
+ * 100.0
+ with _ ->
+ Double.NaN
+
+ let stats =
+ [
+ for name in readings.Keys do
+ let v = readings[name].Value
+
+ if v > 0 then
+ $"{name}: {v}"
+ ]
+ |> String.concat ", "
+ |> sprintf "%s | hit ratio: %s %s" this.CacheId (if Double.IsNaN(ratio) then "-" else $"%.1f{ratio}%%")
+
+ if clearCounts then
+ for r in readings.Values do
+ Interlocked.Exchange(r, 0L) |> ignore
+
+ if stats <> this.RecentStats then
+ this.RecentStats <- stats
+ true
+ else
+ false
+
+ // TODO: Should return a Map, not a string
+ static member GetStats(cacheId) =
+ observedCaches[cacheId].TryUpdateStats(false) |> ignore
+ observedCaches[cacheId].RecentStats
+
+ static member GetStatsUpdateForAllCaches(clearCounts) =
+ [
+ for i in observedCaches.Values do
+ if i.TryUpdateStats(clearCounts) then
+ i.RecentStats
+ ]
+ |> String.concat "\n"
+
+ static member AddInstrumentation(cacheId) =
+ if observedCaches.ContainsKey cacheId then
+ invalidArg "cacheId" $"cache with name {cacheId} already exists"
+
+ observedCaches[cacheId] <- new CacheMetrics(cacheId)
+
+ static member RemoveInstrumentation(cacheId) =
+ observedCaches[cacheId].Dispose()
+ observedCaches.TryRemove(cacheId) |> ignore
+
+// Creates and after reclaiming holds entities for reuse.
+// More than totalCapacity can be created, but it will hold for reuse at most totalCapacity.
+type EntityPool<'Key, 'Value>(totalCapacity, cacheId) =
+ let pool = ConcurrentBag>()
+
+ let created = CacheMetrics.Meter.CreateCounter("created", "count", cacheId)
+
+ member _.Acquire(key, value) =
+ match pool.TryTake() with
+ | true, entity -> entity.ReUse(key, value)
+ | _ ->
+ created.Add 1L
+ CachedEntity.Create(key, value)
+
+ member _.Reclaim(entity: CachedEntity<'Key, 'Value>) =
+ if pool.Count < totalCapacity then
+ pool.Add(entity)
+
+module Cache =
+ // During testing a lot of compilations are started in app domains and subprocesses.
+ // This is a reliable way to pass the override to all of them.
+ []
+ let private overrideVariable = "FSHARP_CACHE_OVERRIDE"
+
+ /// Use for testing purposes to reduce memory consumption in testhost and its subprocesses.
+ let OverrideCapacityForTesting () =
+ Environment.SetEnvironmentVariable(overrideVariable, "true", EnvironmentVariableTarget.Process)
+
+ let applyOverride (capacity: int) =
+ match Environment.GetEnvironmentVariable(overrideVariable) with
+ | NonNull _ when capacity > 4096 -> 4096
+ | _ -> capacity
+
+[]
+type EvictionQueueMessage<'Key, 'Value> =
+ | Add of CachedEntity<'Key, 'Value>
+ | Update of CachedEntity<'Key, 'Value>
+
+[]
+[]
+type Cache<'Key, 'Value when 'Key: not null and 'Key: equality> internal (totalCapacity, headroom, ?name, ?observeMetrics) =
+
+ let instanceId = defaultArg name (Guid.NewGuid().ToString())
+
+ let observeMetrics = defaultArg observeMetrics false
+
+ do
+ if observeMetrics then
+ CacheMetrics.AddInstrumentation instanceId
+
+ let meter = CacheMetrics.Meter
+ let hits = meter.CreateCounter("hits", "count", instanceId)
+ let misses = meter.CreateCounter("misses", "count", instanceId)
+ let evictions = meter.CreateCounter("evictions", "count", instanceId)
+
+ let evictionFails =
+ meter.CreateCounter("eviction-fails", "count", instanceId)
+
+ let pool = EntityPool<'Key, 'Value>(totalCapacity, instanceId)
+
+ let store =
+ ConcurrentDictionary<'Key, CachedEntity<'Key, 'Value>>(Environment.ProcessorCount, totalCapacity)
+
+ let evictionQueue = LinkedList>()
+
+ // Non-evictable capacity.
+ let capacity = totalCapacity - headroom
+
+ let evicted = Event<_>()
+
+ let cts = new CancellationTokenSource()
+
+ let evictionProcessor =
+ MailboxProcessor.Start(
+ (fun mb ->
+ let rec processNext () =
+ async {
+ match! mb.Receive() with
+ | EvictionQueueMessage.Add entity ->
+ evictionQueue.AddLast(entity.Node)
+
+ // Evict one immediately if necessary.
+ if evictionQueue.Count > capacity then
+ let first = nonNull evictionQueue.First
+
+ match store.TryRemove(first.Value.Key) with
+ | true, removed ->
+ evictionQueue.Remove(first)
+ pool.Reclaim(removed)
+ evictions.Add 1L
+ evicted.Trigger()
+ | _ -> evictionFails.Add 1L
+
+ // Store updates are not synchronized. It is possible the entity is no longer in the queue.
+ | EvictionQueueMessage.Update entity when isNull entity.Node.List -> ()
+
+ | EvictionQueueMessage.Update entity ->
+ // Just move this node to the end of the list.
+ evictionQueue.Remove(entity.Node)
+ evictionQueue.AddLast(entity.Node)
+
+ return! processNext ()
+ }
+
+ processNext ()),
+ cts.Token
+ )
+
+ member val Evicted = evicted.Publish
+
+ member val Name = instanceId
+
+ member _.TryGetValue(key: 'Key, value: outref<'Value>) =
+ match store.TryGetValue(key) with
+ | true, entity ->
+ hits.Add 1L
+ evictionProcessor.Post(EvictionQueueMessage.Update entity)
+ value <- entity.Value
+ true
+ | _ ->
+ misses.Add 1L
+ value <- Unchecked.defaultof<'Value>
+ false
+
+ member _.TryAdd(key: 'Key, value: 'Value) =
+ let entity = pool.Acquire(key, value)
+
+ let added = store.TryAdd(key, entity)
+
+ if added then
+ evictionProcessor.Post(EvictionQueueMessage.Add entity)
+ else
+ pool.Reclaim(entity)
+
+ added
+
+ interface IDisposable with
+ member this.Dispose() =
+ cts.Cancel()
+ cts.Dispose()
+ evictionProcessor.Dispose()
+ store.Clear()
+
+ if observeMetrics then
+ CacheMetrics.RemoveInstrumentation instanceId
+
+ member this.Dispose() = (this :> IDisposable).Dispose()
+
+ member this.GetStats() = CacheMetrics.GetStats(this.Name)
+
+ static member Create<'Key, 'Value>(options: CacheOptions, ?name, ?observeMetrics) =
+ if options.TotalCapacity < 0 then
+ invalidArg "Capacity" "Capacity must be positive"
+
+ if options.HeadroomPercentage < 0 then
+ invalidArg "HeadroomPercentage" "HeadroomPercentage must be positive"
+
+ let totalCapacity = Cache.applyOverride options.TotalCapacity
+ // Determine evictable headroom as the percentage of total capcity, since we want to not resize the dictionary.
+ let headroom =
+ int (float options.TotalCapacity * float options.HeadroomPercentage / 100.0)
+
+ let cache =
+ new Cache<_, _>(totalCapacity, headroom, ?name = name, ?observeMetrics = observeMetrics)
+
+ cache
diff --git a/src/Compiler/Utilities/Caches.fsi b/src/Compiler/Utilities/Caches.fsi
new file mode 100644
index 00000000000..565342bf7f5
--- /dev/null
+++ b/src/Compiler/Utilities/Caches.fsi
@@ -0,0 +1,44 @@
+namespace FSharp.Compiler.Caches
+
+open System
+open System.Diagnostics.Metrics
+open System.Threading
+
+[]
+type internal CacheOptions =
+ {
+ /// Total capacity, determines the size of the underlying store.
+ TotalCapacity: int
+
+ /// Safety margin size as a percentage of TotalCapacity.
+ HeadroomPercentage: int
+ }
+
+ static member Default: CacheOptions
+
+module internal Cache =
+ val OverrideCapacityForTesting: unit -> unit
+
+[]
+type internal Cache<'Key, 'Value when 'Key: not null and 'Key: equality> =
+ new: totalCapacity: int * headroom: int * ?name: string * ?observeMetrics: bool -> Cache<'Key, 'Value>
+
+ member TryGetValue: key: 'Key * value: outref<'Value> -> bool
+ member TryAdd: key: 'Key * value: 'Value -> bool
+ /// Cancels the background eviction task.
+ member Dispose: unit -> unit
+
+ interface IDisposable
+
+ /// For testing only
+ member Evicted: IEvent
+
+ static member Create<'Key, 'Value> :
+ options: CacheOptions * ?name: string * ?observeMetrics: bool -> Cache<'Key, 'Value>
+
+[]
+type internal CacheMetrics =
+ static member Meter: Meter
+ static member GetStats: cacheId: string -> string
+ /// Retrieves current hit ratio, hits, misses, evictions etc. formatted for printing or logging.
+ static member GetStatsUpdateForAllCaches: clearCounts: bool -> string
diff --git a/src/Compiler/Utilities/Cancellable.fs b/src/Compiler/Utilities/Cancellable.fs
index 20e220b7e9f..bae9c6f8299 100644
--- a/src/Compiler/Utilities/Cancellable.fs
+++ b/src/Compiler/Utilities/Cancellable.fs
@@ -73,7 +73,11 @@ module Cancellable =
if ct.IsCancellationRequested then
ValueOrCancelled.Cancelled(OperationCanceledException ct)
else
- oper ct
+ try
+ oper ct
+ with
+ | :? OperationCanceledException as e when ct.IsCancellationRequested -> ValueOrCancelled.Cancelled e
+ | :? OperationCanceledException as e -> InvalidOperationException("Wrong cancellation token", e) |> raise
let fold f acc seq =
Cancellable(fun ct ->
@@ -101,14 +105,10 @@ module Cancellable =
let! ct = Async.CancellationToken
return!
- Async.FromContinuations(fun (cont, econt, ccont) ->
- try
- match run ct c with
- | ValueOrCancelled.Value v -> cont v
- | ValueOrCancelled.Cancelled ce -> ccont ce
- with
- | :? OperationCanceledException as ce when ct.IsCancellationRequested -> ccont ce
- | :? OperationCanceledException as e -> InvalidOperationException("Wrong cancellation token", e) |> econt)
+ Async.FromContinuations(fun (cont, _econt, ccont) ->
+ match run ct c with
+ | ValueOrCancelled.Value v -> cont v
+ | ValueOrCancelled.Cancelled ce -> ccont ce)
}
let token () = Cancellable(ValueOrCancelled.Value)
diff --git a/src/Compiler/Utilities/TypeHashing.fs b/src/Compiler/Utilities/TypeHashing.fs
index bcdface38be..7907c2148dc 100644
--- a/src/Compiler/Utilities/TypeHashing.fs
+++ b/src/Compiler/Utilities/TypeHashing.fs
@@ -126,22 +126,6 @@ module HashAccessibility =
module rec HashTypes =
open Microsoft.FSharp.Core.LanguagePrimitives
- let stampEquals g ty1 ty2 =
- match (stripTyEqns g ty1), (stripTyEqns g ty2) with
- | TType_app(tcref1, _, _), TType_app(tcref2, _, _) -> tcref1.Stamp.Equals(tcref2.Stamp)
- | TType_var(r1, _), TType_var(r2, _) -> r1.Stamp.Equals(r2.Stamp)
- | _ -> false
-
- /// Get has for Stamp for TType_app tyconref and TType_var typar
- let hashStamp g ty =
- let v: Stamp =
- match (stripTyEqns g ty) with
- | TType_app(tcref, _, _) -> tcref.Stamp
- | TType_var(r, _) -> r.Stamp
- | _ -> GenericZero
-
- hash v
-
/// Hash a reference to a type
let hashTyconRef tcref = hashTyconRefImpl tcref
@@ -344,3 +328,69 @@ module HashTastMemberOrVals =
hashNonMemberVal (g, obs) (tps, vref.Deref, tau, cxs)
| Some _ -> hashMember (g, obs) emptyTyparInst vref.Deref
+
+/// Practical TType comparer strictly for the use with cache keys.
+module HashStamps =
+ let rec typeInstStampsEqual (tys1: TypeInst) (tys2: TypeInst) =
+ tys1.Length = tys2.Length && (tys1, tys2) ||> Seq.forall2 stampEquals
+
+ and inline typarStampEquals (t1: Typar) (t2: Typar) = t1.Stamp = t2.Stamp
+
+ and typarsStampsEqual (tps1: Typars) (tps2: Typars) =
+ tps1.Length = tps2.Length && (tps1, tps2) ||> Seq.forall2 typarStampEquals
+
+ and measureStampEquals (m1: Measure) (m2: Measure) =
+ match m1, m2 with
+ | Measure.Var(mv1), Measure.Var(mv2) -> mv1.Stamp = mv2.Stamp
+ | Measure.Const(t1, _), Measure.Const(t2, _) -> t1.Stamp = t2.Stamp
+ | Measure.Prod(m1, m2, _), Measure.Prod(m3, m4, _) -> measureStampEquals m1 m3 && measureStampEquals m2 m4
+ | Measure.Inv m1, Measure.Inv m2 -> measureStampEquals m1 m2
+ | Measure.One _, Measure.One _ -> true
+ | Measure.RationalPower(m1, r1), Measure.RationalPower(m2, r2) -> r1 = r2 && measureStampEquals m1 m2
+ | _ -> false
+
+ and nullnessEquals (n1: Nullness) (n2: Nullness) =
+ match n1, n2 with
+ | Nullness.Known k1, Nullness.Known k2 -> k1 = k2
+ | Nullness.Variable _, Nullness.Variable _ -> true
+ | _ -> false
+
+ and stampEquals ty1 ty2 =
+ match ty1, ty2 with
+ | TType_ucase(u, tys1), TType_ucase(v, tys2) -> u.CaseName = v.CaseName && typeInstStampsEqual tys1 tys2
+ | TType_app(tcref1, tinst1, n1), TType_app(tcref2, tinst2, n2) ->
+ tcref1.Stamp = tcref2.Stamp
+ && nullnessEquals n1 n2
+ && typeInstStampsEqual tinst1 tinst2
+ | TType_anon(info1, tys1), TType_anon(info2, tys2) -> info1.Stamp = info2.Stamp && typeInstStampsEqual tys1 tys2
+ | TType_tuple(c1, tys1), TType_tuple(c2, tys2) -> c1 = c2 && typeInstStampsEqual tys1 tys2
+ | TType_forall(tps1, tau1), TType_forall(tps2, tau2) -> stampEquals tau1 tau2 && typarsStampsEqual tps1 tps2
+ | TType_var(r1, n1), TType_var(r2, n2) -> r1.Stamp = r2.Stamp && nullnessEquals n1 n2
+ | TType_measure m1, TType_measure m2 -> measureStampEquals m1 m2
+ | _ -> false
+
+ let inline hashStamp (x: Stamp) : Hash = uint x * 2654435761u |> int
+
+ // The idea is to keep the illusion of immutability of TType.
+ // This hash must be stable during compilation, otherwise we won't be able to find keys or evict from the cache.
+ let rec hashTType ty : Hash =
+ match ty with
+ | TType_ucase(u, tinst) -> tinst |> hashListOrderMatters (hashTType) |> pipeToHash (hash u.CaseName)
+ | TType_app(tcref, tinst, Nullness.Known n) ->
+ tinst
+ |> hashListOrderMatters (hashTType)
+ |> pipeToHash (hashStamp tcref.Stamp)
+ |> pipeToHash (hash n)
+ | TType_app(tcref, tinst, Nullness.Variable _) -> tinst |> hashListOrderMatters (hashTType) |> pipeToHash (hashStamp tcref.Stamp)
+ | TType_anon(info, tys) -> tys |> hashListOrderMatters (hashTType) |> pipeToHash (hashStamp info.Stamp)
+ | TType_tuple(c, tys) -> tys |> hashListOrderMatters (hashTType) |> pipeToHash (hash c)
+ | TType_forall(tps, tau) ->
+ tps
+ |> Seq.map _.Stamp
+ |> hashListOrderMatters (hashStamp)
+ |> pipeToHash (hashTType tau)
+ | TType_fun(d, r, Nullness.Known n) -> hashTType d |> pipeToHash (hashTType r) |> pipeToHash (hash n)
+ | TType_fun(d, r, Nullness.Variable _) -> hashTType d |> pipeToHash (hashTType r)
+ | TType_var(r, Nullness.Known n) -> hashStamp r.Stamp |> pipeToHash (hash n)
+ | TType_var(r, Nullness.Variable _) -> hashStamp r.Stamp
+ | TType_measure _ -> 0
diff --git a/src/Compiler/Utilities/lib.fs b/src/Compiler/Utilities/lib.fs
index 609245f636e..8acde600ec4 100755
--- a/src/Compiler/Utilities/lib.fs
+++ b/src/Compiler/Utilities/lib.fs
@@ -59,12 +59,11 @@ module Int64 =
module Pair =
let order (compare1: IComparer<'T1>, compare2: IComparer<'T2>) =
- { new IComparer<'T1 * 'T2> with
+ { new IComparer with
member _.Compare((a1, a2), (aa1, aa2)) =
let res1 = compare1.Compare (a1, aa1)
if res1 <> 0 then res1 else compare2.Compare (a2, aa2) }
-
type NameSet = Zset
module NameSet =
diff --git a/src/Compiler/Utilities/lib.fsi b/src/Compiler/Utilities/lib.fsi
index 1dfd610d55a..5d82031642f 100644
--- a/src/Compiler/Utilities/lib.fsi
+++ b/src/Compiler/Utilities/lib.fsi
@@ -52,7 +52,7 @@ module Int64 =
val order: IComparer
module Pair =
- val order: compare1: IComparer<'T1> * compare2: IComparer<'T2> -> IComparer<'T1 * 'T2>
+ val order: compare1: IComparer<'T1> * compare2: IComparer<'T2> -> IComparer
type NameSet = Zset
diff --git a/src/Compiler/Utilities/range.fs b/src/Compiler/Utilities/range.fs
index 5e13752df0b..0857d7c4d7c 100755
--- a/src/Compiler/Utilities/range.fs
+++ b/src/Compiler/Utilities/range.fs
@@ -449,7 +449,7 @@ module Range =
let posOrder =
let pairOrder = Pair.order (Int32.order, Int32.order)
- let lineAndColumn = fun (p: pos) -> p.Line, p.Column
+ let lineAndColumn = fun (p: pos) -> struct (p.Line, p.Column)
{ new IComparer with
member _.Compare(x, xx) =
@@ -458,7 +458,7 @@ module Range =
let rangeOrder =
let tripleOrder = Pair.order (String.order, Pair.order (posOrder, posOrder))
- let fileLineColumn = fun (r: range) -> r.FileName, (r.Start, r.End)
+ let fileLineColumn = fun (r: range) -> struct (r.FileName, struct (r.Start, r.End))
{ new IComparer with
member _.Compare(x, xx) =
diff --git a/src/Compiler/lex.fsl b/src/Compiler/lex.fsl
index 34bfe4bfe17..9abb9408c9e 100644
--- a/src/Compiler/lex.fsl
+++ b/src/Compiler/lex.fsl
@@ -817,7 +817,9 @@ rule token (args: LexArgs) (skip: bool) = parse
// Construct the new position
if args.applyLineDirectives then
- lexbuf.EndPos <- pos.ApplyLineDirective((match file with Some f -> FileIndex.fileIndexOfFile f | None -> pos.FileIndex), line)
+ let fileIndex = match file with Some f -> FileIndex.fileIndexOfFile f | None -> pos.FileIndex
+ WarnScopes.RegisterLineDirective(lexbuf, fileIndex, line)
+ lexbuf.EndPos <- pos.ApplyLineDirective(fileIndex, line)
else
// add a newline when we don't apply a directive since we consumed a newline getting here
incrLine lexbuf
@@ -903,6 +905,8 @@ rule token (args: LexArgs) (skip: bool) = parse
| ">" { GREATER false }
+ | ">|}" { GREATER_BAR_RBRACE }
+
| "[<" { LBRACK_LESS }
| "]" { RBRACK }
@@ -1080,6 +1084,13 @@ rule token (args: LexArgs) (skip: bool) = parse
lexbuf.StartPos <- lexbuf.StartPos.ShiftColumnBy(n)
HASH_IDENT(lexemeTrimLeft lexbuf (n+1)) }
+ | anywhite* ("#nowarn" | "#warnon") anystring
+ { let m = lexbuf.LexemeRange
+ shouldStartLine args lexbuf m (FSComp.SR.lexWarnDirectiveMustBeFirst())
+ WarnScopes.ParseAndRegisterWarnDirective lexbuf
+ let tok = WARN_DIRECTIVE(m, lexeme lexbuf, LexCont.EndLine(args.ifdefStack, args.stringNest, LexerEndlineContinuation.Token))
+ if skip then endline LexerEndlineContinuation.Token args skip lexbuf else tok }
+
| surrogateChar surrogateChar
| _
diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy
index 7cac0ad0dc0..285a8a0c47e 100644
--- a/src/Compiler/pars.fsy
+++ b/src/Compiler/pars.fsy
@@ -84,7 +84,7 @@ let parse_error_rich = Some(fun (ctxt: ParseErrorContext<_>) ->
%token EXCEPTION FALSE FOR FUN FUNCTION IF IN JOIN_IN FINALLY DO_BANG
%token LAZY OLAZY MATCH MATCH_BANG MUTABLE NEW OF
%token OPEN OR REC THEN TO TRUE TRY TYPE VAL INLINE INTERFACE INSTANCE CONST
-%token WHEN WHILE WHILE_BANG WITH HASH AMP AMP_AMP QUOTE LPAREN RPAREN RPAREN_COMING_SOON RPAREN_IS_HERE STAR COMMA RARROW GREATER_BAR_RBRACK LPAREN_STAR_RPAREN
+%token WHEN WHILE WHILE_BANG WITH HASH AMP AMP_AMP QUOTE LPAREN RPAREN RPAREN_COMING_SOON RPAREN_IS_HERE STAR COMMA RARROW GREATER_BAR_RBRACK GREATER_BAR_RBRACE LPAREN_STAR_RPAREN
%token QMARK QMARK_QMARK DOT COLON COLON_COLON COLON_GREATER COLON_QMARK_GREATER COLON_QMARK COLON_EQUALS SEMICOLON
%token SEMICOLON_SEMICOLON LARROW EQUALS LBRACK LBRACK_BAR LBRACE_BAR LBRACK_LESS
%token BAR_RBRACK BAR_RBRACE UNDERSCORE
@@ -152,7 +152,7 @@ let parse_error_rich = Some(fun (ctxt: ParseErrorContext<_>) ->
/* These are artificial */
%token LEX_FAILURE
%token COMMENT WHITESPACE HASH_LINE HASH_LIGHT INACTIVECODE LINE_COMMENT STRING_TEXT EOF
-%token HASH_IF HASH_ELSE HASH_ENDIF
+%token HASH_IF HASH_ELSE HASH_ENDIF WARN_DIRECTIVE
%start signatureFile implementationFile interaction typedSequentialExprEOF typEOF
%type typedSequentialExprEOF
@@ -474,7 +474,7 @@ interactiveSeparator:
| OBLOCKSEP { }
/*--------------------------------------------------------------------------*/
-/* #directives - used by both F# Interactive directives and #nowarn etc. */
+/* #directives - used by F# Interactive directives */
/* A #directive in a module, namespace or an interaction */
@@ -3755,18 +3755,32 @@ atomicPattern:
{ SynPat.ArrayOrList(true, $2, lhs parseState) }
| UNDERSCORE
- { SynPat.Wild(lhs parseState) }
+ { (* Underscore pattern ('_') is represented as SynPat.Wild
+ This wild pattern is used in all binding forms:
+ - let _ = ...
+ - use _ = ...
+ - let! _ = ...
+ - use! _ = ...
+ This ensures consistent representation of wildcard bindings in the AST *)
+ SynPat.Wild(lhs parseState) }
| QMARK ident
{ SynPat.OptionalVal($2, lhs parseState) }
| atomicPatternLongIdent %prec prec_atompat_pathop
- { let vis, lidwd = $1
+ { (* This rule handles identifiers in patterns like 'use! __' *)
+ (* For simple identifiers (like '__'), it creates a SynPat.Named AST node *)
+ (* For complex paths (A.B.C) or uppercase ids, it calls mkSynPatMaybeVar *)
+ let vis, lidwd = $1
if not (isNilOrSingleton lidwd.LongIdent) || String.isLeadingIdentifierCharacterUpperCase (List.head lidwd.LongIdent).idText then
mkSynPatMaybeVar lidwd vis (lhs parseState)
else
let synIdent = List.head lidwd.IdentsWithTrivia
- SynPat.Named(synIdent, false, vis, synIdent.Range) }
+ let m =
+ match vis with
+ | Some vis -> unionRanges vis.Range synIdent.Range
+ | _ -> synIdent.Range
+ SynPat.Named(synIdent, false, vis, m) }
| constant
{ SynPat.Const(fst $1, snd $1) }
@@ -4412,13 +4426,22 @@ declExpr:
let mForLoopAll = rhs2 parseState 1 2
exprFromParseError (SynExpr.ForEach(spFor, spIn, SeqExprOnly false, true, $2, arbExpr ("forLoopCollection", mFor), arbExpr ("forLoopBody3", mForLoopBodyArb), mForLoopAll)) }
- | YIELD declExpr
+ | YIELD declExpr COLON typ
{ let trivia: SynExprYieldOrReturnTrivia = { YieldOrReturnKeyword = rhs parseState 1 }
- SynExpr.YieldOrReturn(($1, not $1), $2, (unionRanges (rhs parseState 1) $2.Range), trivia) }
+ let typedExpr = SynExpr.Typed($2, $4, unionRanges $2.Range $4.Range)
+ parseState.LexBuffer.CheckLanguageFeatureAndRecover LanguageFeature.AllowTypedLetOrUseBang typedExpr.Range
+ SynExpr.YieldOrReturn(($1, not $1), typedExpr, (unionRanges (rhs parseState 1) $4.Range), trivia) }
- | YIELD_BANG declExpr
- { let trivia: SynExprYieldOrReturnFromTrivia = { YieldOrReturnFromKeyword = rhs parseState 1 }
- SynExpr.YieldOrReturnFrom(($1, not $1), $2, (unionRanges (rhs parseState 1) $2.Range), trivia) }
+ | YIELD declExpr opt_topReturnTypeWithTypeConstraints
+ { let trivia: SynExprYieldOrReturnTrivia = { YieldOrReturnKeyword = rhs parseState 1 }
+ let expr =
+ match $3 with
+ | None -> $2
+ | Some(_, SynReturnInfo((ty, _), m)) ->
+ let m = unionRanges $2.Range m
+ parseState.LexBuffer.CheckLanguageFeatureAndRecover LanguageFeature.AllowTypedLetOrUseBang m
+ SynExpr.Typed($2, ty, m)
+ SynExpr.YieldOrReturn(($1, not $1), expr, (unionRanges (rhs parseState 1) expr.Range), trivia) }
| YIELD recover
{ let mYieldAll = rhs parseState 1
@@ -4430,8 +4453,31 @@ declExpr:
let trivia: SynExprYieldOrReturnFromTrivia = { YieldOrReturnFromKeyword = rhs parseState 1 }
SynExpr.YieldOrReturnFrom(($1, not $1), arbExpr ("yield!", mYieldAll), mYieldAll, trivia) }
+ | YIELD_BANG declExpr COLON typ
+ { let trivia: SynExprYieldOrReturnFromTrivia = { YieldOrReturnFromKeyword = rhs parseState 1 }
+ let typedExpr = SynExpr.Typed($2, $4, unionRanges $2.Range $4.Range)
+ parseState.LexBuffer.CheckLanguageFeatureAndRecover LanguageFeature.AllowTypedLetOrUseBang typedExpr.Range
+ SynExpr.YieldOrReturnFrom(($1, not $1), typedExpr, (unionRanges (rhs parseState 1) $2.Range), trivia) }
+
+ | YIELD_BANG declExpr opt_topReturnTypeWithTypeConstraints
+ { let trivia: SynExprYieldOrReturnFromTrivia = { YieldOrReturnFromKeyword = rhs parseState 1 }
+ let expr =
+ match $3 with
+ | None -> $2
+ | Some(_, SynReturnInfo((ty, _), m)) ->
+ let m = unionRanges $2.Range m
+ parseState.LexBuffer.CheckLanguageFeatureAndRecover LanguageFeature.AllowTypedLetOrUseBang m
+ SynExpr.Typed($2, ty, m)
+ SynExpr.YieldOrReturnFrom(($1, not $1), expr, (unionRanges (rhs parseState 1) $2.Range), trivia) }
+
| BINDER headBindingPattern EQUALS typedSequentialExprBlock IN opt_OBLOCKSEP moreBinders typedSequentialExprBlock %prec expr_let
- { let spBind = DebugPointAtBinding.Yes(rhs2 parseState 1 5)
+ { (* This rule handles the 'use!' and 'let!' binding expressions in computation expressions *)
+ (* The BINDER token represents keywords like 'use!' or 'let!' *)
+ (* headBindingPattern represents patterns in the binding:
+ - Underscore ('_') patterns are preserved as SynPat.Wild
+ - Named patterns ('__') are represented as SynPat.Named
+ - Identifiers (like 'value') are represented as SynPat.LongIdent *)
+ let spBind = DebugPointAtBinding.Yes(rhs2 parseState 1 5)
let mEquals = rhs parseState 3
let m = unionRanges (rhs parseState 1) $8.Range
let trivia: SynExprLetOrUseBangTrivia = { LetOrUseBangKeyword = rhs parseState 1 ; EqualsRange = Some mEquals }
@@ -4446,6 +4492,39 @@ declExpr:
let trivia: SynExprLetOrUseBangTrivia = { LetOrUseBangKeyword = rhs parseState 1 ; EqualsRange = Some mEquals }
SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, $2, $4, $7, $8, m, trivia) }
+ | BINDER headBindingPattern opt_topReturnTypeWithTypeConstraints EQUALS typedSequentialExprBlock IN opt_OBLOCKSEP moreBinders typedSequentialExprBlock %prec expr_let
+ { // Handle type annotations on patterns in let!/use! bindings
+ // Examples: let! x: int = async { return 1 }
+ // use! _: IDisposable = async { return new MemoryStream() }
+ let spBind = DebugPointAtBinding.Yes(rhs2 parseState 1 7)
+ let pat =
+ match $3 with
+ | None -> $2
+ | Some (_, SynReturnInfo((ty, _), _)) ->
+ SynPat.Typed($2, ty, unionRanges $2.Range ty.Range)
+ parseState.LexBuffer.CheckLanguageFeatureAndRecover LanguageFeature.AllowTypedLetOrUseBang pat.Range
+ let mEquals = rhs parseState 4
+ let m = unionRanges (rhs parseState 1) $9.Range
+ let trivia: SynExprLetOrUseBangTrivia = { LetOrUseBangKeyword = rhs parseState 1 ; EqualsRange = Some mEquals }
+ SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, pat, $5, $8, $9, m, trivia) }
+
+ | OBINDER headBindingPattern opt_topReturnTypeWithTypeConstraints EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP moreBinders typedSequentialExprBlock %prec expr_let
+ { // Handle type annotations on patterns in let!/use! bindings (offside-sensitive version)
+ // This rule maintains consistent handling of binding constructs across different syntactic contexts
+ let report, mIn, _ = $6
+ report (if $1 = "use" then "use!" else "let!") (rhs parseState 1) // report unterminated error
+ let spBind = DebugPointAtBinding.Yes(unionRanges (rhs parseState 1) $5.Range)
+ let pat =
+ match $3 with
+ | None -> $2
+ | Some (_, SynReturnInfo((ty, _), _)) ->
+ SynPat.Typed($2, ty, unionRanges $2.Range ty.Range)
+ parseState.LexBuffer.CheckLanguageFeatureAndRecover LanguageFeature.AllowTypedLetOrUseBang pat.Range
+ let mEquals = rhs parseState 4
+ let m = unionRanges (rhs parseState 1) $9.Range
+ let trivia: SynExprLetOrUseBangTrivia = { LetOrUseBangKeyword = rhs parseState 1 ; EqualsRange = Some mEquals }
+ SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, pat, $5, $8, $9, m, trivia) }
+
| OBINDER headBindingPattern EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP error %prec expr_let
{ // error recovery that allows intellisense when writing incomplete computation expressions
let spBind = DebugPointAtBinding.Yes(unionRanges (rhs parseState 1) $4.Range)
diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf
index 7d64601c303..15516bde9f4 100644
--- a/src/Compiler/xlf/FSComp.txt.cs.xlf
+++ b/src/Compiler/xlf/FSComp.txt.cs.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
atributy napravo od klíčového slova Module
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarationsautomatické generování vlastnosti Message pro deklarace exception
@@ -597,6 +607,11 @@
Sdílení podkladových polí v rozlišeném sjednocení [<Struct>] za předpokladu, že mají stejný název a typ
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraintsomezení vlastního typu
@@ -657,6 +672,11 @@
Interoperabilita mezi neřízeným obecným omezením jazyka C# a F# (emitovat další modreq)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.Znak }} musí být v interpolovaném řetězci uvozený (zdvojeným znakem).
@@ -862,6 +887,21 @@
Interpolovaný řetězec obsahuje nespárované složené závorky.
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \nVšechny prvky seznamu musí být implicitně převoditelné na typ prvního prvku, což je řazená kolekce členů o délce {0} typu\n {1} \nTento element je řazená kolekce členů o délce {2} typu\n {3} \n
diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf
index 67f4270377e..98203615481 100644
--- a/src/Compiler/xlf/FSComp.txt.de.xlf
+++ b/src/Compiler/xlf/FSComp.txt.de.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
Attribute rechts vom "Module"-Schlüsselwort
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarationsAutomatische Generierung der Eigenschaft „Message“ für „exception“-Deklarationen
@@ -597,6 +607,11 @@
Teilen sie zugrunde liegende Felder in einen [<Struct>]-diskriminierten Union, solange sie denselben Namen und Typ aufweisen.
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraintsSelbsttypeinschränkungen
@@ -657,6 +672,11 @@
Interop zwischen nicht verwalteter generischer Einschränkung in C# und F# (zusätzlicher ModReq ausgeben)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.Ein }}-Zeichen muss in einer interpolierten Zeichenfolge (durch Verdoppeln) mit Escapezeichen versehen werden.
@@ -862,6 +887,21 @@
Die interpolierte Zeichenfolge enthält schließende geschweifte Klammern ohne Entsprechung.
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \nAlle Elemente einer Liste müssen implizit in den Typ des ersten Elements konvertiert werden. Hierbei handelt es sich um ein Tupel der Länge {0} vom Typ\n {1} \nDieses Element ist ein Tupel der Länge {2} vom Typ\n {3}. \n
diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf
index 9478e3d2c55..f9a01cc8009 100644
--- a/src/Compiler/xlf/FSComp.txt.es.xlf
+++ b/src/Compiler/xlf/FSComp.txt.es.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
atributos a la derecha de la palabra clave “módulo”
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarationsgeneración automática de la propiedad 'Message' para declaraciones 'exception'
@@ -597,6 +607,11 @@
Compartir campos subyacentes en una unión discriminada [<Struct>] siempre y cuando tengan el mismo nombre y tipo
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraintsrestricciones de tipo propio
@@ -657,6 +672,11 @@
Interoperabilidad entre la restricción genérica no administrada de C# y F# (emitir modreq adicional)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.El carácter "}}" se debe escapar (duplicándose) en las cadenas interpoladas.
@@ -862,6 +887,21 @@
La cadena interpolada contiene llaves de cierre no coincidentes.
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \nTodos los elementos de una lista deben convertirse implícitamente en el tipo del primer elemento, que aquí es una tupla de longitud {0} de tipo\n {1} \nEste elemento es una tupla de longitud {2} de tipo\n {3} \n
diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf
index 57fade5d250..904ce2c3c69 100644
--- a/src/Compiler/xlf/FSComp.txt.fr.xlf
+++ b/src/Compiler/xlf/FSComp.txt.fr.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
attributs à droite du mot clé 'module'
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarationsgénération automatique de la propriété « Message » pour les déclarations « exception »
@@ -597,6 +607,11 @@
Partager les champs sous-jacents dans une union discriminée [<Struct>] tant qu’ils ont le même nom et le même type
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraintscontraintes d’auto-type
@@ -657,6 +672,11 @@
Interopérabilité entre les contraintes génériques non gérées de C# et F# (émettre un modreq supplémentaire)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.Un caractère '}}' doit faire l'objet d'une séquence d'échappement (par doublement) dans une chaîne interpolée.
@@ -862,6 +887,21 @@
La chaîne interpolée contient des accolades fermantes sans correspondance.
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \nTous les éléments d’une liste doivent être implicitement convertibles en type du premier élément, qui est ici un tuple de longueur {0} de type\n {1} \nCet élément est un tuple de longueur {2} de type\n {3} \n
diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf
index 14d670e8455..ea9f636b455 100644
--- a/src/Compiler/xlf/FSComp.txt.it.xlf
+++ b/src/Compiler/xlf/FSComp.txt.it.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
attributi a destra della parola chiave 'module'
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarationsgenerazione automatica della proprietà 'Messaggio' per le dichiarazioni 'eccezione'
@@ -597,6 +607,11 @@
Condividi i campi sottostanti in un'unione discriminata di [<Struct>] purché abbiano lo stesso nome e tipo
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraintsvincoli di tipo automatico
@@ -657,6 +672,11 @@
Interoperabilità tra il vincolo generico non gestito di C# e di F# (crea un modreq aggiuntivo)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.In una stringa interpolata è necessario specificare il carattere di escape di un carattere '}}' raddoppiandolo.
@@ -862,6 +887,21 @@
La stringa interpolata contiene parentesi graffe di chiusura non corrispondenti.
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \nTutti gli elementi di un elenco devono essere convertibili in modo implicito nel tipo del primo elemento, che qui è una tupla di lunghezza {0} di tipo\n {1} \nQuesto elemento è una tupla di lunghezza {2} di tipo\n {3} \n
diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf
index 78acb0fd944..073d2bc0127 100644
--- a/src/Compiler/xlf/FSComp.txt.ja.xlf
+++ b/src/Compiler/xlf/FSComp.txt.ja.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
'module' キーワードの右側の属性
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarations`exception` 宣言の `Message` プロパティの自動生成
@@ -597,6 +607,11 @@
名前と型が同じである限り、[<Struct>] 判別可能な共用体で基になるフィールドを共有する
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraints自己型制約
@@ -657,6 +672,11 @@
C# と F# のアンマネージド ジェネリック制約の間の相互運用 (追加の modreq を出力)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.文字 '}}' は、補間された文字列内で (二重にすることで) エスケープする必要があります。
@@ -862,6 +887,21 @@
補間された文字列には、一致しない閉じかっこが含まれています。
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \nリストのすべての要素は、最初の要素の型に暗黙的に変換できる必要があります。これは、型の長さ {0} のタプルです\n {1} \nこの要素は、型の長さ {2} のタプルです\n {3} \n
diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf
index 604ac431e4a..ac3e6c95d94 100644
--- a/src/Compiler/xlf/FSComp.txt.ko.xlf
+++ b/src/Compiler/xlf/FSComp.txt.ko.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
'module' 키워드 오른쪽에 있는 특성
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarations'exception' 선언에 대한 'Message' 속성 자동 생성
@@ -597,6 +607,11 @@
이름과 형식이 같으면 [<Struct>] 구분된 공용 구조체에서 기본 필드 공유
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraints자체 형식 제약 조건
@@ -657,6 +672,11 @@
C#과 F#의 관리되지 않는 제네릭 제약 조건 간의 Interop(추가 modreq 내보내기)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.'}}' 문자는 보간된 문자열에서 이중으로 사용하여 이스케이프해야 합니다.
@@ -862,6 +887,21 @@
보간된 문자열에 일치하지 않는 닫는 중괄호가 포함되어 있습니다.
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n목록의 모든 요소는 첫 번째 요소의 형식으로 암시적으로 변환할 수 있어야 합니다. 여기서는 형식이 \n {1}이고 길이가 {0}인 튜플입니다. \n이 요소는 형식이 \n {3}이고 길이가 {2}인 튜플입니다. \n
diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf
index fdee3d82f7d..450bc59ad22 100644
--- a/src/Compiler/xlf/FSComp.txt.pl.xlf
+++ b/src/Compiler/xlf/FSComp.txt.pl.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
atrybuty po prawej stronie słowa kluczowego "module"
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarationsAutomatyczne generowanie właściwości „Wiadomość“ dla deklaracji „Wyjątek“
@@ -597,6 +607,11 @@
Udostępnij pola źródłowe w unii rozłącznej [<Struct>], o ile mają taką samą nazwę i ten sam typ
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraintsograniczenia typu własnego
@@ -657,6 +672,11 @@
Międzyoperacyjnie między niezarządzanym ograniczeniem ogólnym języka C# i F# (emituj dodatkowe modreq)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.W przypadku znaku „}}” należy zastosować ucieczkę (przez wpisanie dwóch takich znaków) w ciągu interpolowanym.
@@ -862,6 +887,21 @@
Ciąg interpolowany zawiera niedopasowane zamykające nawiasy klamrowe.
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \nWszystkie elementy tablicy muszą być niejawnie konwertowalne na typ pierwszego elementu, który w tym miejscu jest krotką o długości {0} typu\n {1} \nTen element jest krotką o długości {2} typu\n {3} \n
diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf
index 2f86c57d960..8eb539fa237 100644
--- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf
+++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
atributos à direita da palavra-chave 'módulo'
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarationsgeração automática da propriedade 'Message' para declarações de 'exception'
@@ -597,6 +607,11 @@
Compartilhar campos subjacentes em uma união discriminada [<Struct>], desde que tenham o mesmo nome e tipo
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraintsrestrições de auto-tipo
@@ -657,6 +672,11 @@
Interoperabilidade entre a restrição genérica não gerenciada de C# e F# (emitir modreq adicional)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.Um caractere ''}}' precisa ser de escape (ao duplicar) em uma cadeia de caracteres interpolada.
@@ -862,6 +887,21 @@
A cadeia de caracteres interpolada contém chaves de fechamento sem correspondência.
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \nTodos os elementos de uma lista devem ser implicitamente conversíveis ao tipo do primeiro elemento, que aqui é uma tupla de comprimento {0} do tipo\n {1} \nEste elemento é uma tupla de comprimento {2} do tipo\n {3} \n
diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf
index fefd5255a0b..27d646c8a9c 100644
--- a/src/Compiler/xlf/FSComp.txt.ru.xlf
+++ b/src/Compiler/xlf/FSComp.txt.ru.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
атрибуты справа от ключевого слова "module"
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarationsавтоматическое создание свойства “Message” для объявлений “exception”
@@ -597,6 +607,11 @@
Совместное использование базовых полей в дискриминируемом объединении [<Struct>], если они имеют одинаковое имя и тип.
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraintsограничения самостоятельного типа
@@ -657,6 +672,11 @@
Взаимодействие между универсальным ограничением "unmanaged" C# и F#(создание дополнительного modreq)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.Символ "}}" необходимо экранировать (путем дублирования) в интерполированной строке.
@@ -862,6 +887,21 @@
Интерполированная строка содержит непарные закрывающие фигурные скобки.
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \nВсе элементы списка должны поддерживать неявное преобразование в тип первого элемента, который здесь является кортежем длиной {0} типа\n {1} \nЭтот элемент является кортежем длиной {2} типа\n {3} \n
diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf
index 5325f0ab09f..ee7db390d59 100644
--- a/src/Compiler/xlf/FSComp.txt.tr.xlf
+++ b/src/Compiler/xlf/FSComp.txt.tr.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
'modül' anahtar sözcüğünün sağındaki öznitelikler
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarations'exception' bildirimleri için 'Message' özelliğinin otomatik olarak oluşturulması
@@ -597,6 +607,11 @@
Aynı ada ve türe sahip oldukları sürece temel alınan alanları [<Struct>] ayırt edici birleşim biçiminde paylaşın
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraintskendi kendine tür kısıtlamaları
@@ -657,6 +672,11 @@
C# ile F#' arasında yönetilmeyen genel kısıtlama (ek modreq yayın)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.Bir '}}' karakteri, düz metin arasına kod eklenmiş bir dizede kaçış dizisi ile (yineleme yapılarak) belirtilir.
@@ -862,6 +887,21 @@
İlişkilendirilmiş dize, eşleşmeyen kapatma küme ayraçları içeriyor.
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \nBir listenin tüm öğeleri örtük olarak ilk öğenin türüne dönüştürülebilir olmalıdır. Burada ilk öğe {0} uzunluğunda türü\n {1} \nolan bir demet. Bu öğe ise {2} uzunluğunda türü\n {3} \nolan bir demet.
diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf
index 2e8b957d810..0ca3574bbb9 100644
--- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf
+++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
"module" 关键字右侧的属性
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarations自动生成“异常”声明的“消息”属性
@@ -597,6 +607,11 @@
只要它们具有相同的名称和类型,即可在 [<Struct>] 中共享基础字段
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraints自类型约束
@@ -657,6 +672,11 @@
C# 和 F# 的非托管泛型约束之间的互操作(发出额外的 modreq)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.在内插字符串中,必需对 "}}" 字符进行转义(通过加倍)。
@@ -862,6 +887,21 @@
内插字符串包含不匹配的右大括号。
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n列表的所有元素必须可隐式转换为第一个元素的类型,这是一个长度为 {0} 的类型的元组\n {1} \n此元素是长度为 {2} 类型的元组\n {3} \n
diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf
index f0924b3d30f..42aa912d17c 100644
--- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf
+++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf
@@ -287,6 +287,11 @@
Allow access modifiers to auto properties getters and setters
+
+ Allow let! and use! type annotations without requiring parentheses
+ Allow let! and use! type annotations without requiring parentheses
+
+ Allow object expressions without overridesAllow object expressions without overrides
@@ -307,6 +312,11 @@
'module' 關鍵字右邊的屬性
+
+ Support for better anonymous record parsing
+ Support for better anonymous record parsing
+
+ automatic generation of 'Message' property for 'exception' declarations自動產生 'exception' 宣告的 'Message' 屬性
@@ -597,6 +607,11 @@
只要 [<Struct>] 具有相同名稱和類型,就以強制聯集共用基礎欄位
+
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+ Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules
+
+ self type constraints自我類型限制式
@@ -657,6 +672,11 @@
C# 與 F# 的非受控泛型條件約束之間的 Interop (發出額外的 modreq)
+
+ Allows use! _ = ... in computation expressions
+ Allows use! _ = ... in computation expressions
+
+ Use type conversion cache during compilationUse type conversion cache during compilation
@@ -832,6 +852,11 @@
This is not a valid byte character literal. The value must be less than or equal to '\127'B.\nNote: In a future F# version this warning will be promoted to an error.
+
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+ The file '{0}' was also pointed to in a line directive in '{1}'. Proper warn directive application may not be possible.
+
+ A '}}' character must be escaped (by doubling) in an interpolated string.在插補字串中,必須將 '}}' 字元逸出 (重複一次)。
@@ -862,6 +887,21 @@
差補字串包含不成對的右大括弧。
+
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+ #nowarn/#warnon directives must appear as the first non-whitespace characters on a line
+
+
+
+ Warn directives must have warning number(s) as argument(s)
+ Warn directives must have warning number(s) as argument(s)
+
+
+
+ There is another {0} for this warning already in line {1}.
+ There is another {0} for this warning already in line {1}.
+
+ All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n清單的所有元素必須以隱含方式轉換成第一個元素的類型,這是類型為\n {1} \n的元組長度 {0}此元素是類型為\n {3} \n的元組長度 {2}
diff --git a/src/Compiler/xlf/FSStrings.cs.xlf b/src/Compiler/xlf/FSStrings.cs.xlf
index 698e7180ad6..cfa0c8bddb7 100644
--- a/src/Compiler/xlf/FSStrings.cs.xlf
+++ b/src/Compiler/xlf/FSStrings.cs.xlf
@@ -82,6 +82,11 @@
symbol ..^
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated stringinterpolovaný řetězec
diff --git a/src/Compiler/xlf/FSStrings.de.xlf b/src/Compiler/xlf/FSStrings.de.xlf
index ebfb525eb2a..e81e671661a 100644
--- a/src/Compiler/xlf/FSStrings.de.xlf
+++ b/src/Compiler/xlf/FSStrings.de.xlf
@@ -82,6 +82,11 @@
Symbol "..^"
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated stringInterpolierte Zeichenfolge
diff --git a/src/Compiler/xlf/FSStrings.es.xlf b/src/Compiler/xlf/FSStrings.es.xlf
index 46816a23aba..9e78f3ddd08 100644
--- a/src/Compiler/xlf/FSStrings.es.xlf
+++ b/src/Compiler/xlf/FSStrings.es.xlf
@@ -82,6 +82,11 @@
símbolo "..^"
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated stringcadena interpolada
diff --git a/src/Compiler/xlf/FSStrings.fr.xlf b/src/Compiler/xlf/FSStrings.fr.xlf
index 7e8f9df4ee3..ccedd3ac360 100644
--- a/src/Compiler/xlf/FSStrings.fr.xlf
+++ b/src/Compiler/xlf/FSStrings.fr.xlf
@@ -82,6 +82,11 @@
symbole '..^'
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated stringchaîne interpolée
diff --git a/src/Compiler/xlf/FSStrings.it.xlf b/src/Compiler/xlf/FSStrings.it.xlf
index 004e8d04e13..e5545d56799 100644
--- a/src/Compiler/xlf/FSStrings.it.xlf
+++ b/src/Compiler/xlf/FSStrings.it.xlf
@@ -82,6 +82,11 @@
simbolo '..^'
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated stringstringa interpolata
diff --git a/src/Compiler/xlf/FSStrings.ja.xlf b/src/Compiler/xlf/FSStrings.ja.xlf
index b7e4a21e670..631370c20e9 100644
--- a/src/Compiler/xlf/FSStrings.ja.xlf
+++ b/src/Compiler/xlf/FSStrings.ja.xlf
@@ -82,6 +82,11 @@
シンボル '..^'
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated string補間された文字列
diff --git a/src/Compiler/xlf/FSStrings.ko.xlf b/src/Compiler/xlf/FSStrings.ko.xlf
index edee12a29a2..084e56072c4 100644
--- a/src/Compiler/xlf/FSStrings.ko.xlf
+++ b/src/Compiler/xlf/FSStrings.ko.xlf
@@ -82,6 +82,11 @@
기호 '..^'
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated string보간 문자열
diff --git a/src/Compiler/xlf/FSStrings.pl.xlf b/src/Compiler/xlf/FSStrings.pl.xlf
index b50fb8fc188..f6e7003e75d 100644
--- a/src/Compiler/xlf/FSStrings.pl.xlf
+++ b/src/Compiler/xlf/FSStrings.pl.xlf
@@ -82,6 +82,11 @@
symbol „..^”
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated stringciąg interpolowany
diff --git a/src/Compiler/xlf/FSStrings.pt-BR.xlf b/src/Compiler/xlf/FSStrings.pt-BR.xlf
index f94ce79cd97..72178364b24 100644
--- a/src/Compiler/xlf/FSStrings.pt-BR.xlf
+++ b/src/Compiler/xlf/FSStrings.pt-BR.xlf
@@ -82,6 +82,11 @@
símbolo '..^'
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated stringcadeia de caracteres interpolada
diff --git a/src/Compiler/xlf/FSStrings.ru.xlf b/src/Compiler/xlf/FSStrings.ru.xlf
index 6df88d26d49..6f2c47d0d10 100644
--- a/src/Compiler/xlf/FSStrings.ru.xlf
+++ b/src/Compiler/xlf/FSStrings.ru.xlf
@@ -82,6 +82,11 @@
символ "..^"
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated stringинтерполированная строка
diff --git a/src/Compiler/xlf/FSStrings.tr.xlf b/src/Compiler/xlf/FSStrings.tr.xlf
index 59fc6b69625..0c41ee99672 100644
--- a/src/Compiler/xlf/FSStrings.tr.xlf
+++ b/src/Compiler/xlf/FSStrings.tr.xlf
@@ -82,6 +82,11 @@
'..^' sembolü
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated stringdüz metin arasına kod eklenmiş dize
diff --git a/src/Compiler/xlf/FSStrings.zh-Hans.xlf b/src/Compiler/xlf/FSStrings.zh-Hans.xlf
index f97800458f1..dc22dbeb28b 100644
--- a/src/Compiler/xlf/FSStrings.zh-Hans.xlf
+++ b/src/Compiler/xlf/FSStrings.zh-Hans.xlf
@@ -82,6 +82,11 @@
符号 "..^"
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated string内插字符串
diff --git a/src/Compiler/xlf/FSStrings.zh-Hant.xlf b/src/Compiler/xlf/FSStrings.zh-Hant.xlf
index 2f0181b62d6..bcb553c7de1 100644
--- a/src/Compiler/xlf/FSStrings.zh-Hant.xlf
+++ b/src/Compiler/xlf/FSStrings.zh-Hant.xlf
@@ -82,6 +82,11 @@
符號 '..^'
+
+ symbol '>|}'
+ symbol '>|}'
+
+ interpolated string插補字串
diff --git a/src/FSharp.Core/array.fs b/src/FSharp.Core/array.fs
index ca88e22465d..358836ddf1b 100644
--- a/src/FSharp.Core/array.fs
+++ b/src/FSharp.Core/array.fs
@@ -2020,15 +2020,18 @@ module Array =
let inputLength = source.Length
if inputLength = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
-
- let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
+ if count = 0 then
+ [||]
+ else
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ else
+ let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
- for i = 0 to count - 1 do
- let j = random.Next(0, inputLength)
- result[i] <- source[j]
+ for i = 0 to count - 1 do
+ let j = random.Next(0, inputLength)
+ result[i] <- source[j]
- result
+ result
[]
let randomChoicesBy (randomizer: unit -> float) (count: int) (source: 'T array) : 'T array =
@@ -2040,15 +2043,18 @@ module Array =
let inputLength = source.Length
if inputLength = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
-
- let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
+ if count = 0 then
+ [||]
+ else
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ else
+ let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
- for i = 0 to count - 1 do
- let j = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
- result[i] <- source[j]
+ for i = 0 to count - 1 do
+ let j = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
+ result[i] <- source[j]
- result
+ result
[]
let randomChoices (count: int) (source: 'T array) : 'T array =
@@ -2065,35 +2071,38 @@ module Array =
let inputLength = source.Length
if inputLength = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
-
- if count > inputLength then
- invalidArg "count" (SR.GetString(SR.notEnoughElements))
+ if count = 0 then
+ [||]
+ else
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ else
+ if count > inputLength then
+ invalidArg "count" (SR.GetString(SR.notEnoughElements))
- let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
+ let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
- let setSize =
- Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
+ let setSize =
+ Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
- if inputLength <= setSize then
- let pool = copy source
+ if inputLength <= setSize then
+ let pool = copy source
- for i = 0 to count - 1 do
- let j = random.Next(0, inputLength - i)
- result[i] <- pool[j]
- pool[j] <- pool[inputLength - i - 1]
- else
- let selected = HashSet()
+ for i = 0 to count - 1 do
+ let j = random.Next(0, inputLength - i)
+ result[i] <- pool[j]
+ pool[j] <- pool[inputLength - i - 1]
+ else
+ let selected = HashSet()
- for i = 0 to count - 1 do
- let mutable j = random.Next(0, inputLength)
+ for i = 0 to count - 1 do
+ let mutable j = random.Next(0, inputLength)
- while not (selected.Add j) do
- j <- random.Next(0, inputLength)
+ while not (selected.Add j) do
+ j <- random.Next(0, inputLength)
- result[i] <- source[j]
+ result[i] <- source[j]
- result
+ result
[]
let randomSampleBy (randomizer: unit -> float) (count: int) (source: 'T array) : 'T array =
@@ -2105,39 +2114,42 @@ module Array =
let inputLength = source.Length
if inputLength = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
-
- if count > inputLength then
- invalidArg "count" (SR.GetString(SR.notEnoughElements))
+ if count = 0 then
+ [||]
+ else
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ else
+ if count > inputLength then
+ invalidArg "count" (SR.GetString(SR.notEnoughElements))
- let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
+ let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
- // algorithm taken from https://github.com/python/cpython/blob/69b3e8ea569faabccd74036e3d0e5ec7c0c62a20/Lib/random.py#L363-L456
- let setSize =
- Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
+ // algorithm taken from https://github.com/python/cpython/blob/69b3e8ea569faabccd74036e3d0e5ec7c0c62a20/Lib/random.py#L363-L456
+ let setSize =
+ Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
- if inputLength <= setSize then
- let pool = copy source
+ if inputLength <= setSize then
+ let pool = copy source
- for i = 0 to count - 1 do
- let j =
- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 (inputLength - i)
+ for i = 0 to count - 1 do
+ let j =
+ Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 (inputLength - i)
- result[i] <- pool[j]
- pool[j] <- pool[inputLength - i - 1]
- else
- let selected = HashSet()
+ result[i] <- pool[j]
+ pool[j] <- pool[inputLength - i - 1]
+ else
+ let selected = HashSet()
- for i = 0 to count - 1 do
- let mutable j =
- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
+ for i = 0 to count - 1 do
+ let mutable j =
+ Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
- while not (selected.Add j) do
- j <- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
+ while not (selected.Add j) do
+ j <- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
- result[i] <- source[j]
+ result[i] <- source[j]
- result
+ result
[]
let randomSample (count: int) (source: 'T array) : 'T array =
diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi
index 151081c300c..ba6274e11c6 100644
--- a/src/FSharp.Core/array.fsi
+++ b/src/FSharp.Core/array.fsi
@@ -3282,7 +3282,7 @@ module Array =
/// An array of randomly selected elements from the input array.
///
/// Thrown when the input array is null.
- /// Thrown when the input array is empty.
+ /// Thrown when count is more than 0 and the input array is empty.
/// Thrown when count is less than 0.
///
///
@@ -3306,7 +3306,7 @@ module Array =
///
/// Thrown when the input array is null.
/// Thrown when the random argument is null.
- /// Thrown when the input array is empty.
+ /// Thrown when count is more than 0 and the input array is empty.
/// Thrown when count is less than 0.
///
///
@@ -3329,7 +3329,7 @@ module Array =
/// An array of randomly selected elements from the input array.
///
/// Thrown when the input array is null.
- /// Thrown when the input array is empty.
+ /// Thrown when count is more than 0 and the input array is empty.
/// Thrown when count is less than 0.
/// Thrown when the randomizer function returns a value outside the range [0, 1).
///
@@ -3352,7 +3352,7 @@ module Array =
/// An array of randomly selected elements from the input array.
///
/// Thrown when the input array is null.
- /// Thrown when the input array is empty.
+ /// Thrown when count is more than 0 and the input array is empty.
/// Thrown when count is less than 0.
/// Thrown when count is greater than the length of the input array.
///
@@ -3377,7 +3377,7 @@ module Array =
///
/// Thrown when the input array is null.
/// Thrown when the random argument is null.
- /// Thrown when the input array is empty.
+ /// Thrown when count is more than 0 and the input array is empty..
/// Thrown when count is less than 0.
/// Thrown when count is greater than the length of the input array.
///
@@ -3401,7 +3401,7 @@ module Array =
/// An array of randomly selected elements from the input array.
///
/// Thrown when the input array is null.
- /// Thrown when the input array is empty.
+ /// Thrown when count is more than 0 and the input array is empty.
/// Thrown when count is less than 0.
/// Thrown when count is greater than the length of the input array.
/// Thrown when the randomizer function returns a value outside the range [0, 1).
diff --git a/src/FSharp.Core/list.fs b/src/FSharp.Core/list.fs
index d502107a6da..7fc02845d3a 100644
--- a/src/FSharp.Core/list.fs
+++ b/src/FSharp.Core/list.fs
@@ -1043,13 +1043,16 @@ module List =
let inputLength = source.Length
if inputLength = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
-
- [
- for _ = 0 to count - 1 do
- let j = random.Next(0, inputLength)
- source[j]
- ]
+ if count = 0 then
+ []
+ else
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ else
+ [
+ for _ = 0 to count - 1 do
+ let j = random.Next(0, inputLength)
+ source[j]
+ ]
[]
let randomChoicesBy (randomizer: unit -> float) (count: int) (source: 'T list) : 'T list =
@@ -1059,13 +1062,16 @@ module List =
let inputLength = source.Length
if inputLength = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
-
- [
- for _ = 0 to count - 1 do
- let j = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
- source[j]
- ]
+ if count = 0 then
+ []
+ else
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ else
+ [
+ for _ = 0 to count - 1 do
+ let j = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
+ source[j]
+ ]
[]
let randomChoices (count: int) (source: 'T list) : 'T list =
@@ -1081,37 +1087,40 @@ module List =
let inputLength = source.Length
if inputLength = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
-
- if count > inputLength then
- invalidArg "count" (SR.GetString(SR.notEnoughElements))
-
- // algorithm taken from https://github.com/python/cpython/blob/69b3e8ea569faabccd74036e3d0e5ec7c0c62a20/Lib/random.py#L363-L456
- let setSize =
- Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
-
- if inputLength <= setSize then
- let pool = source |> toArray
-
- [
- for i = 0 to count - 1 do
- let j = random.Next(0, inputLength - i)
- let item = pool[j]
- pool[j] <- pool[inputLength - i - 1]
- item
- ]
+ if count = 0 then
+ []
+ else
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
else
- let selected = HashSet()
+ if count > inputLength then
+ invalidArg "count" (SR.GetString(SR.notEnoughElements))
+
+ // algorithm taken from https://github.com/python/cpython/blob/69b3e8ea569faabccd74036e3d0e5ec7c0c62a20/Lib/random.py#L363-L456
+ let setSize =
+ Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
+
+ if inputLength <= setSize then
+ let pool = source |> toArray
+
+ [
+ for i = 0 to count - 1 do
+ let j = random.Next(0, inputLength - i)
+ let item = pool[j]
+ pool[j] <- pool[inputLength - i - 1]
+ item
+ ]
+ else
+ let selected = HashSet()
- [
- for _ = 0 to count - 1 do
- let mutable j = random.Next(0, inputLength)
+ [
+ for _ = 0 to count - 1 do
+ let mutable j = random.Next(0, inputLength)
- while not (selected.Add j) do
- j <- random.Next(0, inputLength)
+ while not (selected.Add j) do
+ j <- random.Next(0, inputLength)
- source[j]
- ]
+ source[j]
+ ]
[]
let randomSampleBy (randomizer: unit -> float) (count: int) (source: 'T list) : 'T list =
@@ -1121,39 +1130,42 @@ module List =
let inputLength = source.Length
if inputLength = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
-
- if count > inputLength then
- invalidArg "count" (SR.GetString(SR.notEnoughElements))
+ if count = 0 then
+ []
+ else
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ else
+ if count > inputLength then
+ invalidArg "count" (SR.GetString(SR.notEnoughElements))
- let setSize =
- Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
+ let setSize =
+ Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
- if inputLength <= setSize then
- let pool = source |> toArray
+ if inputLength <= setSize then
+ let pool = source |> toArray
- [
- for i = 0 to count - 1 do
- let j =
- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 (inputLength - i)
+ [
+ for i = 0 to count - 1 do
+ let j =
+ Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 (inputLength - i)
- let item = pool[j]
- pool[j] <- pool[inputLength - i - 1]
- item
- ]
- else
- let selected = HashSet()
+ let item = pool[j]
+ pool[j] <- pool[inputLength - i - 1]
+ item
+ ]
+ else
+ let selected = HashSet()
- [
- for _ = 0 to count - 1 do
- let mutable j =
- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
+ [
+ for _ = 0 to count - 1 do
+ let mutable j =
+ Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
- while not (selected.Add j) do
- j <- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
+ while not (selected.Add j) do
+ j <- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
- source[j]
- ]
+ source[j]
+ ]
[]
let randomSample (count: int) (source: 'T list) : 'T list =
diff --git a/src/FSharp.Core/list.fsi b/src/FSharp.Core/list.fsi
index e14fe7eb447..0c69ccc60c7 100644
--- a/src/FSharp.Core/list.fsi
+++ b/src/FSharp.Core/list.fsi
@@ -2820,7 +2820,7 @@ module List =
///
/// A list of randomly selected elements from the input list.
///
- /// Thrown when the input list is empty.
+ /// Thrown when count is more than 0 and the input list is empty.
/// Thrown when count is less than 0.
///
///
@@ -2843,7 +2843,7 @@ module List =
/// A list of randomly selected elements from the input list.
///
/// Thrown when the random argument is null.
- /// Thrown when the input list is empty.
+ /// Thrown when count is more than 0 and the input list is empty.
/// Thrown when count is less than 0.
///
///
@@ -2866,6 +2866,7 @@ module List =
/// A list of randomly selected elements from the input list.
///
/// Thrown when the input list is empty.
+ /// Thrown when count is more than 0 and the input list is empty.
/// Thrown when count is less than 0.
/// Thrown when the randomizer function returns a value outside the range [0, 1).
///
@@ -2887,7 +2888,7 @@ module List =
///
/// A list of randomly selected elements from the input list.
///
- /// Thrown when the input list is empty.
+ /// Thrown when count is more than 0 and the input list is empty.
/// Thrown when count is less than 0.
/// Thrown when count is greater than the length of the input list.
///
@@ -2911,7 +2912,7 @@ module List =
/// A list of randomly selected elements from the input list.
///
/// Thrown when the random argument is null.
- /// Thrown when the input list is empty.
+ /// Thrown when count is more than 0 and the input list is empty.
/// Thrown when count is less than 0.
/// Thrown when count is greater than the length of the input list.
///
@@ -2934,7 +2935,7 @@ module List =
///
/// A list of randomly selected elements from the input list.
///
- /// Thrown when the input list is empty.
+ /// Thrown when count is more than 0 and the input list is empty.
/// Thrown when count is less than 0.
/// Thrown when count is greater than the length of the input list.
/// Thrown when the randomizer function returns a value outside the range [0, 1).
diff --git a/src/FSharp.Core/seq.fs b/src/FSharp.Core/seq.fs
index 20fcdefb159..ce1bfe6d4ab 100644
--- a/src/FSharp.Core/seq.fs
+++ b/src/FSharp.Core/seq.fs
@@ -2002,13 +2002,16 @@ module Seq =
let inputLength = tempArray.Length
if inputLength = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
-
- seq {
- for _ = 0 to count - 1 do
- let j = random.Next(0, inputLength)
- tempArray[j]
- }
+ if count = 0 then
+ empty
+ else
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ else
+ seq {
+ for _ = 0 to count - 1 do
+ let j = random.Next(0, inputLength)
+ tempArray[j]
+ }
[]
let randomChoicesBy (randomizer: unit -> float) (count: int) (source: seq<'T>) : seq<'T> =
@@ -2021,13 +2024,16 @@ module Seq =
let inputLength = tempArray.Length
if inputLength = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
-
- seq {
- for _ = 0 to count - 1 do
- let j = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
- tempArray[j]
- }
+ if count = 0 then
+ empty
+ else
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ else
+ seq {
+ for _ = 0 to count - 1 do
+ let j = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
+ tempArray[j]
+ }
[]
let randomChoices (count: int) (source: seq<'T>) : seq<'T> =
@@ -2045,35 +2051,38 @@ module Seq =
let inputLength = tempArray.Length
if inputLength = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
-
- if count > inputLength then
- invalidArg "count" (SR.GetString(SR.notEnoughElements))
-
- // algorithm taken from https://github.com/python/cpython/blob/69b3e8ea569faabccd74036e3d0e5ec7c0c62a20/Lib/random.py#L363-L456
- let setSize =
- Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
-
- if inputLength <= setSize then
- seq {
- for i = 0 to count - 1 do
- let j = random.Next(0, inputLength - i)
- let item = tempArray[j]
- tempArray[j] <- tempArray[inputLength - i - 1]
- item
- }
+ if count = 0 then
+ empty
+ else
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
else
- let selected = HashSet()
+ if count > inputLength then
+ invalidArg "count" (SR.GetString(SR.notEnoughElements))
+
+ // algorithm taken from https://github.com/python/cpython/blob/69b3e8ea569faabccd74036e3d0e5ec7c0c62a20/Lib/random.py#L363-L456
+ let setSize =
+ Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
+
+ if inputLength <= setSize then
+ seq {
+ for i = 0 to count - 1 do
+ let j = random.Next(0, inputLength - i)
+ let item = tempArray[j]
+ tempArray[j] <- tempArray[inputLength - i - 1]
+ item
+ }
+ else
+ let selected = HashSet()
- seq {
- for _ = 0 to count - 1 do
- let mutable j = random.Next(0, inputLength)
+ seq {
+ for _ = 0 to count - 1 do
+ let mutable j = random.Next(0, inputLength)
- while not (selected.Add j) do
- j <- random.Next(0, inputLength)
+ while not (selected.Add j) do
+ j <- random.Next(0, inputLength)
- tempArray[j]
- }
+ tempArray[j]
+ }
[]
let randomSampleBy (randomizer: unit -> float) (count: int) (source: seq<'T>) : seq<'T> =
@@ -2086,37 +2095,40 @@ module Seq =
let inputLength = tempArray.Length
if inputLength = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
-
- if count > inputLength then
- invalidArg "count" (SR.GetString(SR.notEnoughElements))
+ if count = 0 then
+ empty
+ else
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ else
+ if count > inputLength then
+ invalidArg "count" (SR.GetString(SR.notEnoughElements))
- let setSize =
- Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
+ let setSize =
+ Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
- if inputLength <= setSize then
- seq {
- for i = 0 to count - 1 do
- let j =
- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 (inputLength - i)
+ if inputLength <= setSize then
+ seq {
+ for i = 0 to count - 1 do
+ let j =
+ Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 (inputLength - i)
- let item = tempArray[j]
- tempArray[j] <- tempArray[inputLength - i - 1]
- item
- }
- else
- let selected = HashSet()
+ let item = tempArray[j]
+ tempArray[j] <- tempArray[inputLength - i - 1]
+ item
+ }
+ else
+ let selected = HashSet()
- seq {
- for _ = 0 to count - 1 do
- let mutable j =
- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
+ seq {
+ for _ = 0 to count - 1 do
+ let mutable j =
+ Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
- while not (selected.Add j) do
- j <- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
+ while not (selected.Add j) do
+ j <- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
- tempArray[j]
- }
+ tempArray[j]
+ }
[]
let randomSample (count: int) (source: seq<'T>) : seq<'T> =
diff --git a/src/FSharp.Core/seq.fsi b/src/FSharp.Core/seq.fsi
index 790a486e850..19c83624bef 100644
--- a/src/FSharp.Core/seq.fsi
+++ b/src/FSharp.Core/seq.fsi
@@ -3077,7 +3077,7 @@ module Seq =
/// A sequence of randomly selected elements from the input sequence.
///
/// Thrown when the input sequence is null.
- /// Thrown when the input sequence is empty.
+ /// Thrown when count is more than 0 and the input list is empty.
/// Thrown when count is less than 0.
///
///
@@ -3103,7 +3103,7 @@ module Seq =
///
/// Thrown when the input sequence is null.
/// Thrown when the random argument is null.
- /// Thrown when the input sequence is empty.
+ /// Thrown when count is more than 0 and the input list is empty.
/// Thrown when count is less than 0.
///
///
@@ -3128,7 +3128,7 @@ module Seq =
/// A sequence of randomly selected elements from the input sequence.
///
/// Thrown when the input sequence is null.
- /// Thrown when the input sequence is empty.
+ /// Thrown when count is more than 0 and the input list is empty.
/// Thrown when count is less than 0.
/// Thrown when the randomizer function returns a number outside the range [0.0..1.0).
///
@@ -3153,7 +3153,7 @@ module Seq =
/// A sequence of randomly selected elements from the input sequence.
///
/// Thrown when the input sequence is null.
- /// Thrown when the input sequence is empty.
+ /// Thrown when count is more than 0 and the input list is empty.
/// Thrown when count is less than 0.
/// Thrown when count is greater than the length of the input sequence.
///
@@ -3180,7 +3180,7 @@ module Seq =
///
/// Thrown when the input sequence is null.
/// Thrown when the random argument is null.
- /// Thrown when the input sequence is empty.
+ /// Thrown when count is more than 0 and the input list is empty.
/// Thrown when count is less than 0.
/// Thrown when count is greater than the length of the input sequence.
///
@@ -3206,7 +3206,7 @@ module Seq =
/// A sequence of randomly selected elements from the input sequence.
///
/// Thrown when the input sequence is null.
- /// Thrown when the input sequence is empty.
+ /// Thrown when count is more than 0 and the input list is empty.
/// Thrown when count is less than 0.
/// Thrown when count is greater than the length of the input sequence.
/// Thrown when the randomizer function returns a number outside the range [0.0..1.0).
diff --git a/tests/FSharp.Build.UnitTests/FSharp.Build.UnitTests.fsproj b/tests/FSharp.Build.UnitTests/FSharp.Build.UnitTests.fsproj
index 853737b3ca8..07585566210 100644
--- a/tests/FSharp.Build.UnitTests/FSharp.Build.UnitTests.fsproj
+++ b/tests/FSharp.Build.UnitTests/FSharp.Build.UnitTests.fsproj
@@ -21,7 +21,7 @@
PreserveNewest
-
+
@@ -30,8 +30,11 @@
-
+
+
+
+
diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/NonStringArgs.fs b/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/NonStringArgs.fs
index 32f40de89d2..a28132266be 100644
--- a/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/NonStringArgs.fs
+++ b/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/NonStringArgs.fs
@@ -9,7 +9,7 @@ module NonStringArgs =
[]
[]
[]
- let ``#nowarn - errors`` (languageVersion) =
+ let ``#nowarn - errors - separate`` (languageVersion) =
FSharp """
#nowarn "988"
@@ -43,42 +43,7 @@ module NonStringArgs =
[]
[]
- []
- let ``#nowarn - errors - collected`` (languageVersion) =
-
- FSharp """
-#nowarn
- "988"
- FS
- FSBLAH
- ACME
- "FS"
- "FSBLAH"
- "ACME"
- """
- |> withLangVersion languageVersion
- |> asExe
- |> compile
- |> shouldFail
- |> withDiagnostics [
- if languageVersion = "8.0" then
- (Error 3350, Line 4, Col 5, Line 4, Col 7, "Feature '# directives with non-quoted string arguments' is not available in F# 8.0. Please use language version 9.0 or greater.")
- (Error 3350, Line 5, Col 5, Line 5, Col 11, "Feature '# directives with non-quoted string arguments' is not available in F# 8.0. Please use language version 9.0 or greater.")
- (Error 3350, Line 6, Col 5, Line 6, Col 9, "Feature '# directives with non-quoted string arguments' is not available in F# 8.0. Please use language version 9.0 or greater.")
- (Warning 203, Line 7, Col 5, Line 7, Col 9, "Invalid warning number 'FS'");
- (Warning 203, Line 8, Col 5, Line 8, Col 13, "Invalid warning number 'FSBLAH'");
- else
- (Warning 203, Line 4, Col 5, Line 4, Col 7, "Invalid warning number 'FS'");
- (Warning 203, Line 5, Col 5, Line 5, Col 11, "Invalid warning number 'FSBLAH'");
- (Warning 203, Line 6, Col 5, Line 6, Col 9, "Invalid warning number 'ACME'");
- (Warning 203, Line 7, Col 5, Line 7, Col 9, "Invalid warning number 'FS'");
- (Warning 203, Line 8, Col 5, Line 8, Col 13, "Invalid warning number 'FSBLAH'");
- (Warning 203, Line 9, Col 5, Line 9, Col 11, "Invalid warning number 'ACME'")
- ]
-
-
- []
- []
+ []
[]
let ``#nowarn - errors - inline`` (languageVersion) =
@@ -97,18 +62,26 @@ module NonStringArgs =
(Error 3350, Line 3, Col 19, Line 3, Col 23, "Feature '# directives with non-quoted string arguments' is not available in F# 8.0. Please use language version 9.0 or greater.")
(Warning 203, Line 3, Col 24, Line 3, Col 28, "Invalid warning number 'FS'");
(Warning 203, Line 3, Col 29, Line 3, Col 37, "Invalid warning number 'FSBLAH'");
- else
+ elif languageVersion = "9.0" then
(Warning 203, Line 3, Col 9, Line 3, Col 11, "Invalid warning number 'FS'");
(Warning 203, Line 3, Col 12, Line 3, Col 18, "Invalid warning number 'FSBLAH'");
(Warning 203, Line 3, Col 19, Line 3, Col 23, "Invalid warning number 'ACME'");
(Warning 203, Line 3, Col 24, Line 3, Col 28, "Invalid warning number 'FS'");
(Warning 203, Line 3, Col 29, Line 3, Col 37, "Invalid warning number 'FSBLAH'");
(Warning 203, Line 3, Col 38, Line 3, Col 44, "Invalid warning number 'ACME'")
+ else // preview
+ (Error 203, Line 3, Col 9, Line 3, Col 11, "Invalid warning number 'FS'");
+ (Error 203, Line 3, Col 12, Line 3, Col 18, "Invalid warning number 'FSBLAH'");
+ (Error 203, Line 3, Col 19, Line 3, Col 23, "Invalid warning number 'ACME'");
+ (Error 203, Line 3, Col 24, Line 3, Col 28, "Invalid warning number 'FS'");
+ (Error 203, Line 3, Col 29, Line 3, Col 37, "Invalid warning number 'FSBLAH'");
+ (Error 203, Line 3, Col 38, Line 3, Col 44, "Invalid warning number 'ACME'")
]
[]
[]
+ []
[]
let ``#nowarn - realcode`` (langVersion) =
@@ -142,10 +115,10 @@ module DoBinding =
compileResult
|> shouldFail
|> withDiagnostics [
- (Warning 1104, Line 5, Col 15, Line 5, Col 31, "Identifiers containing '@' are reserved for use in F# code generation")
(Error 3350, Line 2, Col 9, Line 2, Col 11, "Feature '# directives with non-quoted string arguments' is not available in F# 8.0. Please use language version 9.0 or greater.")
(Error 3350, Line 2, Col 12, Line 2, Col 18, "Feature '# directives with non-quoted string arguments' is not available in F# 8.0. Please use language version 9.0 or greater.")
(Warning 203, Line 2, Col 26, Line 2, Col 34, "Invalid warning number 'FS3221'")
+ (Warning 1104, Line 5, Col 15, Line 5, Col 31, "Identifiers containing '@' are reserved for use in F# code generation")
]
else
compileResult
diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Nowarn.fs b/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Nowarn.fs
new file mode 100644
index 00000000000..dfbb6d3a735
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Nowarn.fs
@@ -0,0 +1,184 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+namespace CompilerDirectives
+
+open Xunit
+open FSharp.Test.Compiler
+open FSharp.Test
+open System
+open System.Text
+
+module Nowarn =
+
+ let private nowarn n = $"#nowarn {n}"
+ let private warnon n = $"#warnon {n}"
+ let private line1 = """#line 1 "some.fsy" """
+ let private line10 = """#line 10 "some.fsy" """
+ let private make20 = "1"
+ let private make25 = "match None with None -> ()"
+ let private W20 = Warning 20
+ let private vp = "PREVIEW"
+ let private v9 = "9.0"
+ let private fs = String.concat Environment.NewLine >> FsSource
+ let private fsMod lines = fs ("module A" :: lines)
+ let private fsSub lines = fs ("namespace A" :: "module B =" :: (lines |> List.map (fun s -> " " + s)))
+ let private fsi = String.concat Environment.NewLine >> FsiSource
+ let private fsx = String.concat Environment.NewLine >> FsxSourceCode
+
+ let private fsiSource44 = [
+ "namespace A"
+ "[]"
+ "type T = class end"
+ "type T2 = T"
+ "#nowarn 44"
+ "type T3 = T"
+ "#warnon 44"
+ "type T4 = T"
+ "#nowarn 44"
+ "type T5 = T"
+ ]
+
+ let private fsSource44 = [
+ "namespace A"
+ "#nowarn 44"
+ "[]"
+ "type T = class end"
+ "type T2 = T"
+ "type T3 = T"
+ "type T4 = T"
+ "type T5 = T"
+ ]
+
+ let private testData =
+ [
+ vp, [], [fsMod [make20]], [W20, 2]
+ vp, [], [fsMod [nowarn 20; make20]], []
+ vp, [], [fsMod ["#nowarn 20;;"; make20]], []
+ vp, [], [fsMod [make20; nowarn 20; make20; warnon 20; make20]], [W20, 2; W20, 6]
+ v9, [], [fsMod [make20; nowarn 20; make20; warnon 20; make20]], [Error 3350, 5]
+ vp, [], [fsMod [nowarn 20; line1; make20]], []
+ v9, [], [fsMod [nowarn 20; line1; make20]], [] // real v9 shows a warning here
+ vp, [], [fsMod [nowarn 20; line10; make20]], []
+ v9, [], [fsMod [nowarn 20; line10; make20]], []
+ vp, [], [fsMod [nowarn 20; line1; make20; warnon 20; make20]], [W20, 3]
+ v9, [], [fsMod [nowarn 20; line1; make20; warnon 20; make20]], [Error 3350, 2]
+ vp, ["--nowarn:20"], [fsMod [make20]], []
+ v9, ["--nowarn:20"], [fsMod [make20]], []
+ vp, ["--nowarn:20"], [fsMod [warnon 20; make20]], [W20, 3]
+ v9, ["--nowarn:20"], [fsMod [warnon 20; make20]], [Error 3350, 2]
+ vp, ["--warnon:3579"], [fsMod ["""ignore $"{1}" """]], [Warning 3579, 2]
+ v9, ["--warnon:3579"], [fsMod ["""ignore $"{1}" """]], [Warning 3579, 2]
+ vp, [], [fsMod ["#warnon 3579"; """ignore $"{1}" """]], [Warning 3579, 3]
+ v9, [], [fsMod ["#warnon 3579"; """ignore $"{1}" """]], [Error 3350, 2]
+ vp, ["--warnaserror"], [fsMod [make20]], [Error 20, 2]
+ vp, ["--warnaserror"; "--nowarn:20"], [fsMod [make20]], []
+ vp, ["--warnaserror"; "--nowarn:20"], [fsMod [warnon 20; make20]], [Error 20, 3]
+ v9, ["--warnaserror"; "--nowarn:20"], [fsMod [warnon 20; make20]], [Error 3350, 2]
+ vp, ["--warnaserror"], [fsMod [nowarn 20; make20]], []
+ vp, ["--warnaserror"; "--warnaserror-:20"], [fsMod [make20]], [W20, 2]
+ vp, ["--warnaserror:20"], [fsMod [nowarn 20; make20]], []
+ vp, [], [fsSub [nowarn 20; make20]], []
+ v9, [], [fsSub [nowarn 20; make20]], [Warning 236, 3; W20, 4]
+ vp, [], [fsSub [make20; nowarn 20; make20; warnon 20; make20]], [W20, 3; W20, 7]
+ v9, [], [fsSub [make20; nowarn 20; make20; warnon 20; make20]], [Warning 236, 4; Warning 236, 6; W20, 3; W20, 5; W20, 7]
+ vp, [], [fsi fsiSource44; fs fsSource44], [Warning 44, 4; Warning 44, 8]
+ v9, [], [fsi fsiSource44; fs fsSource44], [Error 3350, 7]
+ vp, [], [fsx ["module A"; make20; nowarn 20; make20; warnon 20; make20]], [] // 20 is not checked in scripts
+ vp, [], [fsx ["module A"; make25; nowarn 25; make25; warnon 25; make25]], [Warning 25, 2; Warning 25, 6]
+ v9, [], [fsx ["module A"; make25; nowarn 25; make25; warnon 25; make25]], [Error 3350, 5]
+ v9, [], [fsx ["module A"; make25; nowarn 25; make25]], []
+ vp, [], [fsMod ["let x ="; nowarn 20; " 1"; warnon 20; " 2"; " 3"; "4"]], [W20, 6; W20, 8]
+ vp, [], [fsMod [nowarn 20; nowarn 20; warnon 20; make20]], [Information 3876, 3; W20, 5]
+ vp, [], [fsMod [nowarn 20; warnon 20; warnon 20; make20]], [Warning 3876, 4; W20, 5]
+ vp, ["--warnon:3876"], [fsMod [nowarn 20; nowarn 20; warnon 20; make20]], [Warning 3876, 3; W20, 5]
+ vp, [], [fsMod ["#nowarn \"\"\"20\"\"\" "; make20]], []
+ vp, [], [fsMod ["#nowarnx 20"; make20]], [Error 3353, 2]
+ vp, [], [fsMod ["#nowarn 20 // comment"; make20]], []
+ vp, [], [fsMod ["#nowarn"; make20]], [Error 3875, 2]
+ vp, [], [fsMod ["let a = 1; #nowarn 20"; make20]], [Error 3874, 2]
+ ]
+ |> List.mapi (fun i (v, fl, sources, diags) -> [|
+ box (i + 1)
+ box v
+ box fl
+ box (List.toArray sources)
+ box (List.toArray diags) |])
+
+ let testMemberData =
+ match System.Int32.TryParse(System.Environment.GetEnvironmentVariable("NowarnSingleTest")) with
+ | true, n when n > 0 && n <= testData.Length -> [testData[n-1]]
+ | _ -> testData
+
+ let private testFailed (expected: (ErrorType * int) list) (actual: ErrorInfo list) =
+ expected.Length <> actual.Length
+ || (List.zip expected actual |> List.exists(fun((error, line), d) -> error <> d.Error || line <> d.Range.StartLine))
+
+ let private withDiags testId langVersion flags (sources: SourceCodeFileKind list) (expected: (ErrorType * int) list) (result: CompilationResult) =
+ let actual = result.Output.Diagnostics
+ if testFailed expected actual then
+ let sb = new StringBuilder()
+ let print (s: string) = sb.AppendLine s |> ignore
+ print ""
+ print $"test {testId} of {testData.Length}"
+ print " language version:"
+ print $" {langVersion}"
+ print " added compiler options:"
+ for flag in flags do print $" {flag}"
+ for source in sources do
+ print $" source code %s{source.GetSourceFileName}:"
+ let text = source.GetSourceText |> Option.defaultValue ""
+ let lines = text.Split(Environment.NewLine |> Seq.toArray) |> Array.toList
+ for line in lines do print $" {line}"
+ print $" expected diagnostics:"
+ for (error, line) in expected do print $" {error} in line {line}"
+ print $" actual diagnostics:"
+ for d in actual do print $" {d.Error} in line {d.Range.StartLine}"
+ Assert.Fail(string sb)
+
+ []
+ []
+ let testWarnScopes testId langVersion flags (sourceArray: SourceCodeFileKind array) expectedDiags =
+ let sources = Array.toList sourceArray
+ sources.Head
+ |> fsFromString
+ |> FS
+ |> withAdditionalSourceFiles sources.Tail
+ |> withLangVersion langVersion
+ |> withOptions flags
+ |> compile
+ |> withDiags testId langVersion flags sources (Array.toList expectedDiags)
+
+ []
+ let testBadLineDirectiveInteraction() =
+ let sources =
+ [
+ "test1.fs", "module A1 \n#line 10 \"test.fsy\" \n()"
+ "test2.fs", "module A2 \n#line 20 \"test.fsy\" \n()"
+ ]
+ |> List.map (fun (name, text) -> {FileName = name; SourceText = Some text})
+ |> List.map SourceCodeFileKind.Fs
+ let result =
+ sources.Head
+ |> fsFromString
+ |> FS
+ |> withAdditionalSourceFiles sources.Tail
+ |> compile
+ let actual = result.Output.Diagnostics
+ if actual.Length <> 1 then Assert.Fail $"expected 1 warning, got {actual.Length}"
+ let errorInfo = actual.Head
+ if errorInfo.Error <> Warning 3877 then Assert.Fail $"expected Warning 3877, got {errorInfo.Error}"
+ if errorInfo.Range.StartLine <> 3 then Assert.Fail $"expected warning in line 3, got line {errorInfo.Range.StartLine}"
+ if not <| errorInfo.Message.StartsWith "The file 'test.fsy' was also pointed to" then Assert.Fail $"unexpected message {errorInfo.Message}"
+
+ []
+ let warnDirectiveArgRange() =
+ FSharp """
+module A
+#nowarn xy "abx"
+let a = 1; #nowarn 20
+"""
+ |> compile
+ |> withDiagnostics [
+ Error 3874, Line 4, Col 11, Line 4, Col 22, "#nowarn/#warnon directives must appear as the first non-whitespace characters on a line"
+ Warning 203, Line 3, Col 9, Line 3, Col 11, "Invalid warning number 'xy'"
+ Warning 203, Line 3, Col 12, Line 3, Col 17, "Invalid warning number 'abx'"
+ ]
diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/checked/checked.fs b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/checked/checked.fs
index 8a0447a450e..b842f04de77 100644
--- a/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/checked/checked.fs
+++ b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/checked/checked.fs
@@ -12,7 +12,7 @@ module Checked =
[]
let ``fsc-unchecked - unchecked01_fs`` compilation =
compilation
- |> getCompilation
+ |> getCompilation
|> asFs
|> compile
|> shouldSucceed
diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/Caches.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/Caches.fs
new file mode 100644
index 00000000000..3849cd9addd
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/Caches.fs
@@ -0,0 +1,90 @@
+module CompilerService.Caches
+
+open FSharp.Compiler.Caches
+
+open System.Threading
+open Xunit
+
+[]
+let ``Create and dispose many`` () =
+ let caches =
+ [
+ for _ in 1 .. 100 do
+ Cache.Create(CacheOptions.Default, observeMetrics = true)
+ ]
+
+ for c in caches do c.Dispose()
+
+[]
+let ``Create and dispose many named`` () =
+ let caches =
+ [
+ for i in 1 .. 100 do
+ Cache.Create(CacheOptions.Default, name = $"testCache{i}", observeMetrics = true)
+ ]
+
+ for c in caches do c.Dispose()
+
+[]
+let ``Basic add and retrieve`` () =
+ use cache = Cache.Create(CacheOptions.Default, observeMetrics = true)
+
+ cache.TryAdd("key1", 1) |> ignore
+ cache.TryAdd("key2", 2) |> ignore
+
+ let mutable value = 0
+ Assert.True(cache.TryGetValue("key1", &value), "Should retrieve key1")
+ Assert.Equal(1, value)
+ Assert.True(cache.TryGetValue("key2", &value), "Should retrieve key2")
+ Assert.Equal(2, value)
+ Assert.False(cache.TryGetValue("key3", &value), "Should not retrieve non-existent key3")
+
+[]
+let ``Eviction of least recently used`` () =
+ use cache = Cache.Create({ TotalCapacity = 2; HeadroomPercentage = 0 }, observeMetrics = true)
+
+ cache.TryAdd("key1", 1) |> ignore
+ cache.TryAdd("key2", 2) |> ignore
+
+ // Make key1 recently used by accessing it
+ let mutable value = 0
+ cache.TryGetValue("key1", &value) |> ignore
+
+ let evicted = new ManualResetEvent(false)
+ cache.Evicted.Add(fun _ -> evicted.Set() |> ignore)
+
+ // Add a third item, which should schedule key2 for eviction
+ cache.TryAdd("key3", 3) |> ignore
+
+ // Wait for eviction to complete using the event
+ evicted.WaitOne() |> ignore
+
+ Assert.False(cache.TryGetValue("key2", &value), "key2 should have been evicted")
+ Assert.True(cache.TryGetValue("key1", &value), "key1 should still be in cache")
+ Assert.Equal(1, value)
+ Assert.True(cache.TryGetValue("key3", &value), "key3 should be in cache")
+ Assert.Equal(3, value)
+
+[]
+let ``Metrics can be retrieved`` () =
+ use cache = Cache.Create({ TotalCapacity = 2; HeadroomPercentage = 0 }, name = "test_metrics", observeMetrics = true)
+
+ cache.TryAdd("key1", 1) |> ignore
+ cache.TryAdd("key2", 2) |> ignore
+
+ // Make key1 recently used by accessing it
+ let mutable value = 0
+ cache.TryGetValue("key1", &value) |> ignore
+
+ let evicted = new ManualResetEvent(false)
+ cache.Evicted.Add(fun _ -> evicted.Set() |> ignore)
+
+ // Add a third item, which should schedule key2 for eviction
+ cache.TryAdd("key3", 3) |> ignore
+
+ // Wait for eviction to complete using the event
+ evicted.WaitOne() |> ignore
+
+ let metrics = CacheMetrics.GetStats "test_metrics"
+
+ Assert.Contains("test_metrics | hit ratio", metrics)
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs
index c7c2cf72eca..f027745b73e 100644
--- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs
@@ -104,10 +104,10 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 21, Col 21, Line 21, Col 22, "This attribute is not valid for use on this language element")
- (Error 842, Line 24, Col 21, Line 24, Col 29, "This attribute is not valid for use on this language element")
- (Error 842, Line 27, Col 7, Line 27, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 18, Col 7, Line 18, Col 8, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 21, Col 21, Line 21, Col 22, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 24, Col 21, Line 24, Col 29, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 27, Col 7, Line 27, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 18, Col 7, Line 18, Col 8, "This attribute is not valid for use on this language element")
]
// SOURCE=E_AttributeTargets02.fs # E_AttributeTargets02.fs
@@ -117,9 +117,10 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 14, Col 7, Line 14, Col 34, "This attribute is not valid for use on this language element")
- (Error 842, Line 24, Col 7, Line 24, Col 36, "This attribute is not valid for use on this language element")
- (Error 842, Line 29, Col 15, Line 29, Col 47, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 14, Col 7, Line 14, Col 34, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 24, Col 7, Line 24, Col 36, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 29, Col 15, Line 29, Col 47, "This attribute is not valid for use on this language element")
+ (Error 3172, Line 28, Col 14, Line 28, Col 17, "A property's getter and setter must have the same type. Property 'Foo' has getter of type 'int' but setter of type 'obj'.")
]
// SOURCE=E_AttributeTargetIsField01.fs # E_AttributeTargetIsField01.fs
@@ -140,23 +141,23 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 9, Col 3, Line 9, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 12, Col 3, Line 12, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 15, Col 3, Line 15, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 18, Col 3, Line 18, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 21, Col 3, Line 21, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 24, Col 3, Line 24, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 27, Col 3, Line 27, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 30, Col 3, Line 30, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 33, Col 3, Line 33, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 36, Col 3, Line 36, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 39, Col 3, Line 39, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 42, Col 3, Line 42, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 45, Col 3, Line 45, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 49, Col 3, Line 49, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 56, Col 3, Line 56, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 64, Col 3, Line 64, Col 12, "This attribute is not valid for use on this language element")
- (Error 842, Line 66, Col 7, Line 66, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 9, Col 3, Line 9, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 12, Col 3, Line 12, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 15, Col 3, Line 15, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 18, Col 3, Line 18, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 21, Col 3, Line 21, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 24, Col 3, Line 24, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 27, Col 3, Line 27, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 30, Col 3, Line 30, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 33, Col 3, Line 33, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 36, Col 3, Line 36, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 39, Col 3, Line 39, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 42, Col 3, Line 42, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 45, Col 3, Line 45, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 49, Col 3, Line 49, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 56, Col 3, Line 56, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 64, Col 3, Line 64, Col 12, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 66, Col 7, Line 66, Col 16, "This attribute is not valid for use on this language element")
]
// SOURCE=E_AttributeTargetIsField02.fs # E_AttributeTargetIsField02.fs
@@ -194,17 +195,17 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 9, Col 3, Line 9, Col 13, "This attribute is not valid for use on this language element")
- (Error 842, Line 12, Col 3, Line 12, Col 13, "This attribute is not valid for use on this language element")
- (Error 842, Line 15, Col 3, Line 15, Col 13, "This attribute is not valid for use on this language element")
- (Error 842, Line 18, Col 3, Line 18, Col 13, "This attribute is not valid for use on this language element")
- (Error 842, Line 21, Col 3, Line 21, Col 13, "This attribute is not valid for use on this language element")
- (Error 842, Line 24, Col 3, Line 24, Col 13, "This attribute is not valid for use on this language element")
- (Error 842, Line 26, Col 7, Line 26, Col 17, "This attribute is not valid for use on this language element")
- (Error 842, Line 28, Col 3, Line 28, Col 13, "This attribute is not valid for use on this language element")
- (Error 842, Line 31, Col 3, Line 31, Col 13, "This attribute is not valid for use on this language element")
- (Error 842, Line 34, Col 3, Line 34, Col 13, "This attribute is not valid for use on this language element")
- (Error 842, Line 39, Col 3, Line 39, Col 13, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 9, Col 3, Line 9, Col 13, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 12, Col 3, Line 12, Col 13, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 15, Col 3, Line 15, Col 13, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 18, Col 3, Line 18, Col 13, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 21, Col 3, Line 21, Col 13, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 24, Col 3, Line 24, Col 13, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 26, Col 7, Line 26, Col 17, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 28, Col 3, Line 28, Col 13, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 31, Col 3, Line 31, Col 13, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 34, Col 3, Line 34, Col 13, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 39, Col 3, Line 39, Col 13, "This attribute is not valid for use on this language element")
]
// SOURCE=E_AttributeTargetIsMethod03.fs # E_AttributeTargetIsMethod03.fs
@@ -225,21 +226,21 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 12, Col 6, Line 12, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 15, Col 6, Line 15, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 18, Col 6, Line 18, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 20, Col 10, Line 20, Col 20, "This attribute is not valid for use on this language element")
- (Error 842, Line 22, Col 6, Line 22, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 25, Col 6, Line 25, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 28, Col 6, Line 28, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 31, Col 6, Line 31, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 34, Col 6, Line 34, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 37, Col 6, Line 37, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 39, Col 10, Line 39, Col 20, "This attribute is not valid for use on this language element")
- (Error 842, Line 41, Col 6, Line 41, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 44, Col 6, Line 44, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 47, Col 6, Line 47, Col 16, "This attribute is not valid for use on this language element")
- (Error 842, Line 52, Col 6, Line 52, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 12, Col 6, Line 12, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 15, Col 6, Line 15, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 18, Col 6, Line 18, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 20, Col 10, Line 20, Col 20, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 22, Col 6, Line 22, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 25, Col 6, Line 25, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 28, Col 6, Line 28, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 31, Col 6, Line 31, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 34, Col 6, Line 34, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 37, Col 6, Line 37, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 39, Col 10, Line 39, Col 20, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 41, Col 6, Line 41, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 44, Col 6, Line 44, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 47, Col 6, Line 47, Col 16, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 52, Col 6, Line 52, Col 16, "This attribute is not valid for use on this language element")
]
// SOURCE=E_AttributeTargetIsMethod04.fs # E_AttributeTargetIsMethod04.fs
@@ -250,8 +251,8 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 10, Col 3, Line 10, Col 15, "This attribute is not valid for use on this language element")
- (Error 842, Line 13, Col 3, Line 13, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 10, Col 3, Line 10, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 13, Col 3, Line 13, Col 15, "This attribute is not valid for use on this language element")
]
// SOURCE=E_ConditionalAttribute.fs SCFLAGS="--test:ErrorRanges" # E_ConditionalAttribute.fs
@@ -293,7 +294,7 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 12, Col 3, Line 12, Col 6, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 12, Col 3, Line 12, Col 6, "This attribute is not valid for use on this language element")
]
// SOURCE=AttributeTargetIsStruct.fs # AttributeTargetIsStruct.fs
@@ -342,18 +343,18 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 13, Col 3, Line 13, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 19, Col 3, Line 19, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 22, Col 11, Line 22, Col 22, "This attribute is not valid for use on this language element")
- (Error 842, Line 25, Col 3, Line 25, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 34, Col 3, Line 34, Col 18, "This attribute is not valid for use on this language element")
- (Error 842, Line 35, Col 3, Line 35, Col 15, "This attribute is not valid for use on this language element")
- (Error 842, Line 40, Col 3, Line 40, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 41, Col 3, Line 41, Col 18, "This attribute is not valid for use on this language element")
- (Error 842, Line 49, Col 3, Line 49, Col 18, "This attribute is not valid for use on this language element")
- (Error 842, Line 50, Col 3, Line 50, Col 15, "This attribute is not valid for use on this language element")
- (Error 842, Line 53, Col 3, Line 53, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 54, Col 3, Line 54, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 13, Col 3, Line 13, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 19, Col 3, Line 19, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 22, Col 11, Line 22, Col 22, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 25, Col 3, Line 25, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 34, Col 3, Line 34, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 35, Col 3, Line 35, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 40, Col 3, Line 40, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 41, Col 3, Line 41, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 49, Col 3, Line 49, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 50, Col 3, Line 50, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 53, Col 3, Line 53, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 54, Col 3, Line 54, Col 18, "This attribute is not valid for use on this language element")
]
// SOURCE=E_AttributeTargetIsClass.fs # E_AttributeTargetIsClass.fs
@@ -372,9 +373,9 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 13, Col 3, Line 13, Col 15, "This attribute is not valid for use on this language element")
- (Error 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element")
- (Error 842, Line 22, Col 10, Line 22, Col 22, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 13, Col 3, Line 13, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 22, Col 10, Line 22, Col 22, "This attribute is not valid for use on this language element")
]
// SOURCE=E_AttributeTargetIsClass01.fs # E_AttributeTargetIsClass01.fs
@@ -393,8 +394,8 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 7, Col 3, Line 7, Col 18, "This attribute is not valid for use on this language element")
- (Error 842, Line 10, Col 10, Line 10, Col 25, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 7, Col 3, Line 7, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 10, Col 10, Line 10, Col 25, "This attribute is not valid for use on this language element")
]
// SOURCE=MarshalAsAttribute.fs # MarshalAsAttribute.fs
@@ -480,7 +481,7 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element")
]
// SOURCE=E_AttributeTargetIsField03.fs # E_AttributeTargetIsField03.fs
@@ -491,8 +492,8 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element")
- (Error 842, Line 15, Col 5, Line 15, Col 25, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 15, Col 5, Line 15, Col 25, "This attribute is not valid for use on this language element")
]
// SOURCE=E_AttributeTargetIsProperty01.fs # E_AttributeTargetIsField03.fs
@@ -511,8 +512,8 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 14, Col 5, Line 14, Col 18, "This attribute is not valid for use on this language element")
- (Error 842, Line 15, Col 5, Line 15, Col 25, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 14, Col 5, Line 14, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 15, Col 5, Line 15, Col 25, "This attribute is not valid for use on this language element")
]
// SOURCE=E_AttributeTargetIsCtor01.fs # E_AttributeTargetIsCtor01.fs
@@ -531,10 +532,10 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 9, Col 15, Line 9, Col 27, "This attribute is not valid for use on this language element")
- (Error 842, Line 11, Col 16, Line 11, Col 28, "This attribute is not valid for use on this language element")
- (Error 842, Line 14, Col 15, Line 14, Col 27, "This attribute is not valid for use on this language element")
- (Error 842, Line 17, Col 16, Line 17, Col 28, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 9, Col 15, Line 9, Col 27, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 11, Col 16, Line 11, Col 28, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 14, Col 15, Line 14, Col 27, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 17, Col 16, Line 17, Col 28, "This attribute is not valid for use on this language element")
]
// SOURCE=AttributeTargetsIsEnum01.fs # AttributeTargetsIsEnum01.fs
@@ -568,10 +569,10 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element")
- (Error 842, Line 20, Col 3, Line 20, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element")
- (Error 842, Line 22, Col 3, Line 22, Col 17, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 20, Col 3, Line 20, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 22, Col 3, Line 22, Col 17, "This attribute is not valid for use on this language element")
]
// SOURCE=AttributeTargetsIsDelegate01.fs # AttributeTargetsIsDelegate01.fs
@@ -605,10 +606,10 @@ module CustomAttributes_AttributeUsage =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 19, Col 3, Line 19, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 20, Col 3, Line 20, Col 15, "This attribute is not valid for use on this language element")
- (Error 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element")
- (Error 842, Line 22, Col 3, Line 22, Col 13, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 19, Col 3, Line 19, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 20, Col 3, Line 20, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 22, Col 3, Line 22, Col 13, "This attribute is not valid for use on this language element")
]
[]
@@ -654,10 +655,10 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 11, Col 3, Line 11, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 14, Col 3, Line 14, Col 15, "This attribute is not valid for use on this language element")
- (Error 842, Line 18, Col 3, Line 18, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 11, Col 3, Line 11, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 14, Col 3, Line 14, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 18, Col 3, Line 18, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element")
]
// SOURCE= E_AttributeTargetIsClass02.fs # E_AttributeTargetIsClass02.fs
@@ -676,18 +677,18 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 15, Col 3, Line 15, Col 18, "This attribute is not valid for use on this language element");
- (Error 842, Line 16, Col 3, Line 16, Col 15, "This attribute is not valid for use on this language element")
- (Error 842, Line 20, Col 3, Line 20, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element")
- (Error 842, Line 26, Col 3, Line 26, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 27, Col 3, Line 27, Col 18, "This attribute is not valid for use on this language element")
- (Error 842, Line 34, Col 3, Line 34, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 35, Col 3, Line 35, Col 18, "This attribute is not valid for use on this language element")
- (Error 842, Line 43, Col 3, Line 43, Col 18, "This attribute is not valid for use on this language element")
- (Error 842, Line 44, Col 3, Line 44, Col 15, "This attribute is not valid for use on this language element")
- (Error 842, Line 47, Col 3, Line 47, Col 14, "This attribute is not valid for use on this language element")
- (Error 842, Line 48, Col 3, Line 48, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 15, Col 3, Line 15, Col 18, "This attribute is not valid for use on this language element");
+ (Warning 842, Line 16, Col 3, Line 16, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 20, Col 3, Line 20, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 26, Col 3, Line 26, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 27, Col 3, Line 27, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 34, Col 3, Line 34, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 35, Col 3, Line 35, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 43, Col 3, Line 43, Col 18, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 44, Col 3, Line 44, Col 15, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 47, Col 3, Line 47, Col 14, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 48, Col 3, Line 48, Col 18, "This attribute is not valid for use on this language element")
]
// SOURCE= CLIMutableAttribute01.fs # CLIMutableAttribute01.fs
@@ -756,8 +757,8 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) =
(Error 934, Line 33, Col 10, Line 33, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute")
(Error 934, Line 36, Col 10, Line 36, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute")
(Error 934, Line 39, Col 10, Line 39, Col 13, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute")
- (Error 842, Line 41, Col 7, Line 41, Col 23, "This attribute is not valid for use on this language element")
- (Error 842, Line 44, Col 7, Line 44, Col 23, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 41, Col 7, Line 41, Col 23, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 44, Col 7, Line 44, Col 23, "This attribute is not valid for use on this language element")
(Error 935, Line 54, Col 10, Line 54, Col 11, "Types with the 'AllowNullLiteral' attribute may only inherit from or implement types which also allow the use of the null literal")
]
@@ -775,8 +776,8 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) =
(Error 934, Line 33, Col 10, Line 33, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute")
(Error 934, Line 36, Col 10, Line 36, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute")
(Error 934, Line 39, Col 10, Line 39, Col 13, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute")
- (Error 842, Line 41, Col 7, Line 41, Col 23, "This attribute is not valid for use on this language element")
- (Error 842, Line 44, Col 7, Line 44, Col 23, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 41, Col 7, Line 41, Col 23, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 44, Col 7, Line 44, Col 23, "This attribute is not valid for use on this language element")
(Error 935, Line 54, Col 10, Line 54, Col 11, "Types with the 'AllowNullLiteral' attribute may only inherit from or implement types which also allow the use of the null literal")
]
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs
index 1e3c99dc8a5..44ee388af9d 100644
--- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs
@@ -61,7 +61,7 @@ module CustomAttributes_Basic =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 15, Col 7, Line 15, Col 17, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 15, Col 7, Line 15, Col 17, "This attribute is not valid for use on this language element")
]
// SOURCE=E_AttributeApplication04.fs SCFLAGS="--test:ErrorRanges" # E_AttributeApplication04.fs
@@ -71,7 +71,7 @@ module CustomAttributes_Basic =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 14, Col 3, Line 14, Col 13, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 14, Col 3, Line 14, Col 13, "This attribute is not valid for use on this language element")
]
// SOURCE=E_AttributeApplication05.fs SCFLAGS="--test:ErrorRanges" # E_AttributeApplication05.fs
@@ -81,7 +81,8 @@ module CustomAttributes_Basic =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 8, Col 7, Line 8, Col 8, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 8, Col 7, Line 8, Col 8, "This attribute is not valid for use on this language element")
+ (Error 824, Line 8, Col 7, Line 8, Col 8, "Attributes are not permitted on 'let' bindings in expressions")
(Warning 20, Line 8, Col 1, Line 8, Col 31, "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'.")
]
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/EntryPoint/EntryPoint.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/EntryPoint/EntryPoint.fs
index ce51bcf6c14..38b84fb6498 100644
--- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/EntryPoint/EntryPoint.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/EntryPoint/EntryPoint.fs
@@ -75,7 +75,7 @@ module EntryPoint =
|> compile
|> shouldFail
|> withDiagnostics [
- (Error 842, Line 9, Col 3, Line 9, Col 13, """This attribute is not valid for use on this language element""")
+ (Warning 842, Line 9, Col 3, Line 9, Col 13, """This attribute is not valid for use on this language element""")
]
// SOURCE=E_twoattributesonsamefunction001.fs SCFLAGS="--test:ErrorRanges" # E_twoattributesonsamefunction001.fs
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/LetBindings/Basic/Basic.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/LetBindings/Basic/Basic.fs
index c0a19c9ad3e..b59d28cbdd2 100644
--- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/LetBindings/Basic/Basic.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/LetBindings/Basic/Basic.fs
@@ -53,9 +53,9 @@ module LetBindings_Basic =
|> shouldFail
|> withDiagnostics [
(Error 683, Line 14, Col 6, Line 14, Col 27, "Attributes are not allowed within patterns")
- (Error 842, Line 14, Col 8, Line 14, Col 25, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 14, Col 8, Line 14, Col 25, "This attribute is not valid for use on this language element")
(Error 683, Line 14, Col 42, Line 14, Col 63, "Attributes are not allowed within patterns")
- (Error 842, Line 14, Col 44, Line 14, Col 61, "This attribute is not valid for use on this language element")
+ (Warning 842, Line 14, Col 44, Line 14, Col 61, "This attribute is not valid for use on this language element")
]
// SOURCE=E_ErrorsForInlineValue.fs SCFLAGS="--test:ErrorRanges" # E_ErrorsForInlineValue.fs
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang01.fs
new file mode 100644
index 00000000000..4b6335c3789
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang01.fs
@@ -0,0 +1,58 @@
+open System
+
+open System
+
+type Disposable(id: int) =
+ static let mutable disposedIds = Set.empty
+ static let mutable constructedIds = Set.empty
+
+ do constructedIds <- constructedIds.Add(id)
+
+ member _.Id = id
+
+ static member GetDisposed() = disposedIds
+ static member GetConstructed() = constructedIds
+ static member Reset() =
+ disposedIds <- Set.empty
+ constructedIds <- Set.empty
+
+ interface IDisposable with
+ member this.Dispose() = disposedIds <- disposedIds.Add(this.Id)
+
+type DisposableBuilder() =
+ member _.Using(resource: #IDisposable, f) =
+ async {
+ use res = resource
+ return! f res
+ }
+
+ member _.Bind(disposable: Disposable, f) = async.Bind(async.Return(disposable), f)
+ member _.Return(x) = async.Return x
+ member _.ReturnFrom(x) = x
+ member _.Bind(task, f) = async.Bind(task, f)
+
+let counterDisposable = DisposableBuilder()
+
+let testBindingPatterns() =
+ Disposable.Reset()
+
+ counterDisposable {
+ use! res = new Disposable(1)
+ use! __ = new Disposable(2)
+ use! (res1) = new Disposable(3)
+ use! _ = new Disposable(4)
+ use! (_) = new Disposable(5)
+ return ()
+ } |> Async.RunSynchronously
+
+ let constructed = Disposable.GetConstructed()
+ let disposed = Disposable.GetDisposed()
+ let undisposed = constructed - disposed
+
+ if not undisposed.IsEmpty then
+ printfn $"Undisposed instances: %A{undisposed}"
+ failwithf "Not all disposables were properly disposed"
+ else
+ printfn $"Success! All %d{constructed.Count} disposables were properly disposed"
+
+testBindingPatterns()
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang02.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang02.fs
new file mode 100644
index 00000000000..d57f0b8c14d
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang02.fs
@@ -0,0 +1,57 @@
+open System
+
+open System
+
+type Disposable(id: int) =
+ static let mutable disposedIds = Set.empty
+ static let mutable constructedIds = Set.empty
+
+ do constructedIds <- constructedIds.Add(id)
+
+ member _.Id = id
+
+ static member GetDisposed() = disposedIds
+ static member GetConstructed() = constructedIds
+ static member Reset() =
+ disposedIds <- Set.empty
+ constructedIds <- Set.empty
+
+ interface IDisposable with
+ member this.Dispose() = disposedIds <- disposedIds.Add(this.Id)
+
+type DisposableBuilder() =
+ member _.Using(resource: #IDisposable, f) =
+ async {
+ use res = resource
+ return! f res
+ }
+
+ member _.Bind(disposable: Disposable, f) = async.Bind(async.Return(disposable), f)
+ member _.Return(x) = async.Return x
+ member _.ReturnFrom(x) = x
+ member _.Bind(task, f) = async.Bind(task, f)
+
+let counterDisposable = DisposableBuilder()
+
+let testBindingPatterns() =
+ Disposable.Reset()
+
+ counterDisposable {
+ use! _ = new Disposable(1)
+ use! _ = new Disposable(2)
+ use! (_) = new Disposable(3)
+ use! (_) = new Disposable(4)
+ return ()
+ } |> Async.RunSynchronously
+
+ let constructed = Disposable.GetConstructed()
+ let disposed = Disposable.GetDisposed()
+ let undisposed = constructed - disposed
+
+ if not undisposed.IsEmpty then
+ printfn $"Undisposed instances: %A{undisposed}"
+ failwithf "Not all disposables were properly disposed"
+ else
+ printfn $"Success! All %d{constructed.Count} disposables were properly disposed"
+
+testBindingPatterns()
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang03.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang03.fs
new file mode 100644
index 00000000000..57c814c561a
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang03.fs
@@ -0,0 +1,71 @@
+open System
+
+type Disposable(id: int) =
+ static let mutable disposedIds = Map.empty
+ static let mutable constructedIds = Set.empty
+
+ do constructedIds <- constructedIds.Add(id)
+
+ member _.Id = id
+
+ static member GetDisposed() = disposedIds
+ static member GetConstructed() = constructedIds
+ static member Reset() =
+ disposedIds <- Map.empty
+ constructedIds <- Set.empty
+
+ interface IDisposable with
+ member this.Dispose() =
+ let currentCount =
+ match Map.tryFind this.Id disposedIds with
+ | Some count -> count
+ | None -> 0
+ disposedIds <- Map.add this.Id (currentCount + 1) disposedIds
+
+type DisposableBuilder() =
+ member _.Using(resource: #IDisposable, f) =
+ async {
+ use res = resource
+ return! f res
+ }
+
+ member _.Bind(disposable: Disposable, f) = async.Bind(async.Return(disposable), f)
+ member _.Return(x) = async.Return x
+ member _.ReturnFrom(x) = x
+ member _.Bind(task, f) = async.Bind(task, f)
+
+let counterDisposable = DisposableBuilder()
+
+let testBindingPatterns() =
+ Disposable.Reset()
+
+ counterDisposable {
+ use! res = new Disposable(1)
+ use! __ = new Disposable(2)
+ use! (res1) = new Disposable(3)
+ use! _ = new Disposable(4)
+ use! (_) = new Disposable(5)
+ return ()
+ } |> Async.RunSynchronously
+
+ let constructed = Disposable.GetConstructed()
+ let disposed = Disposable.GetDisposed()
+
+ let disposedSet = Set.ofSeq (Map.keys disposed)
+ let undisposed = constructed - disposedSet
+
+ if not undisposed.IsEmpty then
+ printfn $"Undisposed instances: %A{undisposed}"
+ failwithf "Not all disposables were properly disposed"
+
+ let multipleDisposed =
+ disposed
+ |> Map.filter (fun _ count -> count > 1)
+
+ if not multipleDisposed.IsEmpty then
+ printfn $"Objects disposed multiple times: %A{multipleDisposed}"
+ failwithf "Some disposables were disposed multiple times"
+
+ printfn $"Success! All %d{constructed.Count} disposables were properly disposed exactly once"
+
+testBindingPatterns()
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang04.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang04.fs
new file mode 100644
index 00000000000..3c32e29bc46
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang04.fs
@@ -0,0 +1,91 @@
+open System
+
+type Disposable(id: int) =
+ static let mutable disposedIds = Map.empty
+ static let mutable constructedIds = Set.empty
+
+ do constructedIds <- constructedIds.Add(id)
+
+ member _.Id = id
+
+ static member GetDisposed() = disposedIds
+ static member GetConstructed() = constructedIds
+ static member Reset() =
+ disposedIds <- Map.empty
+ constructedIds <- Set.empty
+
+ interface IDisposable with
+ member this.Dispose() =
+ let currentCount =
+ match Map.tryFind this.Id disposedIds with
+ | Some count -> count
+ | None -> 0
+ disposedIds <- Map.add this.Id (currentCount + 1) disposedIds
+
+type DisposableBuilder() =
+ member _.Using(resource: #IDisposable, f) =
+ async {
+ use res = resource
+ return! f res
+ }
+
+ member _.Bind(disposable: Disposable, f) = async.Bind(async.Return(disposable), f)
+ member _.Return(x) = async.Return x
+ member _.ReturnFrom(x) = x
+ member _.Bind(task, f) = async.Bind(task, f)
+
+let counterDisposable = DisposableBuilder()
+
+let testBindingPatterns() =
+ Disposable.Reset()
+
+ counterDisposable {
+ use! res = new Disposable(1)
+ use! __ = new Disposable(2)
+ use! (res1) = new Disposable(3)
+
+ use! _ = new Disposable(4)
+ use! _ = new Disposable(5)
+
+ use! x = new Disposable(6)
+ use! x = new Disposable(7)
+
+ use! (_) = new Disposable(8)
+ use! (_) = new Disposable(9)
+
+ return ()
+ } |> Async.RunSynchronously
+
+ let constructed = Disposable.GetConstructed()
+ let disposed = Disposable.GetDisposed()
+
+ let disposedSet = Set.ofSeq (Map.keys disposed)
+ let undisposed = constructed - disposedSet
+
+ if not undisposed.IsEmpty then
+ printfn $"Undisposed instances: %A{undisposed}"
+ failwithf "Not all disposables were properly disposed"
+
+ // Verify each object was disposed exactly once
+ let incorrectlyDisposed =
+ disposed
+ |> Map.partition (fun _ count -> count = 1)
+ |> snd
+
+ if not incorrectlyDisposed.IsEmpty then
+ printfn $"Objects with incorrect disposal count: %A{incorrectlyDisposed}"
+ failwithf "Some disposables were not disposed exactly once"
+
+ let idChecks =
+ [1..9] |> List.map (fun id ->
+ match Map.tryFind id disposed with
+ | Some 1 -> true
+ | _ -> false
+ )
+
+ if not ((List.forall id) idChecks) then
+ failwithf "Not all disposable IDs were properly handled"
+
+ printfn $"Success! All %d{constructed.Count} disposables were properly disposed exactly once, including repeated patterns"
+
+testBindingPatterns()
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang05.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang05.fs
new file mode 100644
index 00000000000..7bd2b4cd827
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang05.fs
@@ -0,0 +1,58 @@
+open System
+
+open System
+
+type Disposable(id: int) =
+ static let mutable disposedIds = Set.empty
+ static let mutable constructedIds = Set.empty
+
+ do constructedIds <- constructedIds.Add(id)
+
+ member _.Id = id
+
+ static member GetDisposed() = disposedIds
+ static member GetConstructed() = constructedIds
+ static member Reset() =
+ disposedIds <- Set.empty
+ constructedIds <- Set.empty
+
+ interface IDisposable with
+ member this.Dispose() = disposedIds <- disposedIds.Add(this.Id)
+
+type DisposableBuilder() =
+ member _.Using(resource: #IDisposable, f) =
+ async {
+ use res = resource
+ return! f res
+ }
+
+ member _.Bind(disposable: Disposable, f) = async.Bind(async.Return(disposable), f)
+ member _.Return(x) = async.Return x
+ member _.ReturnFrom(x) = x
+ member _.Bind(task, f) = async.Bind(task, f)
+
+let counterDisposable = DisposableBuilder()
+
+let testBindingPatterns() =
+ Disposable.Reset()
+
+ counterDisposable {
+ use! res:IDisposable = new Disposable(1)
+ use! __:IDisposable = new Disposable(2)
+ use! (res1: IDisposable) = new Disposable(3)
+ use! _: IDisposable = new Disposable(4)
+ use! (_: IDisposable) = new Disposable(5)
+ return ()
+ } |> Async.RunSynchronously
+
+ let constructed = Disposable.GetConstructed()
+ let disposed = Disposable.GetDisposed()
+ let undisposed = constructed - disposed
+
+ if not undisposed.IsEmpty then
+ printfn $"Undisposed instances: %A{undisposed}"
+ failwithf "Not all disposables were properly disposed"
+ else
+ printfn $"Success! All %d{constructed.Count} disposables were properly disposed"
+
+testBindingPatterns()
\ No newline at end of file
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBangBindings.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBangBindings.fs
new file mode 100644
index 00000000000..37c1447e89e
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBangBindings.fs
@@ -0,0 +1,108 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace Language
+
+open FSharp.Test
+open Xunit
+open FSharp.Test.Compiler
+
+module UseBangBindingsVersion9 =
+ []
+ let ``UseBangBindings - UseBang01_fs - Current LangVersion`` compilation =
+ compilation
+ |> asFsx
+ |> withLangVersion90
+ |> typecheck
+ |> shouldFail
+ |> withDiagnostics [
+ (Error 1228, Line 43, Col 14, Line 43, Col 15, "'use!' bindings must be of the form 'use! = '")
+ ]
+
+ []
+ let ``UseBangBindings - UseBang02_fs - Current LangVersion`` compilation =
+ compilation
+ |> asFsx
+ |> withLangVersion90
+ |> typecheck
+ |> shouldFail
+ |> withDiagnostics [
+ (Error 1228, Line 40, Col 14, Line 40, Col 15, "'use!' bindings must be of the form 'use! = '")
+ ]
+
+ []
+ let ``UseBangBindings - UseBang03_fs - Current LangVersion`` compilation =
+ compilation
+ |> asFsx
+ |> withLangVersion90
+ |> typecheck
+ |> shouldFail
+ |> withDiagnostics [
+ (Error 1228, Line 46, Col 14, Line 46, Col 15, "'use!' bindings must be of the form 'use! = '")
+ ]
+
+ []
+ let ``UseBangBindings - UseBang04_fs - Current LangVersion`` compilation =
+ compilation
+ |> asFsx
+ |> withLangVersion90
+ |> typecheck
+ |> shouldFail
+ |> withDiagnostics [
+ (Error 1228, Line 47, Col 14, Line 47, Col 15, "'use!' bindings must be of the form 'use! = '")
+ ]
+
+ []
+ let ``UseBangBindings - UseBang05_fs - Current LangVersion`` compilation =
+ compilation
+ |> asFsx
+ |> withLangVersion90
+ |> typecheck
+ |> shouldFail
+ |> withDiagnostics [
+ (Error 3350, Line 43, Col 14, Line 43, Col 28, "Feature 'Allow let! and use! type annotations without requiring parentheses' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
+ (Error 3350, Line 41, Col 14, Line 41, Col 28, "Feature 'Allow let! and use! type annotations without requiring parentheses' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
+ (Error 3350, Line 40, Col 14, Line 40, Col 29, "Feature 'Allow let! and use! type annotations without requiring parentheses' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
+ ]
+
+module UseBangBindingsPreview =
+ []
+ let ``UseBangBindings - UseBang01_fs - Preview LangVersion`` compilation =
+ compilation
+ |> asExe
+ |> withLangVersionPreview
+ |> compileAndRun
+ |> shouldSucceed
+
+ []
+ let ``UseBangBindings - UseBang02_fs - Preview LangVersion`` compilation =
+ compilation
+ |> asExe
+ |> withLangVersionPreview
+ |> compileAndRun
+ |> shouldSucceed
+
+ []
+ let ``UseBangBindings - UseBang03_fs - Preview LangVersion`` compilation =
+ compilation
+ |> asExe
+ |> withLangVersionPreview
+ |> compileAndRun
+ |> shouldSucceed
+
+ []
+ let ``UseBangBindings - UseBang04_fs - Preview LangVersion`` compilation =
+ compilation
+ |> asExe
+ |> withLangVersionPreview
+ |> compileAndRun
+ |> shouldSucceed
+
+ []
+ let ``UseBangBindings - UseBang05_fs - Preview LangVersion`` compilation =
+ compilation
+ |> asExe
+ |> withLangVersionPreview
+ |> compileAndRun
+ |> shouldSucceed
+
+
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBinding01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBinding01.fs
new file mode 100644
index 00000000000..4fbe7575b3a
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBinding01.fs
@@ -0,0 +1,7 @@
+// #DeclarationElements #LetBindings
+//
+open System
+
+let answer =
+ use x:IDisposable = new System.IO.MemoryStream()
+ 42
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBinding02.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBinding02.fs
new file mode 100644
index 00000000000..be6cf7b8399
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBinding02.fs
@@ -0,0 +1,26 @@
+open System
+
+type private Disposable() =
+ [] static val mutable private disposedTimes: int
+ [] static val mutable private constructedTimes: int
+
+ do Disposable.constructedTimes <- Disposable.constructedTimes + 1
+
+ static member DisposeCallCount() = Disposable.disposedTimes
+ static member ConstructorCallCount() = Disposable.constructedTimes
+
+ interface System.IDisposable with
+ member _.Dispose() =
+ Disposable.disposedTimes <- Disposable.disposedTimes + 1
+
+let _scope =
+ use x: IDisposable = new Disposable()
+ ()
+
+let disposeCalls = Disposable.DisposeCallCount()
+if disposeCalls <> 1 then
+ failwith "was not disposed or disposed too many times"
+
+let ctorCalls = Disposable.ConstructorCallCount()
+if ctorCalls <> 1 then
+ failwithf "unexpected constructor call count: %i" ctorCalls
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindingDiscard02.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindingDiscard02.fs
new file mode 100644
index 00000000000..9a31ba2763b
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindingDiscard02.fs
@@ -0,0 +1,26 @@
+open System
+
+type private Disposable() =
+ [] static val mutable private disposedTimes: int
+ [] static val mutable private constructedTimes: int
+
+ do Disposable.constructedTimes <- Disposable.constructedTimes + 1
+
+ static member DisposeCallCount() = Disposable.disposedTimes
+ static member ConstructorCallCount() = Disposable.constructedTimes
+
+ interface System.IDisposable with
+ member _.Dispose() =
+ Disposable.disposedTimes <- Disposable.disposedTimes + 1
+
+let _scope =
+ use _ = new Disposable()
+ ()
+
+let disposeCalls = Disposable.DisposeCallCount()
+if disposeCalls <> 1 then
+ failwith "was not disposed or disposed too many times"
+
+let ctorCalls = Disposable.ConstructorCallCount()
+if ctorCalls <> 1 then
+ failwithf "unexpected constructor call count: %i" ctorCalls
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindingDiscard03.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindingDiscard03.fs
new file mode 100644
index 00000000000..840870377fe
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindingDiscard03.fs
@@ -0,0 +1,26 @@
+open System
+
+type private Disposable() =
+ [] static val mutable private disposedTimes: int
+ [] static val mutable private constructedTimes: int
+
+ do Disposable.constructedTimes <- Disposable.constructedTimes + 1
+
+ static member DisposeCallCount() = Disposable.disposedTimes
+ static member ConstructorCallCount() = Disposable.constructedTimes
+
+ interface System.IDisposable with
+ member _.Dispose() =
+ Disposable.disposedTimes <- Disposable.disposedTimes + 1
+
+let _scope =
+ use _:IDisposable = new Disposable()
+ ()
+
+let disposeCalls = Disposable.DisposeCallCount()
+if disposeCalls <> 1 then
+ failwith "was not disposed or disposed too many times"
+
+let ctorCalls = Disposable.ConstructorCallCount()
+if ctorCalls <> 1 then
+ failwithf "unexpected constructor call count: %i" ctorCalls
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindings.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindings.fs
index 8196a9fe286..b1e08869312 100644
--- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindings.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindings.fs
@@ -27,36 +27,31 @@ module UseBindings =
|> withErrorCode 3350
|> withDiagnosticMessageMatches "Feature 'discard pattern in use binding' is not available.*"
- []
- let ``Dispose called for discarded value of use binding`` () =
- Fsx """
-type private Disposable() =
- [] static val mutable private disposedTimes: int
- [] static val mutable private constructedTimes: int
-
- do Disposable.constructedTimes <- Disposable.constructedTimes + 1
-
- static member DisposeCallCount() = Disposable.disposedTimes
- static member ConstructorCallCount() = Disposable.constructedTimes
-
- interface System.IDisposable with
- member _.Dispose() =
- Disposable.disposedTimes <- Disposable.disposedTimes + 1
-
-let _scope =
- use _ = new Disposable()
- ()
-
-let disposeCalls = Disposable.DisposeCallCount()
-if disposeCalls <> 1 then
- failwith "was not disposed or disposed too many times"
-
-let ctorCalls = Disposable.ConstructorCallCount()
-if ctorCalls <> 1 then
- failwithf "unexpected constructor call count: %i" ctorCalls
-
- """
+ []
+ let ``Dispose called for discarded value of use binding`` compilation =
+ compilation
|> asExe
|> withLangVersion60
|> compileAndRun
- |> shouldSucceed
\ No newline at end of file
+ |> shouldSucceed
+
+ []
+ let ``UseBindings - UseBindingDiscard03_fs - Current LangVersion`` compilation =
+ compilation
+ |> asExe
+ |> compileAndRun
+ |> shouldSucceed
+
+ []
+ let ``UseBindings - UseBinding01_fs - Current LangVersion`` compilation =
+ compilation
+ |> asFsx
+ |> compile
+ |> shouldSucceed
+
+ []
+ let ``UseBindings - UseBinding02_fs - Current LangVersion`` compilation =
+ compilation
+ |> asFsx
+ |> compile
+ |> shouldSucceed
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs
index 354539ed7c1..ef0b307853a 100644
--- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs
@@ -19,6 +19,138 @@ module AnonRecd =
|> shouldFail
|> withErrorCode 3522
|> withMessage "The field 'A' appears multiple times in this record expression."
+
+ []
+ let ``Anonymous Record with unit of measures`` () =
+ FSharp """
+namespace FSharpTest
+
+[]
+type m
+
+module AnonRecd =
+ let a = {|a=1|}
+ let b = {|a=1; b=2|}
+ let c = {|a=1 |}
+ let d = {| a=1; b=2; c=3 |}
+"""
+ |> compile
+ |> shouldFail
+ |> withDiagnostics [
+ (Error 3350, Line 8, Col 20, Line 8, Col 23, "Feature 'Support for better anonymous record parsing' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
+ (Error 3350, Line 9, Col 28, Line 9, Col 31, "Feature 'Support for better anonymous record parsing' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
+ ]
+
+ []
+ let ``Preview : Anonymous Record with unit of measures`` () =
+ FSharp """
+namespace FSharpTest
+
+[]
+type m
+
+module AnonRecd =
+ let a = {|a=1|}
+ let b = {|a=1; b=2|}
+ let c = {|a=1 |}
+ let d = {| a=1; b=2; c=3 |}
+"""
+ |> withLangVersionPreview
+ |> compile
+ |> shouldSucceed
+
+ []
+ let ``Anonymous Record with typeof`` () =
+ FSharp """
+namespace FSharpTest
+module AnonRecd =
+ let a = {|a=typeof|}
+ let b = {|a=typeof |}
+ let c = {| a=typeof|}
+ let d = {| a=typeof |}
+"""
+ |> compile
+ |> shouldFail
+ |> withDiagnostics [
+ (Error 3350, Line 4, Col 27, Line 4, Col 30, "Feature 'Support for better anonymous record parsing' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
+ (Error 3350, Line 6, Col 28, Line 6, Col 31, "Feature 'Support for better anonymous record parsing' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
+ ]
+
+ []
+ let ``Preview: Anonymous Record with typeof`` () =
+ FSharp """
+namespace FSharpTest
+module AnonRecd =
+ let a = {|a=typeof|}
+ let b = {|a=typeof |}
+ let c = {| a=typeof|}
+ let d = {| a=typeof |}
+"""
+ |> withLangVersionPreview
+ |> compile
+ |> shouldSucceed
+
+ []
+ let ``Anonymous Record with typedefof`` () =
+ FSharp """
+namespace FSharpTest
+module AnonRecd =
+ let a = {|a=typedefof<_ option>|}
+ let b = {|a=typedefof<_ option> |}
+ let c = {| a=typedefof<_ option>|}
+ let d = {| a=typedefof<_ option> |}
+"""
+ |> compile
+ |> shouldFail
+ |> withDiagnostics [
+ (Error 3350, Line 4, Col 35, Line 4, Col 38, "Feature 'Support for better anonymous record parsing' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
+ (Error 3350, Line 6, Col 36, Line 6, Col 39, "Feature 'Support for better anonymous record parsing' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
+ ]
+
+ []
+ let ``Preview: Anonymous Record with typedefof`` () =
+ FSharp """
+namespace FSharpTest
+module AnonRecd =
+ let a = {|a=typedefof<_ option>|}
+ let b = {|a=typedefof<_ option> |}
+ let c = {| a=typedefof<_ option>|}
+ let d = {| a=typedefof<_ option> |}
+"""
+ |> withLangVersionPreview
+ |> compile
+ |> shouldSucceed
+
+ []
+ let ``Anonymous Record with nameof`` () =
+ FSharp """
+namespace FSharpTest
+module AnonRecd =
+ let a<'T> = {|a=nameof<'T>|}
+ let b<'T> = {|a=nameof<'T> |}
+ let c<'T> = {| a=nameof<'T>|}
+ let d<'T> = {| a=nameof<'T> |}
+"""
+ |> compile
+ |> shouldFail
+ |> withDiagnostics [
+ (Error 3350, Line 4, Col 30, Line 4, Col 33, "Feature 'Support for better anonymous record parsing' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
+ (Error 3350, Line 6, Col 31, Line 6, Col 34, "Feature 'Support for better anonymous record parsing' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.")
+ ]
+
+ []
+ let ``Preview: Anonymous Record with nameof`` () =
+ FSharp """
+namespace FSharpTest
+module AnonRecd =
+ let a<'T> = {|a=nameof<'T>|}
+ let b<'T> = {|a=nameof<'T> |}
+ let c<'T> = {| a=nameof<'T>|}
+ let d<'T> = {| a=nameof<'T> |}
+"""
+ |> withLangVersionPreview
+ |> compile
+ |> shouldSucceed
[]
let ``Anonymous Record missing single field`` () =
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic.fs
deleted file mode 100644
index da86f949265..00000000000
--- a/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic.fs
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-
-namespace Conformance.UnitsOfMeasure
-
-open Xunit
-open FSharp.Test
-open FSharp.Test.Compiler
-
-module Basic =
-
- // This test was automatically generated (moved from FSharpQA suite - Conformance/UnitsOfMeasure/Basic)
- []
- let ``Basic - Misc01_fs`` compilation =
- compilation
- |> asFsx
- |> typecheck
- |> shouldSucceed
- |> ignore
-
- // This test was automatically generated (moved from FSharpQA suite - Conformance/UnitsOfMeasure/Basic)
- []
- let ``Basic - Misc03_fs`` compilation =
- compilation
- |> asFsx
- |> typecheck
- |> shouldSucceed
- |> ignore
-
- // This test was automatically generated (moved from FSharpQA suite - Conformance/UnitsOfMeasure/Basic)
- []
- let ``Basic - Stats_fs`` compilation =
- compilation
- |> asFsx
- |> typecheck
- |> shouldSucceed
- |> ignore
-
- // This test was automatically generated (moved from FSharpQA suite - Conformance/UnitsOfMeasure/Basic)
- []
- let ``Basic - SI_fs`` compilation =
- compilation
- |> asFsx
- |> typecheck
- |> shouldSucceed
- |> ignore
-
- // This test was automatically generated (moved from FSharpQA suite - Conformance/UnitsOfMeasure/Basic)
- []
- let ``Basic - RationalExponents01_fs`` compilation =
- compilation
- |> asFsx
- |> typecheck
- |> shouldSucceed
- |> ignore
-
- // This test was automatically generated (moved from FSharpQA suite - Conformance/UnitsOfMeasure/Basic)
- []
- let ``Basic - Quotation04_hidden_fs`` compilation =
- compilation
- |> asFsx
- |> typecheck
- |> shouldSucceed
- |> ignore
-
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Basic.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Basic.fs
new file mode 100644
index 00000000000..ddb3a9fb049
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Basic.fs
@@ -0,0 +1,56 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace Conformance.UnitsOfMeasure
+
+open Xunit
+open FSharp.Test
+open FSharp.Test.Compiler
+
+module Basic =
+ let shouldFailWithDiagnostics expectedDiagnostics compilation =
+ compilation
+ |> asLibrary
+ |> withOptions ["--test:ErrorRanges"]
+ |> typecheck
+ |> shouldFail
+ |> withDiagnostics expectedDiagnostics
+
+ let shouldSucceed compilation =
+ compilation
+ |> asLibrary
+ |> withOptions ["--test:ErrorRanges"]
+ |> typecheck
+ |> shouldSucceed
+
+ []
+ []
+ []
+ []
+ []
+ []
+ []
+ []
+ []
+ []
+ []
+ let ``Basic - shouldSucceed`` compilation =
+ compilation
+ |> getCompilation
+ |> shouldSucceed
+
+ []
+ let ``Basic - E_MassForce`` compilation =
+ compilation
+ |> getCompilation
+ |> shouldFailWithDiagnostics [
+ (Error 1, Line 15, Col 27, Line 15, Col 32, "The unit of measure 'N' does not match the unit of measure 'kg'")
+ (Error 43, Line 15, Col 25, Line 15, Col 26, "The unit of measure 'N' does not match the unit of measure 'kg'")
+ ]
+
+ []
+ let ``Basic - Misc02_fs`` compilation =
+ compilation
+ |> getCompilation
+ |> shouldFailWithDiagnostics [
+ (Warning 64, Line 36, Col 60, Line 36, Col 61, "This construct causes code to be less generic than indicated by the type annotations. The unit-of-measure variable 'v has been constrained to be measure ''u/'w'.")
+ ]
diff --git a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/Calculus.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Calculus.fsx
similarity index 97%
rename from tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/Calculus.fs
rename to tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Calculus.fsx
index 0263135fc55..cd91c9f2d2b 100644
--- a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/Calculus.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Calculus.fsx
@@ -18,6 +18,7 @@ let rec newton (f:float<_> -> float<_>) f' x xacc =
else newton f f' x' xacc
// Non-regular datatype: a list of derivatives of a function
+[]
type derivs<[] 'u, [] 'v> =
Nil
| Cons of (float<'u> -> float<'v>) * derivs<'u,'v/'u>
diff --git a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/DynamicTypeTest.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/DynamicTypeTest.fsx
similarity index 100%
rename from tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/DynamicTypeTest.fs
rename to tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/DynamicTypeTest.fsx
diff --git a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/E_MassForce.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/E_MassForce.fsx
similarity index 100%
rename from tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/E_MassForce.fs
rename to tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/E_MassForce.fsx
diff --git a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/Ints01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Ints01.fsx
similarity index 100%
rename from tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/Ints01.fs
rename to tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Ints01.fsx
diff --git a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/Mars.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Mars.fsx
similarity index 100%
rename from tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/Mars.fs
rename to tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Mars.fsx
diff --git a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/MassForce.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/MassForce.fsx
similarity index 100%
rename from tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/MassForce.fs
rename to tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/MassForce.fsx
diff --git a/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/UnitsOfMeasure/Basic/Misc01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Misc01.fsx
similarity index 100%
rename from tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/UnitsOfMeasure/Basic/Misc01.fs
rename to tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Misc01.fsx
diff --git a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/Misc02.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Misc02.fsx
similarity index 97%
rename from tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/Misc02.fs
rename to tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Misc02.fsx
index 87e1f8d6025..79b036bef91 100644
--- a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Basic/Misc02.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Basic/Misc02.fsx
@@ -94,4 +94,4 @@ let r2 = (polyadd (new ComplexProd()))
let weird(x:float<'u 'w>) (y:float<'v 'w>) (z:float<'w/'u 'v>) = 1
-if (r/1.0