diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644
index 00000000000..9ffc7f9619b
--- /dev/null
+++ b/.devcontainer/Dockerfile
@@ -0,0 +1,40 @@
+#-------------------------------------------------------------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
+#-------------------------------------------------------------------------------------------------------------
+
+FROM mcr.microsoft.com/dotnet/core/sdk:3.1
+
+# Avoid warnings by switching to noninteractive
+ENV DEBIAN_FRONTEND=noninteractive
+
+# This Dockerfile adds a non-root user with sudo access. Use the "remoteUser"
+# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs
+# will be updated to match your local UID/GID (when using the dockerFile property).
+# See https://aka.ms/vscode-remote/containers/non-root-user for details.
+ARG USERNAME=vscode
+ARG USER_UID=1000
+ARG USER_GID=$USER_UID
+
+# Configure apt and install packages
+RUN apt-get update \
+ && apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
+ #
+ # Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
+ && apt-get -y install git openssh-client less iproute2 procps lsb-release \
+ #
+ # Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user.
+ && groupadd --gid $USER_GID $USERNAME \
+ && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
+ # [Optional] Add sudo support for the non-root user
+ && apt-get install -y sudo \
+ && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
+ && chmod 0440 /etc/sudoers.d/$USERNAME \
+ #
+ # Clean up
+ && apt-get autoremove -y \
+ && apt-get clean -y \
+ && rm -rf /var/lib/apt/lists/*
+
+# Switch back to dialog for any ad-hoc use of apt-get
+ENV DEBIAN_FRONTEND=dialog
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 00000000000..970a9ca1c00
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,34 @@
+// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
+// https://github.com/microsoft/vscode-dev-containers/tree/v0.108.0/containers/dotnetcore-3.1-fsharp
+{
+ "name": "F# (.NET Core 3.1)",
+ "dockerFile": "Dockerfile",
+
+ // Set *default* container specific settings.json values on container create.
+ //
+ // .NET Core is now the default for F# in .NET Core 3.0+
+ // However, .NET Core scripting is not the default yet. Set that to true.
+ "settings": {
+ "terminal.integrated.shell.linux": "/bin/bash",
+ "FSharp.useSdkScripts":true,
+ "editor.trimAutoWhitespace": false,
+ "files.trimTrailingWhitespace": false,
+ "FSharp.suggestGitignore": false,
+ "FSharp.workspacePath": "FSharp.sln"
+ },
+
+ // Add the IDs of extensions you want installed when the container is created.
+ "extensions": [
+ "Ionide.Ionide-fsharp",
+ "ms-dotnettools.csharp"
+ ],
+
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ // "forwardPorts": [],
+
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "./build.sh",
+
+ // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
+ // "remoteUser": "vscode"
+}
diff --git a/.gitattributes b/.gitattributes
index f5b288ab2d8..d3a9149263c 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -26,3 +26,5 @@ mono/config.make text eol=lf
targets.make text eol=lf
*.bsl linguist-vendored=true
+
+*.png binary
diff --git a/.gitignore b/.gitignore
index 61e0743599e..563631afb5c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,7 +9,6 @@
# Patches that may have been generated by scripts.
# (These aren't generally useful to commit directly; if anything, they should be applied.)
scripts/*.patch
-
/fcs/FSharp.Compiler.Service/illex.fs
/fcs/FSharp.Compiler.Service/ilpars.fs
/fcs/FSharp.Compiler.Service/ilpars.fsi
@@ -54,6 +53,7 @@ scripts/*.patch
/src/fsharp/FSharp.LanguageService.Compiler/pplex.fs
/src/fsharp/FSharp.LanguageService.Compiler/pppars.fs
/src/fsharp/FSharp.LanguageService.Compiler/pppars.fsi
+/src/fsharp/*/Properties/launchSettings.json
/vsintegration/src/unittests/Unittests.fsi
/tests/*FSharp_Failures.env
/tests/*FSharp_Failures.lst
@@ -119,7 +119,8 @@ source_link.json
.vs/
System.ValueTuple.dll
tests/fsharpqa/testenv/bin/System.ValueTuple.dll
-*/.fake
+**/.fake
+.ionide
/fcs/packages/
*/paket-files/
/fcs/TestResult.xml
@@ -129,3 +130,16 @@ msbuild.binlog
/fcs/FSharp.Compiler.Service.netstandard/*.fs
/fcs/FSharp.Compiler.Service.netstandard/*.fsi
/.ionide/
+**/.DS_Store
+/tests/fsharp/regression/5531/compilation.output.test.txt
+/tests/fsharp/core/fsfromfsviacs/compilation.langversion.old.output.txt
+/tests/fsharp/core/fsfromfsviacs/compilation.errors.output.txt
+*ncrunch*.user
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+.idea
+/tests/fsharp/core/members/set-only-property/vb.dll
+/tests/fsharp/core/members/set-only-property/fs.dll
+/tests/fsharp/core/members/set-only-property/cs.dll
diff --git a/.vscode/launch.json b/.vscode/launch.json
deleted file mode 100644
index 0546015eee9..00000000000
--- a/.vscode/launch.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "version": "0.2.0",
- "configurations": [
- {
- "name": ".NET Core Launch (console)",
- "type": "coreclr",
- "request": "launch",
- "preLaunchTask": "build",
- "program": "${workspaceRoot}/lkg/fsc/bin/Debug/netcoreapp1.0/fsc.dll",
- "args": [],
- "cwd": "${workspaceRoot}",
- "externalConsole": false,
- "stopAtEntry": false,
- "internalConsoleOptions": "openOnSessionStart"
- },
- {
- "name": ".NET Core Attach",
- "type": "coreclr",
- "request": "attach",
- "processId": "${command.pickProcess}"
- }
- ]
-}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000000..d763943d4e5
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,6 @@
+{
+ "editor.trimAutoWhitespace": false,
+ "files.trimTrailingWhitespace": false,
+ "FSharp.suggestGitignore": false,
+ "FSharp.workspacePath": "FSharp.sln"
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
deleted file mode 100644
index 9c103be70d4..00000000000
--- a/.vscode/tasks.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "version": "0.1.0",
- "command": "dotnet",
- "isShellCommand": true,
- "args": [],
- "tasks": [
- {
- "taskName": "build",
- "args": [
- "${workspaceRoot}/lkg/fsc/project.json"
- ],
- "isBuildCommand": true,
- "problemMatcher": "$msCompile"
- }
- ]
-}
\ No newline at end of file
diff --git a/.vsconfig b/.vsconfig
index 302d9808902..f08811fff53 100644
--- a/.vsconfig
+++ b/.vsconfig
@@ -8,8 +8,6 @@
"Microsoft.VisualStudio.Component.Roslyn.Compiler",
"Microsoft.VisualStudio.Component.Roslyn.LanguageServices",
"Microsoft.VisualStudio.Component.FSharp",
- "Microsoft.Net.Core.Component.SDK.2.1",
- "Microsoft.NetCore.ComponentGroup.DevelopmentTools.2.1",
"Microsoft.Net.Component.4.7.2.SDK",
"Microsoft.Net.Component.4.7.2.TargetingPack",
"Microsoft.Net.ComponentGroup.DevelopmentPrerequisites",
diff --git a/.vsts-signed.yaml b/.vsts-signed.yaml
index ed30cb74ef2..a93dcd1af94 100644
--- a/.vsts-signed.yaml
+++ b/.vsts-signed.yaml
@@ -11,117 +11,142 @@ variables:
#- name: SkipTests
# defaultValue: false
-jobs:
-- job: Full_Signed
- pool:
- name: VSEng-MicroBuildVS2019
- timeoutInMinutes: 300
- variables:
- BuildConfiguration: 'Release'
- steps:
-
- # Install Signing Plugin
- - task: ms-vseng.MicroBuildTasks.30666190-6959-11e5-9f96-f56098202fef.MicroBuildSigningPlugin@1
- displayName: Install Signing Plugin
- inputs:
- signType: real
- esrpSigning: true
- condition: and(succeeded(), ne(variables['SignType'], ''))
-
- # Build
- - script: eng\CIBuild.cmd
- -configuration $(BuildConfiguration)
- -testAll
- -officialSkipTests $(SkipTests)
- /p:OfficialBuildId=$(BUILD.BUILDNUMBER)
- /p:VisualStudioDropName=$(VisualStudioDropName)
- /p:DotNetSignType=$(SignType)
- /p:DotNetPublishToBlobFeed=true
- /p:DotNetPublishBlobFeedKey=$(dotnetfeed-storage-access-key-1)
- /p:DotNetPublishBlobFeedUrl=https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json
- /p:PublishToSymbolServer=true
- /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
- /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
- displayName: Build
-
- # Publish logs
- - task: PublishBuildArtifacts@1
- displayName: Publish Logs
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)\artifacts\log\$(BuildConfiguration)'
- ArtifactName: 'Build Diagnostic Files'
- publishLocation: Container
- continueOnError: true
- condition: succeededOrFailed()
-
- # Publish test results
- - task: PublishBuildArtifacts@1
- displayName: Publish Test Results
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)\artifacts\TestResults'
- ArtifactName: 'Test Results'
- publishLocation: Container
- continueOnError: true
- condition: and(succeededOrFailed(), ne(variables['SkipTests'], 'true'))
-
- # Upload VSTS Drop
- - task: ms-vseng.MicroBuildTasks.4305a8de-ba66-4d8b-b2d1-0dc4ecbbf5e8.MicroBuildUploadVstsDropFolder@1
- displayName: Upload VSTS Drop
- inputs:
- DropName: $(VisualStudioDropName)
- DropFolder: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(BuildConfiguration)\Insertion'
- condition: succeeded()
-
- # Publish an artifact that the RoslynInsertionTool is able to find by its name.
- - task: PublishBuildArtifacts@1
- displayName: Publish Artifact VSSetup
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(BuildConfiguration)\Insertion'
- ArtifactName: 'VSSetup'
- condition: succeeded()
-
- # Archive NuGet packages to DevOps.
- - task: PublishBuildArtifacts@1
- displayName: Publish Artifact Packages
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)\artifacts\packages\$(BuildConfiguration)'
- ArtifactName: 'Packages'
- condition: succeeded()
-
- # Publish nightly package to ADO
- - task: PublishBuildArtifacts@1
- displayName: Publish Artifact Nightly
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(BuildConfiguration)\VisualFSharpFull.vsix'
- ArtifactName: 'Nightly'
- condition: succeeded()
-
- # Package publish
- - task: PublishBuildArtifacts@1
- displayName: Push Asset Manifests
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)/AssetManifest'
- ArtifactName: AssetManifests
- continueOnError: true
- condition: succeeded()
-
- # Publish native PDBs for archiving
- - task: PublishBuildArtifacts@1
- displayName: Publish Artifact Symbols
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)/artifacts/SymStore/$(BuildConfiguration)'
- ArtifactName: NativeSymbols
- condition: succeeded()
-
- # Execute cleanup tasks
- - task: ms-vseng.MicroBuildTasks.521a94ea-9e68-468a-8167-6dcf361ea776.MicroBuildCleanup@1
- displayName: Execute cleanup tasks
- condition: succeededOrFailed()
-
-- template: /eng/common/templates/job/publish-build-assets.yml
- parameters:
- dependsOn:
- - Full_Signed
+stages:
+- stage: build
+ displayName: Build
+
+ jobs:
+ - job: Full_Signed
pool:
- vmImage: windows-2019
- enablePublishBuildArtifacts: true
+ name: VSEng-MicroBuildVS2019
+ timeoutInMinutes: 300
+ variables:
+ BuildConfiguration: 'Release'
+ steps:
+
+ # Install Signing Plugin
+ - task: ms-vseng.MicroBuildTasks.30666190-6959-11e5-9f96-f56098202fef.MicroBuildSigningPlugin@1
+ displayName: Install Signing Plugin
+ inputs:
+ signType: real
+ esrpSigning: true
+ condition: and(succeeded(), ne(variables['SignType'], ''))
+
+ # Build
+ - script: eng\CIBuild.cmd
+ -configuration $(BuildConfiguration)
+ -testAll
+ -officialSkipTests $(SkipTests)
+ /p:OfficialBuildId=$(BUILD.BUILDNUMBER)
+ /p:VisualStudioDropName=$(VisualStudioDropName)
+ /p:DotNetSignType=$(SignType)
+ /p:DotNetPublishToBlobFeed=true
+ /p:DotNetPublishBlobFeedKey=$(dotnetfeed-storage-access-key-1)
+ /p:DotNetPublishBlobFeedUrl=https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json
+ /p:PublishToSymbolServer=true
+ /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
+ /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
+ displayName: Build
+
+ # Publish logs
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Logs
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\log\$(BuildConfiguration)'
+ ArtifactName: 'Build Diagnostic Files'
+ publishLocation: Container
+ continueOnError: true
+ condition: succeededOrFailed()
+
+ # Publish test results
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Test Results
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\TestResults'
+ ArtifactName: 'Test Results'
+ publishLocation: Container
+ continueOnError: true
+ condition: and(succeededOrFailed(), ne(variables['SkipTests'], 'true'))
+
+ # Upload VSTS Drop
+ - task: ms-vseng.MicroBuildTasks.4305a8de-ba66-4d8b-b2d1-0dc4ecbbf5e8.MicroBuildUploadVstsDropFolder@1
+ displayName: Upload VSTS Drop
+ inputs:
+ DropName: $(VisualStudioDropName)
+ DropFolder: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(BuildConfiguration)\Insertion'
+ condition: succeeded()
+
+ # Publish an artifact that the RoslynInsertionTool is able to find by its name.
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Artifact VSSetup
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(BuildConfiguration)\Insertion'
+ ArtifactName: 'VSSetup'
+ condition: succeeded()
+
+ # Archive NuGet packages to DevOps.
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Artifact Packages
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\packages\$(BuildConfiguration)'
+ ArtifactName: 'Packages'
+ condition: succeeded()
+
+ # Publish nightly package to ADO
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Artifact Nightly
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(BuildConfiguration)\VisualFSharpFull.vsix'
+ ArtifactName: 'Nightly'
+ condition: succeeded()
+
+ # Package publish
+ - task: PublishBuildArtifacts@1
+ displayName: Push Asset Manifests
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)/AssetManifest'
+ ArtifactName: AssetManifests
+ continueOnError: true
+ condition: succeeded()
+
+ # Publish PackageArtifacts for Arcade verification
+ - task: PublishBuildArtifacts@1
+ displayName: Publish PackageArtifacts
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\packages\$(BuildConfiguration)\Shipping'
+ ArtifactName: 'PackageArtifacts'
+ condition: succeeded()
+
+ # Publish BlobArtifacts for Arcade verification
+ - task: PublishBuildArtifacts@1
+ displayName: Publish BlobArtifacts
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\packages\$(BuildConfiguration)\Shipping'
+ ArtifactName: 'BlobArtifacts'
+ condition: succeeded()
+
+ # Publish native PDBs for archiving
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Artifact Symbols
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/artifacts/SymStore/$(BuildConfiguration)'
+ ArtifactName: NativeSymbols
+ condition: succeeded()
+
+ # Execute cleanup tasks
+ - task: ms-vseng.MicroBuildTasks.521a94ea-9e68-468a-8167-6dcf361ea776.MicroBuildCleanup@1
+ displayName: Execute cleanup tasks
+ condition: succeededOrFailed()
+
+ - template: /eng/common/templates/job/publish-build-assets.yml
+ parameters:
+ dependsOn:
+ - Full_Signed
+ pool:
+ vmImage: windows-2019
+ enablePublishBuildArtifacts: true
+
+- template: eng/common/templates/post-build/post-build.yml
+ parameters:
+ # Symbol validation is not entirely reliable as of yet, so should be turned off until https://github.com/dotnet/arcade/issues/2871 is resolved.
+ enableSymbolValidation: false
diff --git a/Build.cmd b/Build.cmd
index ad55484933d..e092641b8e2 100644
--- a/Build.cmd
+++ b/Build.cmd
@@ -1,2 +1,2 @@
-@echo off
+@echo off
powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0eng\build.ps1""" -build -restore %*"
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 1c658245edb..775f221c98e 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -1,46 +1,6 @@
-# Contributor Covenant Code of Conduct
+# Code of Conduct
-## Our Pledge
+This project has adopted the code of conduct defined by the Contributor Covenant
+to clarify expected behavior in our community.
-In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
-
-## Our Standards
-
-Examples of behavior that contributes to creating a positive environment include:
-
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery and unwelcome sexual attention or advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or electronic address, without explicit permission
-* Other conduct which could reasonably be considered inappropriate in a professional setting
-
-## Our Responsibilities
-
-Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
-
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
-
-## Scope
-
-This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
-
-## Enforcement
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at opensource@microsoft.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
-
-Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
-
-## Attribution
-
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version]
-
-[homepage]: https://contributor-covenant.org
-[version]: https://contributor-covenant.org/version/1/4/
+For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
diff --git a/DEVGUIDE.md b/DEVGUIDE.md
index 79468cdd556..cc8c7e84a6e 100644
--- a/DEVGUIDE.md
+++ b/DEVGUIDE.md
@@ -10,6 +10,11 @@ We recommend the following overall workflow when developing for this repository:
* Always work in your fork
* Always keep your fork up to date
+Before updating your fork, run this command:
+```
+git remote add upstream https://github.com/dotnet/fsharp.git
+```
+
This will make management of multiple forks and your own work easier over time.
## Updating your fork
@@ -17,35 +22,37 @@ This will make management of multiple forks and your own work easier over time.
We recommend the following commands to update your fork:
```
-git checkout master
+git checkout main
git clean -xdf
git fetch upstream
-git rebase upstream/master
+git rebase upstream/main
git push
```
Or more succinctly:
```
-git checkout master && git clean -xdf && git fetch upstream && git rebase upstream/master && git push
+git checkout main && git clean -xdf && git fetch upstream && git rebase upstream/main && git push
```
This will update your fork with the latest from `dotnet/fsharp` on your machine and push those updates to your remote fork.
## Developing on Windows
-Install the latest released [Visual Studio](https://www.visualstudio.com/downloads/), as that is what the `master` branch's tools are synced with. Select the following workloads:
+Install the latest released [Visual Studio](https://www.visualstudio.com/downloads/), as that is what the `main` branch's tools are synced with. Select the following workloads:
* .NET desktop development (also check F# desktop support, as this will install some legacy templates)
* Visual Studio extension development
+You will also need the latest .NET 5 SDK installed from [here](https://dotnet.microsoft.com/download/dotnet/5.0).
+
Building is simple:
build.cmd
Desktop tests can be run with:
- build.cmd -test
+ build.cmd -test -c Release
After you build the first time you can open and use this solution in Visual Studio:
@@ -55,16 +62,6 @@ If you don't have everything installed yet, you'll get prompted by Visual Studio
If you are just developing the core compiler and library then building ``FSharp.sln`` will be enough.
-### Developing the F# Compiler (Linux/macOS)
-
-For Linux/Mac:
-
- ./build.sh
-
-Running tests:
-
- ./build.sh --test
-
We recommend installing the latest released Visual Studio and using that if you are on Windows. However, if you prefer not to do that, you will need to install the following:
* [.NET Framework 4.7.2](https://dotnet.microsoft.com/download/dotnet-framework/net472)
@@ -90,15 +87,19 @@ You can then open `FSharp.sln` in your editor of choice.
## Testing from the command line
-You can find all test options as separate flags. For example:
+You can find all test options as separate flags. For example `build -testAll`:
```
-build -testDesktop -- test all net472 target frameworks
-build -testCoreClr -- test all netstandard and netcoreapp target frameworks
-build -testFSharpQA -- test all F# Cambridge tests
-build -testVs -- test all VS integration points
-build -testFcs -- test F# compiler service components
-build -testAll -- all of the above
+ -testAll Run all tests
+ -testCambridge Run Cambridge tests
+ -testCompiler Run FSharpCompiler unit tests
+ -testCompilerService Run FSharpCompilerService unit tests
+ -testDesktop Run tests against full .NET Framework
+ -testCoreClr Run tests against CoreCLR
+ -testFSharpCore Run FSharpCore unit tests
+ -testFSharpQA Run F# Cambridge tests
+ -testScripting Run Scripting tests
+ -testVs Run F# editor unit tests
```
Running any of the above will build the latest changes and run tests against them.
@@ -138,7 +139,7 @@ VSIXInstaller.exe /u:"VisualFSharp"
VSIXInstaller.exe artifacts\VSSetup\Release\VisualFSharpFull.vsix
```
-It's important to use `Release` if you want to see if your changes have had a noticable performance impact.
+It's important to use `Release` if you want to see if your changes have had a noticeable performance impact.
### Performance and debugging
diff --git a/FSharp.Compiler.Service.sln b/FSharp.Compiler.Service.sln
new file mode 100644
index 00000000000..0f0d871b018
--- /dev/null
+++ b/FSharp.Compiler.Service.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30503.244
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Service", "src\fsharp\FSharp.Compiler.Service\FSharp.Compiler.Service.fsproj", "{A59DB8AE-8044-41A5-848A-800A7FF31C93}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.Service.Tests", "tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj", "{8D9C9683-5041-48AB-8FA9-0939D2D27D33}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.DependencyManager.Nuget", "src\fsharp\FSharp.DependencyManager.Nuget\FSharp.DependencyManager.Nuget.fsproj", "{98E7659D-8E0C-489F-B4F5-E12AFC0D1BFA}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A59DB8AE-8044-41A5-848A-800A7FF31C93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A59DB8AE-8044-41A5-848A-800A7FF31C93}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A59DB8AE-8044-41A5-848A-800A7FF31C93}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A59DB8AE-8044-41A5-848A-800A7FF31C93}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8D9C9683-5041-48AB-8FA9-0939D2D27D33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8D9C9683-5041-48AB-8FA9-0939D2D27D33}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8D9C9683-5041-48AB-8FA9-0939D2D27D33}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8D9C9683-5041-48AB-8FA9-0939D2D27D33}.Release|Any CPU.Build.0 = Release|Any CPU
+ {98E7659D-8E0C-489F-B4F5-E12AFC0D1BFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {98E7659D-8E0C-489F-B4F5-E12AFC0D1BFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {98E7659D-8E0C-489F-B4F5-E12AFC0D1BFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {98E7659D-8E0C-489F-B4F5-E12AFC0D1BFA}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {F9A60F3B-D894-4C8E-BA0F-C51115B25A5A}
+ EndGlobalSection
+EndGlobal
diff --git a/FSharp.Profiles.props b/FSharp.Profiles.props
index 6b473ce7eea..993512bde43 100644
--- a/FSharp.Profiles.props
+++ b/FSharp.Profiles.props
@@ -2,27 +2,29 @@
-
- $(DefineConstants);CROSS_PLATFORM_COMPILER
- $(DefineConstants);ENABLE_MONO_SUPPORT
- $(DefineConstants);FX_LCIDFROMCODEPAGE
-
-
-
- $(DefineConstants);NETSTANDARD
- $(DefineConstants);FX_NO_APP_DOMAINS
- $(DefineConstants);FX_NO_CORHOST_SIGNER
- $(DefineConstants);FX_NO_LINKEDRESOURCES
- $(DefineConstants);FX_NO_PDB_READER
- $(DefineConstants);FX_NO_PDB_WRITER
- $(DefineConstants);FX_NO_SYMBOLSTORE
- $(DefineConstants);FX_NO_SYSTEM_CONFIGURATION
- $(DefineConstants);FX_NO_WIN_REGISTRY
- $(DefineConstants);FX_NO_WINFORMS
- $(DefineConstants);FX_NO_INDENTED_TEXT_WRITER
- $(DefineConstants);FX_RESHAPED_REFEMIT
- $(DefineConstants);FX_RESHAPED_MSBUILD
- $(OtherFlags) --simpleresolution
-
+
+
+
+ $(DefineConstants);CROSS_PLATFORM_COMPILER
+ $(DefineConstants);ENABLE_MONO_SUPPORT
+
+
+
+
+ $(DefineConstants);NETSTANDARD
+ $(DefineConstants);FX_NO_APP_DOMAINS
+ $(DefineConstants);FX_NO_CORHOST_SIGNER
+ $(DefineConstants);FX_NO_PDB_READER
+ $(DefineConstants);FX_NO_PDB_WRITER
+ $(DefineConstants);FX_NO_SYMBOLSTORE
+ $(DefineConstants);FX_NO_SYSTEM_CONFIGURATION
+ $(DefineConstants);FX_NO_WIN_REGISTRY
+ $(DefineConstants);FX_NO_WINFORMS
+ $(DefineConstants);FX_NO_INDENTED_TEXT_WRITER
+ $(DefineConstants);FX_RESHAPED_REFEMIT
+ $(OtherFlags) --simpleresolution
+
+
+
diff --git a/FSharp.sln b/FSharp.sln
index e1c47795e8d..210dac21ef6 100644
--- a/FSharp.sln
+++ b/FSharp.sln
@@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.28729.10
MinimumVisualStudioVersion = 10.0.40219.1
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Private", "src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj", "{2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}"
EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Server.Shared", "src\fsharp\FSharp.Compiler.Server.Shared\FSharp.Compiler.Server.Shared.fsproj", "{D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}"
+EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Core", "src\fsharp\FSharp.Core\FSharp.Core.fsproj", "{DED3BBD7-53F4-428A-8C9F-27968E768605}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}"
@@ -17,6 +19,13 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Interactive
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "fsi", "src\fsharp\fsi\fsi.fsproj", "{D0E98C0D-490B-4C61-9329-0862F6E87645}"
EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "fsiAnyCpu", "src\fsharp\fsiAnyCpu\fsiAnyCpu.fsproj", "{8B3E283D-B5FE-4055-9D80-7E3A32F3967B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {649FA588-F02E-457C-9FCF-87E46407481E} = {649FA588-F02E-457C-9FCF-87E46407481E}
+ EndProjectSection
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Test.Utilities", "tests\FSharp.Test.Utilities\FSharp.Test.Utilities.fsproj", "{60D275B0-B14A-41CB-A1B2-E815A7448FCB}"
+EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharpSuite.Tests", "tests\fsharp\FSharpSuite.Tests.fsproj", "{C163E892-5BF7-4B59-AA99-B0E8079C67C4}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.UnitTests", "tests\FSharp.Compiler.UnitTests\FSharp.Compiler.UnitTests.fsproj", "{A8D9641A-9170-4CF4-8FE0-6DB8C134E1B5}"
@@ -33,11 +42,29 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Build.UnitTests", "t
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Packages", "Packages", "{3840F2E7-3898-45F7-8CF7-1E6829E56DB8}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.FSharp.Compiler", "src\fsharp\FSharp.Compiler.nuget\Microsoft.FSharp.Compiler.csproj", "{81B9FE26-C976-4FC7-B6CC-C7DB5903CAA7}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.FSharp.Compiler", "src\fsharp\Microsoft.FSharp.Compiler\Microsoft.FSharp.Compiler.csproj", "{81B9FE26-C976-4FC7-B6CC-C7DB5903CAA7}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.DependencyManager.Nuget", "src\fsharp\FSharp.DependencyManager.Nuget\FSharp.DependencyManager.Nuget.fsproj", "{8B7BF62E-7D8C-4928-BE40-4E392A9EE851}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Private.Scripting", "src\fsharp\FSharp.Compiler.Private.Scripting\FSharp.Compiler.Private.Scripting.fsproj", "{6771860A-614D-4FDD-A655-4C70EBCC91B0}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Private.Scripting.UnitTests", "tests\FSharp.Compiler.Private.Scripting.UnitTests\FSharp.Compiler.Private.Scripting.UnitTests.fsproj", "{4FEDF286-0252-4EBC-9E75-879CCA3B85DC}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Microsoft.DotNet.DependencyManager", "src\fsharp\Microsoft.DotNet.DependencyManager\Microsoft.DotNet.DependencyManager.fsproj", "{B5A043F8-6D7F-4D4E-B8AD-5880070180B6}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.ComponentTests", "tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj", "{FAC5A3BF-C0D6-437A-868A-E962AA00B418}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fsharpqa", "fsharpqa", "{292C4F92-A313-4CAF-9552-731F39C6C21F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testenv", "testenv", "{FF76050A-415A-4FB4-A0E5-13CBF38D83E0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{07482B5E-4980-4285-B732-820F15870284}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PEVerify", "tests\fsharpqa\testenv\src\PEVerify\PEVerify.csproj", "{25568CD2-E654-4C8F-BE5B-59BABFC5BD20}"
EndProject
-Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.LanguageServer", "src\fsharp\FSharp.Compiler.LanguageServer\FSharp.Compiler.LanguageServer.fsproj", "{99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}"
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Service.Tests", "tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj", "{DDFD06DC-D7F2-417F-9177-107764EEBCD8}"
EndProject
-Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.LanguageServer.UnitTests", "tests\FSharp.Compiler.LanguageServer.UnitTests\FSharp.Compiler.LanguageServer.UnitTests.fsproj", "{C97819B0-B428-4B96-9CD7-497D2D1C738C}"
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Service", "src\fsharp\FSharp.Compiler.Service\FSharp.Compiler.Service.fsproj", "{9B4CF83C-C215-4EA0-9F8B-B5A77090F634}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -61,6 +88,18 @@ Global
{2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Release|Any CPU.Build.0 = Release|Any CPU
{2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Release|x86.ActiveCfg = Release|Any CPU
{2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Release|x86.Build.0 = Release|Any CPU
+ {D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Debug|x86.Build.0 = Debug|Any CPU
+ {D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Proto|Any CPU.ActiveCfg = Release|Any CPU
+ {D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Proto|Any CPU.Build.0 = Release|Any CPU
+ {D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Proto|x86.ActiveCfg = Release|Any CPU
+ {D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Proto|x86.Build.0 = Release|Any CPU
+ {D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Release|x86.ActiveCfg = Release|Any CPU
+ {D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Release|x86.Build.0 = Release|Any CPU
{DED3BBD7-53F4-428A-8C9F-27968E768605}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DED3BBD7-53F4-428A-8C9F-27968E768605}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DED3BBD7-53F4-428A-8C9F-27968E768605}.Debug|x86.ActiveCfg = Debug|Any CPU
@@ -121,6 +160,30 @@ Global
{D0E98C0D-490B-4C61-9329-0862F6E87645}.Release|Any CPU.Build.0 = Release|Any CPU
{D0E98C0D-490B-4C61-9329-0862F6E87645}.Release|x86.ActiveCfg = Release|Any CPU
{D0E98C0D-490B-4C61-9329-0862F6E87645}.Release|x86.Build.0 = Release|Any CPU
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B}.Debug|x86.Build.0 = Debug|Any CPU
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B}.Proto|Any CPU.ActiveCfg = Release|Any CPU
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B}.Proto|Any CPU.Build.0 = Release|Any CPU
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B}.Proto|x86.ActiveCfg = Release|Any CPU
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B}.Proto|x86.Build.0 = Release|Any CPU
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B}.Release|x86.ActiveCfg = Release|Any CPU
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B}.Release|x86.Build.0 = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Debug|x86.Build.0 = Debug|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Proto|Any CPU.ActiveCfg = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Proto|Any CPU.Build.0 = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Proto|x86.ActiveCfg = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Proto|x86.Build.0 = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Release|x86.ActiveCfg = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Release|x86.Build.0 = Release|Any CPU
{C163E892-5BF7-4B59-AA99-B0E8079C67C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C163E892-5BF7-4B59-AA99-B0E8079C67C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C163E892-5BF7-4B59-AA99-B0E8079C67C4}.Debug|x86.ActiveCfg = Debug|Any CPU
@@ -181,30 +244,102 @@ Global
{81B9FE26-C976-4FC7-B6CC-C7DB5903CAA7}.Release|Any CPU.Build.0 = Release|Any CPU
{81B9FE26-C976-4FC7-B6CC-C7DB5903CAA7}.Release|x86.ActiveCfg = Release|Any CPU
{81B9FE26-C976-4FC7-B6CC-C7DB5903CAA7}.Release|x86.Build.0 = Release|Any CPU
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}.Debug|x86.ActiveCfg = Debug|Any CPU
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}.Debug|x86.Build.0 = Debug|Any CPU
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}.Proto|Any CPU.Build.0 = Debug|Any CPU
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}.Proto|x86.ActiveCfg = Debug|Any CPU
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}.Proto|x86.Build.0 = Debug|Any CPU
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}.Release|Any CPU.Build.0 = Release|Any CPU
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}.Release|x86.ActiveCfg = Release|Any CPU
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA}.Release|x86.Build.0 = Release|Any CPU
- {C97819B0-B428-4B96-9CD7-497D2D1C738C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C97819B0-B428-4B96-9CD7-497D2D1C738C}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C97819B0-B428-4B96-9CD7-497D2D1C738C}.Debug|x86.ActiveCfg = Debug|Any CPU
- {C97819B0-B428-4B96-9CD7-497D2D1C738C}.Debug|x86.Build.0 = Debug|Any CPU
- {C97819B0-B428-4B96-9CD7-497D2D1C738C}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
- {C97819B0-B428-4B96-9CD7-497D2D1C738C}.Proto|Any CPU.Build.0 = Debug|Any CPU
- {C97819B0-B428-4B96-9CD7-497D2D1C738C}.Proto|x86.ActiveCfg = Debug|Any CPU
- {C97819B0-B428-4B96-9CD7-497D2D1C738C}.Proto|x86.Build.0 = Debug|Any CPU
- {C97819B0-B428-4B96-9CD7-497D2D1C738C}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C97819B0-B428-4B96-9CD7-497D2D1C738C}.Release|Any CPU.Build.0 = Release|Any CPU
- {C97819B0-B428-4B96-9CD7-497D2D1C738C}.Release|x86.ActiveCfg = Release|Any CPU
- {C97819B0-B428-4B96-9CD7-497D2D1C738C}.Release|x86.Build.0 = Release|Any CPU
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851}.Debug|x86.Build.0 = Debug|Any CPU
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851}.Proto|Any CPU.ActiveCfg = Release|Any CPU
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851}.Proto|Any CPU.Build.0 = Release|Any CPU
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851}.Proto|x86.ActiveCfg = Release|Any CPU
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851}.Proto|x86.Build.0 = Release|Any CPU
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851}.Release|x86.ActiveCfg = Release|Any CPU
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851}.Release|x86.Build.0 = Release|Any CPU
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0}.Debug|x86.Build.0 = Debug|Any CPU
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0}.Proto|x86.Build.0 = Debug|Any CPU
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0}.Release|x86.ActiveCfg = Release|Any CPU
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0}.Release|x86.Build.0 = Release|Any CPU
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC}.Debug|x86.Build.0 = Debug|Any CPU
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC}.Proto|x86.Build.0 = Debug|Any CPU
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC}.Release|x86.ActiveCfg = Release|Any CPU
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC}.Release|x86.Build.0 = Release|Any CPU
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6}.Debug|x86.Build.0 = Debug|Any CPU
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6}.Proto|x86.Build.0 = Debug|Any CPU
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6}.Release|x86.ActiveCfg = Release|Any CPU
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6}.Release|x86.Build.0 = Release|Any CPU
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418}.Debug|x86.Build.0 = Debug|Any CPU
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418}.Proto|x86.Build.0 = Debug|Any CPU
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418}.Release|x86.ActiveCfg = Release|Any CPU
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418}.Release|x86.Build.0 = Release|Any CPU
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20}.Debug|x86.Build.0 = Debug|Any CPU
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20}.Proto|x86.Build.0 = Debug|Any CPU
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20}.Release|Any CPU.Build.0 = Release|Any CPU
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20}.Release|x86.ActiveCfg = Release|Any CPU
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20}.Release|x86.Build.0 = Release|Any CPU
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8}.Debug|x86.Build.0 = Debug|Any CPU
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8}.Proto|x86.Build.0 = Debug|Any CPU
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8}.Release|x86.ActiveCfg = Release|Any CPU
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8}.Release|x86.Build.0 = Release|Any CPU
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634}.Debug|x86.Build.0 = Debug|Any CPU
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634}.Proto|x86.Build.0 = Debug|Any CPU
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634}.Release|x86.ActiveCfg = Release|Any CPU
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -216,13 +351,24 @@ Global
{C94C257C-3C0A-4858-B5D8-D746498D1F08} = {3881429D-A97A-49EB-B7AE-A82BA5FE9C77}
{649FA588-F02E-457C-9FCF-87E46407481E} = {B8DDA694-7939-42E3-95E5-265C2217C142}
{D0E98C0D-490B-4C61-9329-0862F6E87645} = {B8DDA694-7939-42E3-95E5-265C2217C142}
+ {8B3E283D-B5FE-4055-9D80-7E3A32F3967B} = {B8DDA694-7939-42E3-95E5-265C2217C142}
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
{C163E892-5BF7-4B59-AA99-B0E8079C67C4} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
{A8D9641A-9170-4CF4-8FE0-6DB8C134E1B5} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
{88E2D422-6852-46E3-A740-83E391DC7973} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
{53C0DAAD-158C-4658-8EC7-D7341530239F} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
{81B9FE26-C976-4FC7-B6CC-C7DB5903CAA7} = {3840F2E7-3898-45F7-8CF7-1E6829E56DB8}
- {99B3F4A5-80B4-41D9-A073-117DB6D7DBBA} = {B8DDA694-7939-42E3-95E5-265C2217C142}
- {C97819B0-B428-4B96-9CD7-497D2D1C738C} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
+ {8B7BF62E-7D8C-4928-BE40-4E392A9EE851} = {3881429D-A97A-49EB-B7AE-A82BA5FE9C77}
+ {6771860A-614D-4FDD-A655-4C70EBCC91B0} = {B8DDA694-7939-42E3-95E5-265C2217C142}
+ {4FEDF286-0252-4EBC-9E75-879CCA3B85DC} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
+ {B5A043F8-6D7F-4D4E-B8AD-5880070180B6} = {3881429D-A97A-49EB-B7AE-A82BA5FE9C77}
+ {FAC5A3BF-C0D6-437A-868A-E962AA00B418} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
+ {292C4F92-A313-4CAF-9552-731F39C6C21F} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
+ {FF76050A-415A-4FB4-A0E5-13CBF38D83E0} = {292C4F92-A313-4CAF-9552-731F39C6C21F}
+ {07482B5E-4980-4285-B732-820F15870284} = {FF76050A-415A-4FB4-A0E5-13CBF38D83E0}
+ {25568CD2-E654-4C8F-BE5B-59BABFC5BD20} = {07482B5E-4980-4285-B732-820F15870284}
+ {DDFD06DC-D7F2-417F-9177-107764EEBCD8} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
+ {9B4CF83C-C215-4EA0-9F8B-B5A77090F634} = {3058BC79-8E79-4645-B05D-48CC182FA8A6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BD5177C7-1380-40E7-94D2-7768E1A8B1B8}
diff --git a/FSharpTests.Directory.Build.props b/FSharpTests.Directory.Build.props
index 8a7a832a43e..098235215c1 100644
--- a/FSharpTests.Directory.Build.props
+++ b/FSharpTests.Directory.Build.props
@@ -22,18 +22,18 @@
$([System.IO.Path]::GetDirectoryName('$(DOTNET_HOST_PATH)'))
dotnet.exe
dotnet
- $(MSBuildThisFileDirectory)artifacts\bin\fsc\$(Configuration)\netcoreapp2.1\fsc.exe
+ $(MSBuildThisFileDirectory)artifacts\bin\fsc\$(Configuration)\netcoreapp3.1\fsc.dll
$([System.IO.Path]::GetDirectoryName('$(DOTNET_HOST_PATH)'))
dotnet.exe
dotnet
- $(MSBuildThisFileDirectory)artifacts\bin\fsi\$(Configuration)\netcoreapp2.1\fsi.exe
+ $(MSBuildThisFileDirectory)artifacts\bin\fsi\$(Configuration)\netcoreapp3.1\fsi.dll
<_FSharpBuildTargetFramework Condition="'$(MSBuildRuntimeType)'!='Core'">net472
- <_FSharpBuildTargetFramework Condition="'$(MSBuildRuntimeType)'=='Core'">netcoreapp2.1
+ <_FSharpBuildTargetFramework Condition="'$(MSBuildRuntimeType)'=='Core'">netcoreapp3.1
<_FSharpBuildBinPath>$(MSBuildThisFileDirectory)artifacts\bin\fsc\$(Configuration)\$(_FSharpBuildTargetFramework)
$(_FSharpBuildBinPath)\FSharp.Build.dll
diff --git a/FSharpTests.Directory.Build.targets b/FSharpTests.Directory.Build.targets
index 8ae8c562556..075321e3fb5 100644
--- a/FSharpTests.Directory.Build.targets
+++ b/FSharpTests.Directory.Build.targets
@@ -1,6 +1,6 @@
-
+
-
- <_CoreCompileResourceInputs Remove="@(_CoreCompileResourceInputs)" />
-
-
+
+ <_CoreCompileResourceInputs Remove="@(_CoreCompileResourceInputs)" />
+
+
+
diff --git a/INTERNAL.md b/INTERNAL.md
new file mode 100644
index 00000000000..2d91080f4a6
--- /dev/null
+++ b/INTERNAL.md
@@ -0,0 +1,81 @@
+# Links for internal team members to find build definitions, etc.
+
+Note that usually only the most recent link in each section is interesting. Older links are included for reference only.
+
+## PR Build Definition
+
+The PR build definition can be found [here](https://dev.azure.com/dnceng/public/_build?definitionId=496) or by
+navigating through an existing PR.
+
+## Signed Build Definitions
+
+[VS 16.4 to current](https://dev.azure.com/dnceng/internal/_build?definitionId=499&_a=summary)
+
+[VS 15.7 to 16.3](https://dev.azure.com/devdiv/DevDiv/_build/index?definitionId=8978)
+
+[VS 15.6](https://dev.azure.com/devdiv/DevDiv/_build?definitionId=7239)
+
+[VS 15.0 to 15.5](https://dev.azure.com/devdiv/DevDiv/_build?definitionId=5037)
+
+## Branch auto-merge definitions
+
+Branch auto-merge definitions are specified [here](https://github.com/dotnet/roslyn-tools/blob/master/src/GitHubCreateMergePRs/config.xml).
+
+## VS Insertion Generators
+
+VS 16.4 to current - part of the build definition. [See below](#vs-insertions-as-part-of-the-build-definition).
+
+The following insertion generators are automatically invoked upon successful completion of a signed build in each of
+their respective branches.
+
+[VS 16.3](https://dev.azure.com/devdiv/DevDiv/_release?definitionId=1839&_a=releases)
+
+[VS 16.2](https://dev.azure.com/devdiv/DevDiv/_release?definitionId=1699&_a=releases)
+
+[VS 16.1](https://dev.azure.com/devdiv/DevDiv/_release?definitionId=1669&_a=releases)
+
+VS 16.0 and prior were done manually
+
+## VS Insertions as part of the build definition
+
+Starting with the 16.4 release and moving forwards, the VS insertion is generated as part of the build. The relevant
+bits can be found near the bottom of [`azure-pipelines.yml`](azure-pipelines.yml) under the `VS Insertion` header. The
+interesting parameters are `componentBranchName` and `insertTargetBranch`. In short, when an internal signed build
+completes and the name of the branch built exactly equals the value in the `componentBranchName` parameter, a component
+insertion into VS will be created into the `insertTargetBranch` branch. The link to the insertion PR will be found
+near the bottom of the build under the title 'Insert into VS'. Examine the log for 'Insert VS Payload' and near the
+bottom you'll see a line that looks like `Created request #xxxxxx at https://...`.
+
+Insertions generated to any `rel/*` branch will have to be manually verified and merged, and they'll be listed
+[here](https://dev.azure.com/devdiv/DevDiv/_git/VS/pullrequests?createdBy=122d5278-3e55-4868-9d40-1e28c2515fc4&_a=active).
+Note that insertions for other teams will also be listed.
+
+Insertions to any other VS branch (e.g., `main`) will have the auto-merge flag set and should handle themselves, but
+it's a good idea to check the previous link for any old or stalled insertions into VS `main`.
+
+## Less interesting links
+
+[FSharp.Core (Official NuGet Release)](https://dev.azure.com/dnceng/internal/_release?_a=releases&definitionId=72).
+Uploads the final `FSharp.Core` package from the specified build to NuGet. This should only be run when we know for
+certain which build produced the final offical package.
+
+[FSharp.Core (Preview NuGet Release)](https://dev.azure.com/dnceng/internal/_release?_a=releases&definitionId=92).
+Uploads the preview `FSharp.Core.*-beta.*` package from the specified build to NuGet. This should be run every time
+a new SDK preview is released.
+
+[FCS (Official NuGet Release)](https://dev.azure.com/dnceng/internal/_release?view=mine&_a=releases&definitionId=99).
+Uploads the final `FSharp.Compiler.Service` package from the specified build to NuGet. Only builds from the `release/fcs`
+branch can be selected. This should only be run when we're fairly certain that the package is complete.
+
+[FCS (Preview NuGet Release)](https://dev.azure.com/dnceng/internal/_release?view=mine&_a=releases&definitionId=98).
+Uploads the preview `FSharp.Compiler.Service.*-preview.*` package from the specified build to NuGet. Only builds from the
+`main` branch can be selected. This can be run whenever we think we're ready to preview a new FCS build.
+
+[Nightly VSIX (main) uploader](https://dev.azure.com/dnceng/internal/_release?_a=releases&definitionId=70). Uploads
+a package from every build of `main` to the [Nightly VSIX feed](README.md#using-nightly-releases-in-visual-studio).
+
+[Nightly VSIX (preview) uploader](https://dev.azure.com/dnceng/internal/_release?_a=releases&definitionId=71). Uploads
+a package from every build of the branch that corresponds to the current Visual Studio preview to the
+[Preview VSIX feed](README.md#using-nightly-releases-in-visual-studio).
+
+[Internal source mirror](https://dev.azure.com/dnceng/internal/_git/dotnet-fsharp).
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 57b9e9d1dbe..00000000000
--- a/Makefile
+++ /dev/null
@@ -1,107 +0,0 @@
-Configuration ?= Release
-ConfigurationProperty = /p:Configuration=$(Configuration)
-DotNetVersion = `cat DotnetCLIToolsVersion.txt`
-DotNetToolPath = $(CURDIR)/artifacts/toolset/dotnet
-
-Verbosity ?= normal
-VerbosityProperty = /Verbosity:$(Verbosity)
-
-MSBuild = $(shell which msbuild)
-RestoreCommand = $(MSBuild) /t:Restore
-BuildCommand = $(MSBuild) /t:Build
-TestCommand = $(MSBuild) /t:VSTest
-ProtoConfiguration = /p:Configuration=Proto
-
-NF45 = /p:TargetFramework=net45
-NF472 = /p:TargetFramework=net472
-NS16 = /p:TargetFramework=netstandard1.6
-NS20 = /p:TargetFramework=netstandard2.0
-NCA20 = /p:TargetFramework=netcoreapp2.0
-NCA21 = /p:TargetFramework=netcoreapp2.1
-
-PackageRoot ?= $(shell nuget locals global-packages -list | cut -d' ' -f2)
-NUnitVersion ?= $(shell ls $(PackageRoot)nunit.runners | sort -r | head -n 1)
-NUnitRunner = $(PackageRoot)nunit.consolerunner/$(NUnitVersion)/tools/nunit3-console.exe
-NUnitCommand = $(monocmd) $(NUnitRunner)
-
-include $(topsrcdir)mono/config.make
-export PATH := "$(DotNetToolPath):$(PATH)"
-
-debug: debugvars
- @echo PackageRoot=$(PackageRoot)
- @echo NUnitVersion=$(NUnitVersion)
- @echo NUnitCommand=$(NUnitCommand)
-
-all: proto restore build
-
-tools:
- $(CURDIR)/scripts/dotnet-install.sh --install-dir "$(DotNetToolPath)"
-
-proto: tools
- $(RestoreCommand) $(NF472) src/buildtools/buildtools.proj
- $(RestoreCommand) $(NF472) src/fsharp/FSharp.Build/FSharp.Build.fsproj
- $(RestoreCommand) $(NF472) src/fsharp/fsc/fsc.fsproj
- $(BuildCommand) $(NF472) $(ConfigurationProperty) src/buildtools/buildtools.proj
- $(BuildCommand) $(NF472) $(ProtoConfiguration) src/fsharp/FSharp.Build/FSharp.Build.fsproj
- $(BuildCommand) $(NF472) $(ProtoConfiguration) $(VerbosityProperty) src/fsharp/fsc/fsc.fsproj
-
-restore:
- $(RestoreCommand) src/fsharp/FSharp.Core/FSharp.Core.fsproj
- $(RestoreCommand) src/fsharp/FSharp.Build/FSharp.Build.fsproj
- $(RestoreCommand) src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj
- $(RestoreCommand) src/fsharp/fsc/fsc.fsproj
- $(RestoreCommand) src/fsharp/FSharp.Compiler.Interactive.Settings/FSharp.Compiler.Interactive.Settings.fsproj
- $(RestoreCommand) src/fsharp/fsi/fsi.fsproj
- $(RestoreCommand) src/fsharp/fsiAnyCpu/fsiAnyCpu.fsproj
- $(RestoreCommand) tests/FSharp.Core.UnitTests/FSharp.Core.UnitTests.fsproj
- $(RestoreCommand) tests/FSharp.Build.UnitTests/FSharp.Build.UnitTests.fsproj
-
-build: proto restore
- $(BuildCommand) $(ConfigurationProperty) $(NF45) src/fsharp/FSharp.Core/FSharp.Core.fsproj
- $(BuildCommand) $(ConfigurationProperty) $(NF472) src/fsharp/FSharp.Build/FSharp.Build.fsproj
- $(BuildCommand) $(ConfigurationProperty) $(NF472) src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj
- $(BuildCommand) $(ConfigurationProperty) $(NF472) src/fsharp/fsc/fsc.fsproj
- $(BuildCommand) $(ConfigurationProperty) $(NF472) src/fsharp/FSharp.Compiler.Interactive.Settings/FSharp.Compiler.Interactive.Settings.fsproj
- $(BuildCommand) $(ConfigurationProperty) $(NF472) src/fsharp/fsi/fsi.fsproj
- $(BuildCommand) $(ConfigurationProperty) $(NF472) src/fsharp/fsiAnyCpu/fsiAnyCpu.fsproj
- $(BuildCommand) $(ConfigurationProperty) $(NF472) tests/FSharp.Core.UnitTests/FSharp.Core.UnitTests.fsproj
- $(BuildCommand) $(ConfigurationProperty) $(NF472) tests/FSharp.Build.UnitTests/FSharp.Build.UnitTests.fsproj
-
-test:
- $(NUnitCommand) $(builddir)/FSharp.Core.UnitTests/$(Configuration)/net472/FSharp.Core.UnitTests.dll
- $(NUnitCommand) $(builddir)/FSharp.Build.UnitTests/$(Configuration)/net472/FSharp.Build.UnitTests.dll
- # TODO: expand the set of tests that are run on mono here (ie FSharp.Compiler.UnitTests, fsharp/FSharpSuite.Tests.fsproj, fsharpqa/run.fsharpqa.test.fsx)
-
-clean:
- rm -rf $(CURDIR)/artifacts
-
-install:
- -rm -fr $(DESTDIR)$(monodir)/fsharp
- -rm -fr $(DESTDIR)$(monodir)/Microsoft\ F#
- -rm -fr $(DESTDIR)$(monodir)/Microsoft\ SDKs/F#
- -rm -fr $(DESTDIR)$(monodir)/msbuild/Microsoft/VisualStudio/v/FSharp
- -rm -fr $(DESTDIR)$(monodir)/msbuild/Microsoft/VisualStudio/v11.0/FSharp
- -rm -fr $(DESTDIR)$(monodir)/msbuild/Microsoft/VisualStudio/v12.0/FSharp
- -rm -fr $(DESTDIR)$(monodir)/msbuild/Microsoft/VisualStudio/v14.0/FSharp
- -rm -fr $(DESTDIR)$(monodir)/msbuild/Microsoft/VisualStudio/v15.0/FSharp
- $(MAKE) -C mono/FSharp.Core TargetDotnetProfile=net45 install
- $(MAKE) -C mono/FSharp.Build TargetDotnetProfile=net472 install
- $(MAKE) -C mono/FSharp.Compiler.Private TargetDotnetProfile=net472 install
- $(MAKE) -C mono/Fsc TargetDotnetProfile=net472 install
- $(MAKE) -C mono/FSharp.Compiler.Interactive.Settings TargetDotnetProfile=net472 install
- $(MAKE) -C mono/FSharp.Compiler.Server.Shared TargetDotnetProfile=net472 install
- $(MAKE) -C mono/fsi TargetDotnetProfile=net472 install
- $(MAKE) -C mono/fsiAnyCpu TargetDotnetProfile=net472 install
- # $(MAKE) -C mono/FSharp.Core TargetDotnetProfile=net40 FSharpCoreBackVersion=3.0 install
- # $(MAKE) -C mono/FSharp.Core TargetDotnetProfile=net40 FSharpCoreBackVersion=3.1 install
- # $(MAKE) -C mono/FSharp.Core TargetDotnetProfile=net40 FSharpCoreBackVersion=4.0 install
- # $(MAKE) -C mono/FSharp.Core TargetDotnetProfile=net40 FSharpCoreBackVersion=4.1 install
- # $(MAKE) -C mono/FSharp.Core TargetDotnetProfile=portable47 install
- # $(MAKE) -C mono/FSharp.Core TargetDotnetProfile=portable7 install
- # $(MAKE) -C mono/FSharp.Core TargetDotnetProfile=portable78 install
- # $(MAKE) -C mono/FSharp.Core TargetDotnetProfile=portable259 install
- # $(MAKE) -C mono/FSharp.Core TargetDotnetProfile=monoandroid10+monotouch10+xamarinios10 install
- # $(MAKE) -C mono/FSharp.Core TargetDotnetProfile=xamarinmacmobile install
- echo "------------------------------ INSTALLED FILES --------------"
- ls -xlR $(DESTDIR)$(monodir)/fsharp $(DESTDIR)$(monodir)/msbuild $(DESTDIR)$(monodir)/xbuild $(DESTDIR)$(monodir)/Reference\ Assemblies $(DESTDIR)$(monodir)/gac/FSharp* $(DESTDIR)$(monodir)/Microsoft* || true
-
diff --git a/NuGet.config b/NuGet.config
index 9acafaa472f..767f37569a2 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -6,29 +6,32 @@
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/README.md b/README.md
index b5f8b936e64..1eb6e1c3b78 100644
--- a/README.md
+++ b/README.md
@@ -2,31 +2,53 @@
You're invited to contribute to future releases of the F# compiler, core library, and tools. Development of this repository can be done on any OS supported by [.NET Core](https://dotnet.microsoft.com/).
+You will also need the latest .NET 5 SDK installed from [here](https://dotnet.microsoft.com/download/dotnet/5.0).
+
## Contributing
### Quickstart on Windows
Build from the command line:
-```bash
+```
build.cmd
```
+The build depends on an installation of Visual Studio. To build the compiler without this dependency use:
+
+```
+build.cmd -noVisualStudio
+```
+
After it's finished, open either `FSharp.sln` or `VisualFSharp.sln` in your editor of choice. The latter solution is larger but includes the F# tools for Visual Studio and its associated infrastructure.
### Quickstart on Linux or macOS
Build from the command line:
-```bash
-sh ./build.sh
+```
+./build.sh
```
After it's finished, open `FSharp.sln` in your editor of choice.
-### More options and information
+### Visual Studio Online quickstart
+
+If you'd like to use Visual Studio online (or VSCode with VSO as backend), just click this button to create a new online environment:
+
+
+
+This will provision an environment with all necessary dependencies. Initial build of the environment may take up to 10 minutes, as it's also performing initial build of the F# compiler.
-See [DEVGUIDE.md](DEVGUIDE.md) and [TESTGUIDE.md](TESTGUIDE.md) for more details on additional configurations for building and testing, how to update compiler error messages, and more.
+### Documentation for contributors
+
+See [DEVGUIDE.md](DEVGUIDE.md) for more details on configurations for building the codebase. In practice, you only really need to run `build.cmd`/`build.sh`.
+
+See [TESTGUIDE.md](TESTGUIDE.md) for information about the various test suites in this codebase and how to run them individually.
+
+See the [Compiler Guide](docs/compiler-guide.md) for an in-depth guide to the F# compiler. It is essential reading for any larger contributions to the F# compiler codebase.
+
+See [the F# Language Specification](https://fsharp.org/specs/language-spec/) for an in-depth description of the F# language. This is essential for understanding some behaviors of the F# compiler and some of the rules within the compiler codebase. For example, the order and way name resolution happens is specified here, which greatly impacts how the code in Name Resolutions works and why certain decisions are made.
### No contribution is too small
@@ -36,11 +58,11 @@ Even if you find a single-character typo, we're happy to take the change! Althou
| Branch | Status |
|:------:|:------:|
-|master|[](https://dev.azure.com/dnceng/public/_build/latest?definitionId=496&branchName=master)|
+|main|[](https://dev.azure.com/dnceng/public/_build/latest?definitionId=496&branchName=main)|
## Using nightly releases in Visual Studio
-You can use the latest `master` build of the F# compiler and tools for Visual Studio via our nightly releases if you are a Visual Studio user. See details on setup here:
+You can use the latest `main` build of the F# compiler and tools for Visual Studio via our nightly releases if you are a Visual Studio user. See details on setup here:
https://blogs.msdn.microsoft.com/dotnet/2017/03/14/announcing-nightly-releases-for-the-visual-f-tools/
@@ -51,26 +73,28 @@ Alternatively, if you _really_ want to live on the bleeding edge, you can set up
* Set your feed to the preview feed: https://dotnet.myget.org/F/fsharp-preview/vsix
* Install a VSIX manually from the preview feed: https://dotnet.myget.org/feed/fsharp-preview/package/vsix/VisualFSharp
+## Per-build NuGet packages
+
+Per-build verions of our NuGet packages are available via this URL: `https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json `
+
## Branches
These are the branches in use:
-* `master`
- - Most contributions go here.
+* `main`
+ - Almost all contributions go here.
- Able to be built, installed and used in the latest public Visual Studio release.
- May contain updated F# features and logic.
- Used to build nightly VSIX (see above).
- - Gets integrated into https://github.com/fsharp/fsharp to form the basis of Mono releases
- - Gets integrated into https://github.com/fsharp/FSharp.Compiler.Service to form the basis of FSharp.Compiler.Service releases
-* `dev15.9`
+* `release/dev15.9`
- Long-term servicing branch for VS 2017 update 15.9.x. We do not expect to service that release, but if we do, that's where the changes will go.
-* `dev16.x`
+* `release/dev16.x`
- Latest release branch for the particular point release of Visual Studio.
- - Incorporates features and fixes from master up to a particular branch point, then selective cherry-picks.
+ - Incorporates features and fixes from main up to a particular branch point, then selective cherry-picks.
- May contain new features that depend on new things or fixes in the corresponding forthcoming Visual Studio release.
- - Gets integrated back into master once the corresponding Visual Studio release is made.
+ - Gets integrated back into main once the corresponding Visual Studio release is made.
## F# language and core library evolution
@@ -80,13 +104,6 @@ Evolution of the F# language and core library follows a process spanning two add
2. Ideas that are "approved in principle" are eligible for a new RFC in the [F# language design repo](https://github.com/fsharp/fslang-design). This is where the technical specification and discussion of approved suggestions go.
3. Implementations and testing of an RFC are submitted to this repository.
-## Additional project documentation
-
-The following links can help you get an overview of some technical aspects of the F# language and compiler:
-
-* [The F# Compiler Technical Guide](https://fsharp.github.io/2015/09/29/fsharp-compiler-guide.html)
-* [The F# Language Specification](https://fsharp.org/specs/language-spec/)
-
## License
This project is subject to the MIT License. A copy of this license is in [License.txt](License.txt).
@@ -109,3 +126,4 @@ If you're curious about F# itself, check out these links:
* [Get started with F#](https://docs.microsoft.com/dotnet/fsharp/get-started/)
* [F# Software Foundation](https://fsharp.org)
* [F# Testimonials](https://fsharp.org/testimonials)
+
diff --git a/RoslynPackageVersion.txt b/RoslynPackageVersion.txt
deleted file mode 100644
index cc99af67911..00000000000
--- a/RoslynPackageVersion.txt
+++ /dev/null
@@ -1 +0,0 @@
-3.2.0-beta4-19312-15
diff --git a/TESTGUIDE.md b/TESTGUIDE.md
index ef34e6f51bb..503cf6dab91 100644
--- a/TESTGUIDE.md
+++ b/TESTGUIDE.md
@@ -1,20 +1,107 @@
# F# Compiler, Core Library and Visual F# Tools Tests
+Where this guide mentions the command `build` it means either `build.cmd` in the root folder for Windows, or `build.sh` for Linux/MacOS.
+
+## In this guide
+
+* [Quick start: Running Tests](#quick-start-running-tests)
+* [Prerequisites](#prerequisites)
+* [Test Suites](#test-suites)
+* [More details](#more-details)
+* [Other Tips and gotchas](#other-tips-and-gotchas)
+* [Solving common errors](#solving-common-errors)
+* [Approximate running times](#approximate-running-times)
+
+
## Quick start: Running Tests
-To run tests, use variations such as the following, depending on which test suite and build configuration you want:
+Tests are grouped as noted below. Some test groups can only be run in `CI` configuration, for that, you need to pass the `-ci -bl` or `-ci -nobl` arguments. Some test groups can only be run in Release mode, this is indicated below. Some tests can only be run on Windows.
+
+To run tests, from a command prompt, use variations such as the following, depending on which test suite and build configuration you want.
+
+### Tests runnable in any configuration
+
+The following testsets can be run in Release or Debug mode, with or without the `-ci` argument.
+
+Run the tests in Release mode:
+
+ build -testCompiler -c Release
+ build -testFSharpCore -c Release
+ build -testScripting -c Release
+ build -testVS -c Release
+
+Run the tests in Debug mode, add `-c Debug` or leave it out:
+
+ build -testCompiler -c Debug
+ build -testFSharpCore -c Debug
+ build -testScripting -c Debug
+ build -testVS -c Debug
+
+### Tests that can be run on Linux and MacOS
+
+If you're using Linux or MacOS to develop, the group of tests that are known to succeed are all in `-testCoreClr`. Any other `-testXXX` argument will currently fail. An effort is underway to make testing and running tests easier on all systems.
+
+### Tests that can only be run in Release mode
+
+The following tests **must** be run in Release mode with `-c Release`:
+
+ build -testAll -c Release
+ build -test -c Release
+ build -testDesktop -c Release
+ build -testCoreClr -c Release
+
+### Tests that can only run with `-ci`
- build.cmd test
- build.cmd net40 test
- build.cmd coreclr test
- build.cmd vs test
- build.cmd all test
+The following tests **must** be run in Release mode and **must** have the CI argument like `-ci -bl` or `-ci -nobl`:
-You can also submit pull requests to https://github.com/dotnet/fsharp and run the tests via continuous integration. Most people do wholesale testing that way.
+ build -testCambridge -c Release -ci -nobl
+ build -testFSharpQA -c Release -ci -nobl
+
+
+### Tests that open other windows
+
+The following testsets open other windows and may interfere with you using your workstation, or change focus while you're doing something else:
+
+* FSharpQA
+* Cambridge
+
+### Tests grouping summary
+
+| Group name | OS | Description |
+|------------|----|-------------|
+| testDesktop | Windows | Runs all net472 tests in 32 bit processes, this includes tests from other groups |
+| testCoreClr | Linux/Mac/Windows | Runs all .NetStandard and .NETCore tests in 64 bit processes, this includes tests from other groups |
+| testFSharpCore | Windows | Runs all test for FSharp.Core.dll |
+| testCambridge | Windows | Runs the Cambridge suite tests |
+| testFSharpQA | Windows | Runs the FSharpQA tests, requires Perl |
+| testVS | Windows + VS | Runs all VS integration tests |
+| testCompiler | Windows | Runs a few quick compiler tests |
+| testScripting | Windows | Runs scripting fsx and fsi commandline tests |
+| test | Windows | Same as testDesktop |
+| testAll | Windows | Runs all above tests |
+
+### Running tests online in CI
+
+You can also submit pull requests to https://github.com/dotnet/fsharp and run the tests via continuous integration. Most people do wholesale testing that way. A few notes:
+
+* Online, sometimes unrelated tests or builds may fail, a rerun may solve this
+* A CI build can be restarted by closing/reopening the PR
+* A new CI build will be started on each pushed commit
+* CI builds that are not finished will be canceled on new commits. If you need to complete such runs, you can do so in the Checks tab of the PR by selecting the actual commit from the dropdown.
+
+#### Analyzing CI results
+
+Finding the logs in the online CI results can be tricky, a small video can be found below under "Test gotchas".
## Prerequisites
-It is recommended that you run tests from an elevated command prompt, as there are a couple of test cases which require administrative privileges.
+The prerequisites are the same as for building the `FSharp.sln`, plus, at a minimum:
+
+* An installation of Perl, required for running FSharpQA tests
+* Run `git clean -xdf -e .vs` before running tests when:
+ * Making changes to the lexer or parser
+ * Between switching git branches
+ * When merging with latest `main` upstream branch.
## Test Suites
@@ -46,9 +133,9 @@ There are also negative tests checking code expected to fail compilation. See no
### FSharpQA Suite
-The FSharpQA suite relies on [Perl](http://www.perl.org/get.html), StrawberryPerl64 package from nuget is used automatically by the test suite.
+The FSharpQA suite relies on [Perl](http://www.perl.org/get.html), StrawberryPerl package from nuget is used automatically by the test suite.
-These tests use the `RunAll.pl` framework to execute, however the easiest way to run them is via the `build.cmd` script, see [usage examples](https://github.com/Microsoft/visualfsharp/blob/master/build.cmd#L31).
+These tests use the `RunAll.pl` framework to execute, however the easiest way to run them is via the `.\build` script, see [usage examples](#quick-start-running-tests).
Tests are grouped in folders per area. Each folder contains a number of source code files and a single `env.lst` file. The `env.lst` file defines a series of test cases, one per line.
@@ -66,7 +153,7 @@ For the FSharpQA suite, the list of test areas and their associated "tags" is st
Tags are in the left column, paths to to corresponding test folders are in the right column. If no tags are specified, all tests will be run.
-If you want to re-run a particular test area, the easiest way to do so is to set a temporary tag for that area in test.lst (e.g. "RERUN") and then pass that as an argument to `build.cmd`: `build.cmd test-net40-fsharpqa include RERUN`.
+If you want to re-run a particular test area, the easiest way to do so is to set a temporary tag for that area in test.lst (e.g. "RERUN") and adjust `ttags` [run.fsharpqa.test.fsx script](tests/fsharpqa/run.fsharpqa.test.fsx) and run it.
### FSharp.Compiler.UnitTests, FSharp.Core.UnitTests, VisualFSharp.UnitTests
@@ -87,11 +174,12 @@ All test execution logs and result files will be dropped into the `tests\TestRes
net40-coreunit-suite-*.*
vs-ideunit-suite-*.*
-### Baselines
+### Working with baseline tests
-FSharp Test Suite works with couples of .bsl (or .bslpp) files considered "expected" and called baseline, those are matched against the actual output which resides under .err or .vserr files of same name at the during test execution.
+FSharp Test Suite works with a couple of `.bsl` (or `.bslpp`) files describing "expected test results" and are called the _Baseline Tests_. Those are matched against the actual output that resides under `.err` or `.vserr` files of the same name during test execution.
When doing so keep in mind to carefully review the diff before comitting updated baseline files.
-.bslpp (baseline pre-process) files are specially designed to enable substitution of certain tokens to generate the .bsl file. You can look further about the pre-processing logic under [tests/fsharp/TypeProviderTests.fs](tests/fsharp/TypeProviderTests.fs), this is used only for type provider tests for now.
+
+The `.bslpp` (for: baseline pre-process) files are specially designed to enable substitution of certain tokens to generate the `.bsl` file. You can look further about the pre-processing logic under [tests/fsharp/TypeProviderTests.fs](tests/fsharp/TypeProviderTests.fs), this is used only for type provider tests for now.
To update baselines use this:
@@ -101,15 +189,93 @@ Use `-n` to dry-run:
fsi tests\scripts\update-baselines.fsx -n
-### Other Tips
+## Other Tips and gotchas
+
+This section contains general tips, for solving errors see [next section](#solving-common-errors).
+
+### Close any open VisualFSharp.sln
-#### Run as Administrator
+If you have the `VisualFSharp.sln` open, or if you recently debugged it through `VisualFSharpFull` as start-up project, certain tests may fail because files will be in use. It's best to close Visual Studio and any debugging sessions during a test run. It is fine to have VS open on a different solution, or to have it open from a different F# repo folder.
-Do this, or a handful of tests will fail.
+### Finding the logs on CI
-#### Making the tests run faster
+Finding the proper logs in the CI system can be daunting, this video shows you where to look once you have an open PR. It shows you how to get the `FsharpQA` logs, but the same method applies to getting any other test logs.
+
+
+The console output of the CI runs do not contain output of the FSharpQA tests, but for most other tests the console output contains enough info and can be found by clicking Raw output in the CI window, or clicking download logs:
+
+
+
+### Increase command screen line buffer on Windows
+
+You can increase the window buffer so that more lines of the console output can be scrolled back to, as opposed to them disappearing off the top. The default size on Windows is very small:
+
+* Click top-left icon of the command window
+* Go to Properties then Layout
+* Select a higher _Screen buffer size_ than the window size (this will add a scroll bar)
+* You may want to increase the width and height as well
+* Click OK.
+
+### Run as Administrator
+
+Running tests should now be possible without admin privileges. If you find tests that don't run unless you are an admin, please create an issue.
+
+### Running tests on other (feature) branches
+
+When you switch branches, certain temporary files, as well as the .NET version (downloaded to `.dotnet` folder) are likely to not be in sync anymore and can lead to curious build errors. Fix this by running `git clean` like this (this will leave your VS settings intact):
+
+ git clean -xdf -e .vs
+
+If you get "file in use" errors during cleaning, make sure to close Visual Studio and any running `dotnet.exe` and `VBCSCompiler.exe`, esp those that show up at the bottom of [Process Explorer](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer) without parent process.
+
+#### Running tests on release/dev16.6 etc branches
+
+Some tests are known to fail on these older branches when run using one of the `testXXXX` commandline arguments. However, `-test`, `-testAll`, `-testCoreClr` and `-testDesktop` are known to work on at least the `dev16.6` and `dev16.7` branches.
+
+### Making the tests run faster
+
+* Adding the `-norestore` flag to the commandline speeds up the build part a little bit.
+* When using the `-ci` flag (mandatory for some testsets), adding the `-nobl` flag prevents creating the binary log files.
* NGen-ing the F# bits (fsc, fsi, FSharp.Core, etc) will result in tests executing much faster. Make sure you run `src\update.cmd` with the `-ngen` flag before running tests.
+
+Some tests run in parallel by default, or use a hosted compiler to speed things up:
+
* The FSharp and FSharpQA suites will run test cases in parallel by default. You can comment out the relevant line (look for `PARALLEL_ARG`) to disable this.
* By default, tests from the FSharpQA suite are run using a persistent, hosted version of the compiler. This speeds up test execution, as there is no need for the `fsc.exe` process to spin up repeatedly. To disable this, uncomment the relevant line (look for `HOSTED_COMPILER`).
+## Solving common errors
+
+The following are common errors that users have encountered while running tests on their system.
+
+### Error that a file cannot be accessed
+
+The build often leaves dangling processes like `HostedCompilerServer.exe`, `VBCSCompiler.exe` or `MSBuild.exe`. In [Process Explorer](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer) you can see these processes having no parent process anymore. You can also use this to kill such processes. A typical error looks like and contains the process IDs (here 23152, 25252 and 24704):
+
+> C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(4364,5): error MSB3026: Could not copy "D:\Projects\FSharp\artifacts\bin\FSharp.Core\Debug\net45\FSharp.Core.dll" to "D:\Projects\FSharp\tests\fsharpqa\testenv\bin\FSharp.Core.dll". Beginning retry 1 in 1000ms. The process cannot access the file 'D:\Projects\FSharp\tests\fsharpqa\testenv\bin\FSharp.Core.dll' because it is being used by another process. The file is locked by: "HostedCompilerServer (23152), HostedCompilerServer (25252), HostedCompilerServer (24704)" [D:\Projects\OpenSource\FSharp\tests\fsharpqa\testenv\src\ILComparer\ILComparer.fsproj]
+
+### StackOverflow exception
+
+This usually happens when you try to run tests without specifying `-c Release`, or as `-c Debug` (which is the default). Run the same set with `-c Release` instead and the SOE should disappear.
+
+## Approximate running times
+
+Some tests can run for several minutes, this doesn't mean that your system froze:
+
+
+
+To get an idea of how long it may take, or how much coffee you'll need while waiting, here are some rough indications from an older workstation run, using arguments `-c Release -nobl -norestore`:
+
+| Testset | Approx running time | Ngen'ed running time |
+|-------|-------|-----|
+| sln build time | 1 min* | n/a |
+| `-testDesktop` | 5 min | ? |
+| `-testCoreClr` | 36 min | ? |
+| `-testCambridge` | 72 min | 35 min |
+| `-testFSharpQA` | 13 min | ? |
+| `-testCompiler` | 30 seconds | n/a |
+| `-testFSharpCore` | 2 min | ? |
+| `-testScripting` | 2 min | 1.5 min |
+| `-testVS` | 13 min | ? |
+
+* This is the build time when a previous build with the same configuration succeeded, and without `-ci` present, which always rebuilds the solution. With `-norestore` the build part can go down to about 10-20 seconds, before tests are being run
diff --git a/VisualFSharp.sln b/VisualFSharp.sln
index 4a1e75f446a..97f33a5da25 100644
--- a/VisualFSharp.sln
+++ b/VisualFSharp.sln
@@ -22,8 +22,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ItemTemplates", "ItemTemplates", "{F6DAEE9A-8BE1-4C4A-BC83-09215517C7DA}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utils", "Utils", "{D086C8C6-D00D-4C3B-9AB2-A4286C9F5922}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FSharp.Compiler.Service.tests Support", "FSharp.Compiler.Service.tests Support", "{35636A82-401A-4C3A-B2AB-EB7DC5E9C268}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Legacy", "Legacy", "{CCAB6E50-34C6-42AF-A6B0-567C29FCD91B}"
@@ -34,8 +32,6 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Private", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisualFSharpFull", "vsintegration\Vsix\VisualFSharpFull\VisualFSharpFull.csproj", "{59ADCE46-9740-4079-834D-9A03A3494EBC}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisualFSharpTemplates", "vsintegration\Vsix\VisualFSharpTemplates\VisualFSharpTemplates.csproj", "{025CE01B-98F3-4C3C-B486-2C0BD038D011}"
-EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Server.Shared", "src\fsharp\FSharp.Compiler.Server.Shared\FSharp.Compiler.Server.Shared.fsproj", "{D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Core", "src\fsharp\FSharp.Core\FSharp.Core.fsproj", "{DED3BBD7-53F4-428A-8C9F-27968E768605}"
@@ -90,6 +86,8 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "fsiAnyCpu", "src\fsharp\fsi
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "fsi", "src\fsharp\fsi\fsi.fsproj", "{D0E98C0D-490B-4C61-9329-0862F6E87645}"
EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Test.Utilities", "tests\FSharp.Test.Utilities\FSharp.Test.Utilities.fsproj", "{60D275B0-B14A-41CB-A1B2-E815A7448FCB}"
+EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharpSuite.Tests", "tests\fsharp\FSharpSuite.Tests.fsproj", "{C163E892-5BF7-4B59-AA99-B0E8079C67C4}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.UnitTests", "tests\FSharp.Compiler.UnitTests\FSharp.Compiler.UnitTests.fsproj", "{A8D9641A-9170-4CF4-8FE0-6DB8C134E1B5}"
@@ -112,8 +110,6 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "HostedCompilerServer", "tes
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ILComparer", "tests\fsharpqa\testenv\src\ILComparer\ILComparer.fsproj", "{2E60864A-E3FF-4BCC-810F-DC7C34E6B236}"
EndProject
-Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "LanguageServiceProfiling", "vsintegration\Utils\LanguageServiceProfiling\LanguageServiceProfiling.fsproj", "{E7FA3A71-51AF-4FCA-9C2F-7C853E515903}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSharp.UIResources", "vsintegration\src\FSharp.UIResources\FSharp.UIResources.csproj", "{C4586A06-1402-48BC-8E35-A1B8642F895B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharp_Analysis", "tests\service\data\CSharp_Analysis\CSharp_Analysis.csproj", "{887630A3-4B1D-40EA-B8B3-2D842E9C40DB}"
@@ -142,23 +138,42 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.FSharp.SDK", "set
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{647810D0-5307-448F-99A2-E83917010DAE}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.FSharp.Compiler", "src\fsharp\Microsoft.FSharp.Compiler\Microsoft.FSharp.Compiler.csproj", "{04C59F6E-1C76-4F6A-AC21-2EA7F296A1B8}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.FSharp.Compiler", "src\fsharp\FSharp.Compiler.nuget\Microsoft.FSharp.Compiler.csproj", "{04C59F6E-1C76-4F6A-AC21-2EA7F296A1B8}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProjectTemplates", "ProjectTemplates", "{BED74F9E-A0D2-48E2-9EE7-449832100487}"
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Private.Scripting", "src\fsharp\FSharp.Compiler.Private.Scripting\FSharp.Compiler.Private.Scripting.fsproj", "{20B7BC36-CF51-4D75-9E13-66681C07977F}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Private.Scripting.UnitTests", "tests\FSharp.Compiler.Private.Scripting.UnitTests\FSharp.Compiler.Private.Scripting.UnitTests.fsproj", "{09F56540-AFA5-4694-B7A6-0DBF6D4618C2}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.DependencyManager.Nuget", "src\fsharp\FSharp.DependencyManager.Nuget\FSharp.DependencyManager.Nuget.fsproj", "{DFA30881-C0B1-4813-B087-C21B5AF9B77F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisualFSharpTemplates", "vsintegration\Vsix\VisualFSharpTemplates\VisualFSharpTemplates.csproj", "{AA259A37-418F-4E18-87B2-C7D5F8C26CC4}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProjectTemplates", "ProjectTemplates", "{12EF27FD-A34B-4373-860A-F9FCE9651859}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleProject", "vsintegration\ProjectTemplates\ConsoleProject\ConsoleProject.csproj", "{44155269-9B30-43DA-B97F-4F36F887B211}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryProject", "vsintegration\ProjectTemplates\LibraryProject\LibraryProject.csproj", "{B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TutorialProject", "vsintegration\ProjectTemplates\TutorialProject\TutorialProject.csproj", "{2937CBEC-262D-4C94-BE1D-291FAB72E3E8}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Microsoft.DotNet.DependencyManager", "src\fsharp\Microsoft.DotNet.DependencyManager\Microsoft.DotNet.DependencyManager.fsproj", "{C2F38485-5F87-4986-985B-55D7ED96D5CE}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleProject", "vsintegration\ProjectTemplates\ConsoleProject\ConsoleProject.csproj", "{1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisualFSharpTemplates", "vsintegration\Vsix\VisualFSharpTemplates\VisualFSharpTemplates.csproj", "{AA259A37-418F-4E18-87B2-C7D5F8C26CC4}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibraryProject", "vsintegration\ProjectTemplates\LibraryProject\LibraryProject.csproj", "{C32806E0-71C2-40E4-AEC4-517F73F6A18A}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProjectTemplates", "ProjectTemplates", "{12EF27FD-A34B-4373-860A-F9FCE9651859}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TutorialProject", "vsintegration\ProjectTemplates\TutorialProject\TutorialProject.csproj", "{7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleProject", "vsintegration\ProjectTemplates\ConsoleProject\ConsoleProject.csproj", "{44155269-9B30-43DA-B97F-4F36F887B211}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSharp.Core.nuget", "src\fsharp\FSharp.Core.nuget\FSharp.Core.nuget.csproj", "{8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryProject", "vsintegration\ProjectTemplates\LibraryProject\LibraryProject.csproj", "{B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}"
EndProject
-Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.LanguageServer", "src\fsharp\FSharp.Compiler.LanguageServer\FSharp.Compiler.LanguageServer.fsproj", "{60BAFFA5-6631-4328-B044-2E012AB76DCA}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TutorialProject", "vsintegration\ProjectTemplates\TutorialProject\TutorialProject.csproj", "{2937CBEC-262D-4C94-BE1D-291FAB72E3E8}"
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.ComponentTests", "tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj", "{0610FB97-7C15-422A-86FD-32335C6DF14D}"
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.ComponentTests", "tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj", "{0610FB97-7C15-422A-86FD-32335C6DF14D}"
EndProject
-Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.LanguageServer.UnitTests", "tests\FSharp.Compiler.LanguageServer.UnitTests\FSharp.Compiler.LanguageServer.UnitTests.fsproj", "{AAF2D233-1C38-4090-8FFA-F7C545625E06}"
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Service", "src\fsharp\FSharp.Compiler.Service\FSharp.Compiler.Service.fsproj", "{B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FSharp.Editor.Helpers", "vsintegration\src\FSharp.Editor.Helpers\FSharp.Editor.Helpers.csproj", "{79255A92-ED00-40BA-9D64-12FCC664A976}"
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Service.Tests", "tests\FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj", "{14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -206,18 +221,6 @@ Global
{59ADCE46-9740-4079-834D-9A03A3494EBC}.Release|Any CPU.Build.0 = Release|Any CPU
{59ADCE46-9740-4079-834D-9A03A3494EBC}.Release|x86.ActiveCfg = Release|Any CPU
{59ADCE46-9740-4079-834D-9A03A3494EBC}.Release|x86.Build.0 = Release|Any CPU
- {025CE01B-98F3-4C3C-B486-2C0BD038D011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {025CE01B-98F3-4C3C-B486-2C0BD038D011}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {025CE01B-98F3-4C3C-B486-2C0BD038D011}.Debug|x86.ActiveCfg = Debug|Any CPU
- {025CE01B-98F3-4C3C-B486-2C0BD038D011}.Debug|x86.Build.0 = Debug|Any CPU
- {025CE01B-98F3-4C3C-B486-2C0BD038D011}.Proto|Any CPU.ActiveCfg = Release|Any CPU
- {025CE01B-98F3-4C3C-B486-2C0BD038D011}.Proto|Any CPU.Build.0 = Release|Any CPU
- {025CE01B-98F3-4C3C-B486-2C0BD038D011}.Proto|x86.ActiveCfg = Release|Any CPU
- {025CE01B-98F3-4C3C-B486-2C0BD038D011}.Proto|x86.Build.0 = Release|Any CPU
- {025CE01B-98F3-4C3C-B486-2C0BD038D011}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {025CE01B-98F3-4C3C-B486-2C0BD038D011}.Release|Any CPU.Build.0 = Release|Any CPU
- {025CE01B-98F3-4C3C-B486-2C0BD038D011}.Release|x86.ActiveCfg = Release|Any CPU
- {025CE01B-98F3-4C3C-B486-2C0BD038D011}.Release|x86.Build.0 = Release|Any CPU
{D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06}.Debug|x86.ActiveCfg = Debug|Any CPU
@@ -542,6 +545,18 @@ Global
{D0E98C0D-490B-4C61-9329-0862F6E87645}.Release|Any CPU.Build.0 = Release|Any CPU
{D0E98C0D-490B-4C61-9329-0862F6E87645}.Release|x86.ActiveCfg = Release|Any CPU
{D0E98C0D-490B-4C61-9329-0862F6E87645}.Release|x86.Build.0 = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Debug|x86.Build.0 = Debug|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Proto|Any CPU.ActiveCfg = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Proto|Any CPU.Build.0 = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Proto|x86.ActiveCfg = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Proto|x86.Build.0 = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Release|x86.ActiveCfg = Release|Any CPU
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB}.Release|x86.Build.0 = Release|Any CPU
{C163E892-5BF7-4B59-AA99-B0E8079C67C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C163E892-5BF7-4B59-AA99-B0E8079C67C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C163E892-5BF7-4B59-AA99-B0E8079C67C4}.Debug|x86.ActiveCfg = Debug|Any CPU
@@ -674,18 +689,6 @@ Global
{2E60864A-E3FF-4BCC-810F-DC7C34E6B236}.Release|Any CPU.Build.0 = Release|Any CPU
{2E60864A-E3FF-4BCC-810F-DC7C34E6B236}.Release|x86.ActiveCfg = Release|Any CPU
{2E60864A-E3FF-4BCC-810F-DC7C34E6B236}.Release|x86.Build.0 = Release|Any CPU
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903}.Debug|x86.ActiveCfg = Debug|Any CPU
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903}.Debug|x86.Build.0 = Debug|Any CPU
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903}.Proto|Any CPU.ActiveCfg = Release|Any CPU
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903}.Proto|Any CPU.Build.0 = Release|Any CPU
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903}.Proto|x86.ActiveCfg = Release|Any CPU
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903}.Proto|x86.Build.0 = Release|Any CPU
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903}.Release|Any CPU.Build.0 = Release|Any CPU
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903}.Release|x86.ActiveCfg = Release|Any CPU
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903}.Release|x86.Build.0 = Release|Any CPU
{C4586A06-1402-48BC-8E35-A1B8642F895B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C4586A06-1402-48BC-8E35-A1B8642F895B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C4586A06-1402-48BC-8E35-A1B8642F895B}.Debug|x86.ActiveCfg = Debug|Any CPU
@@ -842,90 +845,150 @@ Global
{04C59F6E-1C76-4F6A-AC21-2EA7F296A1B8}.Release|Any CPU.Build.0 = Release|Any CPU
{04C59F6E-1C76-4F6A-AC21-2EA7F296A1B8}.Release|x86.ActiveCfg = Release|Any CPU
{04C59F6E-1C76-4F6A-AC21-2EA7F296A1B8}.Release|x86.Build.0 = Release|Any CPU
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}.Debug|x86.ActiveCfg = Debug|Any CPU
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}.Debug|x86.Build.0 = Debug|Any CPU
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}.Proto|Any CPU.ActiveCfg = Proto|Any CPU
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}.Proto|Any CPU.Build.0 = Proto|Any CPU
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}.Proto|x86.ActiveCfg = Proto|Any CPU
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}.Proto|x86.Build.0 = Proto|Any CPU
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}.Release|Any CPU.Build.0 = Release|Any CPU
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}.Release|x86.ActiveCfg = Release|Any CPU
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8}.Release|x86.Build.0 = Release|Any CPU
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A}.Debug|x86.ActiveCfg = Debug|Any CPU
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A}.Debug|x86.Build.0 = Debug|Any CPU
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A}.Proto|Any CPU.ActiveCfg = Proto|Any CPU
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A}.Proto|Any CPU.Build.0 = Proto|Any CPU
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A}.Proto|x86.ActiveCfg = Proto|Any CPU
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A}.Proto|x86.Build.0 = Proto|Any CPU
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A}.Release|Any CPU.Build.0 = Release|Any CPU
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A}.Release|x86.ActiveCfg = Release|Any CPU
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A}.Release|x86.Build.0 = Release|Any CPU
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}.Debug|x86.ActiveCfg = Debug|Any CPU
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}.Debug|x86.Build.0 = Debug|Any CPU
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}.Proto|Any CPU.ActiveCfg = Proto|Any CPU
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}.Proto|Any CPU.Build.0 = Proto|Any CPU
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}.Proto|x86.ActiveCfg = Proto|Any CPU
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}.Proto|x86.Build.0 = Proto|Any CPU
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}.Release|Any CPU.Build.0 = Release|Any CPU
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}.Release|x86.ActiveCfg = Release|Any CPU
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1}.Release|x86.Build.0 = Release|Any CPU
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}.Debug|x86.ActiveCfg = Debug|Any CPU
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}.Debug|x86.Build.0 = Debug|Any CPU
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}.Proto|Any CPU.ActiveCfg = Release|Any CPU
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}.Proto|Any CPU.Build.0 = Release|Any CPU
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}.Proto|x86.ActiveCfg = Release|Any CPU
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}.Proto|x86.Build.0 = Release|Any CPU
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}.Release|Any CPU.Build.0 = Release|Any CPU
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}.Release|x86.ActiveCfg = Release|Any CPU
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC}.Release|x86.Build.0 = Release|Any CPU
- {60BAFFA5-6631-4328-B044-2E012AB76DCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {60BAFFA5-6631-4328-B044-2E012AB76DCA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {60BAFFA5-6631-4328-B044-2E012AB76DCA}.Debug|x86.ActiveCfg = Debug|Any CPU
- {60BAFFA5-6631-4328-B044-2E012AB76DCA}.Debug|x86.Build.0 = Debug|Any CPU
- {60BAFFA5-6631-4328-B044-2E012AB76DCA}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
- {60BAFFA5-6631-4328-B044-2E012AB76DCA}.Proto|Any CPU.Build.0 = Debug|Any CPU
- {60BAFFA5-6631-4328-B044-2E012AB76DCA}.Proto|x86.ActiveCfg = Debug|Any CPU
- {60BAFFA5-6631-4328-B044-2E012AB76DCA}.Proto|x86.Build.0 = Debug|Any CPU
- {60BAFFA5-6631-4328-B044-2E012AB76DCA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {60BAFFA5-6631-4328-B044-2E012AB76DCA}.Release|Any CPU.Build.0 = Release|Any CPU
- {60BAFFA5-6631-4328-B044-2E012AB76DCA}.Release|x86.ActiveCfg = Release|Any CPU
- {60BAFFA5-6631-4328-B044-2E012AB76DCA}.Release|x86.Build.0 = Release|Any CPU
- {AAF2D233-1C38-4090-8FFA-F7C545625E06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {AAF2D233-1C38-4090-8FFA-F7C545625E06}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {AAF2D233-1C38-4090-8FFA-F7C545625E06}.Debug|x86.ActiveCfg = Debug|Any CPU
- {AAF2D233-1C38-4090-8FFA-F7C545625E06}.Debug|x86.Build.0 = Debug|Any CPU
- {AAF2D233-1C38-4090-8FFA-F7C545625E06}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
- {AAF2D233-1C38-4090-8FFA-F7C545625E06}.Proto|Any CPU.Build.0 = Debug|Any CPU
- {AAF2D233-1C38-4090-8FFA-F7C545625E06}.Proto|x86.ActiveCfg = Debug|Any CPU
- {AAF2D233-1C38-4090-8FFA-F7C545625E06}.Proto|x86.Build.0 = Debug|Any CPU
- {AAF2D233-1C38-4090-8FFA-F7C545625E06}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {AAF2D233-1C38-4090-8FFA-F7C545625E06}.Release|Any CPU.Build.0 = Release|Any CPU
- {AAF2D233-1C38-4090-8FFA-F7C545625E06}.Release|x86.ActiveCfg = Release|Any CPU
- {AAF2D233-1C38-4090-8FFA-F7C545625E06}.Release|x86.Build.0 = Release|Any CPU
- {79255A92-ED00-40BA-9D64-12FCC664A976}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {79255A92-ED00-40BA-9D64-12FCC664A976}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {79255A92-ED00-40BA-9D64-12FCC664A976}.Debug|x86.ActiveCfg = Debug|Any CPU
- {79255A92-ED00-40BA-9D64-12FCC664A976}.Debug|x86.Build.0 = Debug|Any CPU
- {79255A92-ED00-40BA-9D64-12FCC664A976}.Proto|Any CPU.ActiveCfg = Release|Any CPU
- {79255A92-ED00-40BA-9D64-12FCC664A976}.Proto|Any CPU.Build.0 = Release|Any CPU
- {79255A92-ED00-40BA-9D64-12FCC664A976}.Proto|x86.ActiveCfg = Release|Any CPU
- {79255A92-ED00-40BA-9D64-12FCC664A976}.Proto|x86.Build.0 = Release|Any CPU
- {79255A92-ED00-40BA-9D64-12FCC664A976}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {79255A92-ED00-40BA-9D64-12FCC664A976}.Release|Any CPU.Build.0 = Release|Any CPU
- {79255A92-ED00-40BA-9D64-12FCC664A976}.Release|x86.ActiveCfg = Release|Any CPU
- {79255A92-ED00-40BA-9D64-12FCC664A976}.Release|x86.Build.0 = Release|Any CPU
+ {20B7BC36-CF51-4D75-9E13-66681C07977F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {20B7BC36-CF51-4D75-9E13-66681C07977F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {20B7BC36-CF51-4D75-9E13-66681C07977F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {20B7BC36-CF51-4D75-9E13-66681C07977F}.Debug|x86.Build.0 = Debug|Any CPU
+ {20B7BC36-CF51-4D75-9E13-66681C07977F}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {20B7BC36-CF51-4D75-9E13-66681C07977F}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {20B7BC36-CF51-4D75-9E13-66681C07977F}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {20B7BC36-CF51-4D75-9E13-66681C07977F}.Proto|x86.Build.0 = Debug|Any CPU
+ {20B7BC36-CF51-4D75-9E13-66681C07977F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {20B7BC36-CF51-4D75-9E13-66681C07977F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {20B7BC36-CF51-4D75-9E13-66681C07977F}.Release|x86.ActiveCfg = Release|Any CPU
+ {20B7BC36-CF51-4D75-9E13-66681C07977F}.Release|x86.Build.0 = Release|Any CPU
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2}.Debug|x86.Build.0 = Debug|Any CPU
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2}.Proto|x86.Build.0 = Debug|Any CPU
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2}.Release|x86.ActiveCfg = Release|Any CPU
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2}.Release|x86.Build.0 = Release|Any CPU
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F}.Debug|x86.Build.0 = Debug|Any CPU
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F}.Proto|x86.Build.0 = Debug|Any CPU
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F}.Release|x86.ActiveCfg = Release|Any CPU
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F}.Release|x86.Build.0 = Release|Any CPU
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768}.Debug|x86.Build.0 = Debug|Any CPU
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768}.Proto|x86.Build.0 = Debug|Any CPU
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768}.Release|x86.ActiveCfg = Release|Any CPU
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768}.Release|x86.Build.0 = Release|Any CPU
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4}.Debug|x86.Build.0 = Debug|Any CPU
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4}.Proto|x86.Build.0 = Debug|Any CPU
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4}.Release|x86.ActiveCfg = Release|Any CPU
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4}.Release|x86.Build.0 = Release|Any CPU
+ {44155269-9B30-43DA-B97F-4F36F887B211}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {44155269-9B30-43DA-B97F-4F36F887B211}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {44155269-9B30-43DA-B97F-4F36F887B211}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {44155269-9B30-43DA-B97F-4F36F887B211}.Debug|x86.Build.0 = Debug|Any CPU
+ {44155269-9B30-43DA-B97F-4F36F887B211}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {44155269-9B30-43DA-B97F-4F36F887B211}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {44155269-9B30-43DA-B97F-4F36F887B211}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {44155269-9B30-43DA-B97F-4F36F887B211}.Proto|x86.Build.0 = Debug|Any CPU
+ {44155269-9B30-43DA-B97F-4F36F887B211}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {44155269-9B30-43DA-B97F-4F36F887B211}.Release|Any CPU.Build.0 = Release|Any CPU
+ {44155269-9B30-43DA-B97F-4F36F887B211}.Release|x86.ActiveCfg = Release|Any CPU
+ {44155269-9B30-43DA-B97F-4F36F887B211}.Release|x86.Build.0 = Release|Any CPU
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}.Debug|x86.Build.0 = Debug|Any CPU
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}.Proto|x86.Build.0 = Debug|Any CPU
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}.Release|x86.ActiveCfg = Release|Any CPU
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8}.Release|x86.Build.0 = Release|Any CPU
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8}.Debug|x86.Build.0 = Debug|Any CPU
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8}.Proto|x86.Build.0 = Debug|Any CPU
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8}.Release|x86.ActiveCfg = Release|Any CPU
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8}.Release|x86.Build.0 = Release|Any CPU
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE}.Debug|x86.Build.0 = Debug|Any CPU
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE}.Proto|x86.Build.0 = Debug|Any CPU
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE}.Release|x86.ActiveCfg = Release|Any CPU
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE}.Release|x86.Build.0 = Release|Any CPU
+ {0610FB97-7C15-422A-86FD-32335C6DF14D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0610FB97-7C15-422A-86FD-32335C6DF14D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0610FB97-7C15-422A-86FD-32335C6DF14D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0610FB97-7C15-422A-86FD-32335C6DF14D}.Debug|x86.Build.0 = Debug|Any CPU
+ {0610FB97-7C15-422A-86FD-32335C6DF14D}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {0610FB97-7C15-422A-86FD-32335C6DF14D}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {0610FB97-7C15-422A-86FD-32335C6DF14D}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {0610FB97-7C15-422A-86FD-32335C6DF14D}.Proto|x86.Build.0 = Debug|Any CPU
+ {0610FB97-7C15-422A-86FD-32335C6DF14D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0610FB97-7C15-422A-86FD-32335C6DF14D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0610FB97-7C15-422A-86FD-32335C6DF14D}.Release|x86.ActiveCfg = Release|Any CPU
+ {0610FB97-7C15-422A-86FD-32335C6DF14D}.Release|x86.Build.0 = Release|Any CPU
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}.Debug|x86.Build.0 = Debug|Any CPU
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}.Proto|x86.Build.0 = Debug|Any CPU
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}.Release|x86.ActiveCfg = Release|Any CPU
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2}.Release|x86.Build.0 = Release|Any CPU
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Debug|x86.Build.0 = Debug|Any CPU
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Proto|Any CPU.Build.0 = Debug|Any CPU
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Proto|x86.ActiveCfg = Debug|Any CPU
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Proto|x86.Build.0 = Debug|Any CPU
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Release|x86.ActiveCfg = Release|Any CPU
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -934,17 +997,15 @@ Global
{3F044931-FB83-4433-B934-AE66AB27B278} = {F7876C9B-FB6A-4EFB-B058-D6967DB75FB2}
{F7876C9B-FB6A-4EFB-B058-D6967DB75FB2} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
{F6DAEE9A-8BE1-4C4A-BC83-09215517C7DA} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
- {D086C8C6-D00D-4C3B-9AB2-A4286C9F5922} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
{35636A82-401A-4C3A-B2AB-EB7DC5E9C268} = {F7876C9B-FB6A-4EFB-B058-D6967DB75FB2}
{CCAB6E50-34C6-42AF-A6B0-567C29FCD91B} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
{991DCF75-C2EB-42B6-9A0D-AA1D2409D519} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
{2E4D67B4-522D-4CF7-97E4-BA940F0B18F3} = {3881429D-A97A-49EB-B7AE-A82BA5FE9C77}
{59ADCE46-9740-4079-834D-9A03A3494EBC} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
- {025CE01B-98F3-4C3C-B486-2C0BD038D011} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
{D5870CF0-ED51-4CBC-B3D7-6F56DA84AC06} = {B8DDA694-7939-42E3-95E5-265C2217C142}
{DED3BBD7-53F4-428A-8C9F-27968E768605} = {3058BC79-8E79-4645-B05D-48CC182FA8A6}
- {EE85AAB7-CDA0-4C4E-BDA0-A64CCC413E3F} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
- {1C5C163C-37EA-4A3C-8CCC-0D34B74BF8EF} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
+ {EE85AAB7-CDA0-4C4E-BDA0-A64CCC413E3F} = {CCAB6E50-34C6-42AF-A6B0-567C29FCD91B}
+ {1C5C163C-37EA-4A3C-8CCC-0D34B74BF8EF} = {CCAB6E50-34C6-42AF-A6B0-567C29FCD91B}
{65E0E82A-EACE-4787-8994-888674C2FE87} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
{B700E38B-F8C0-4E49-B5EC-DB7B7AC0C4E7} = {CCAB6E50-34C6-42AF-A6B0-567C29FCD91B}
{FCFB214C-462E-42B3-91CA-FC557EFEE74F} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
@@ -968,6 +1029,7 @@ Global
{649FA588-F02E-457C-9FCF-87E46407481E} = {B8DDA694-7939-42E3-95E5-265C2217C142}
{8B3E283D-B5FE-4055-9D80-7E3A32F3967B} = {B8DDA694-7939-42E3-95E5-265C2217C142}
{D0E98C0D-490B-4C61-9329-0862F6E87645} = {B8DDA694-7939-42E3-95E5-265C2217C142}
+ {60D275B0-B14A-41CB-A1B2-E815A7448FCB} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
{C163E892-5BF7-4B59-AA99-B0E8079C67C4} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
{A8D9641A-9170-4CF4-8FE0-6DB8C134E1B5} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
{88E2D422-6852-46E3-A740-83E391DC7973} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
@@ -979,7 +1041,6 @@ Global
{1FB1DD07-06AA-45B4-B5AC-20FF5BEE98B6} = {F6DAEE9A-8BE1-4C4A-BC83-09215517C7DA}
{4239EFEA-E746-446A-BF7A-51FCBAB13946} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
{2E60864A-E3FF-4BCC-810F-DC7C34E6B236} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
- {E7FA3A71-51AF-4FCA-9C2F-7C853E515903} = {D086C8C6-D00D-4C3B-9AB2-A4286C9F5922}
{C4586A06-1402-48BC-8E35-A1B8642F895B} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
{887630A3-4B1D-40EA-B8B3-2D842E9C40DB} = {35636A82-401A-4C3A-B2AB-EB7DC5E9C268}
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B} = {35636A82-401A-4C3A-B2AB-EB7DC5E9C268}
@@ -993,14 +1054,19 @@ Global
{E93E7D28-1C6B-4E04-BE83-68428CF7E039} = {6235B3AF-774D-4EA1-8F37-789E767F6368}
{9482211E-23D0-4BD0-9893-E4AA5559F67A} = {6235B3AF-774D-4EA1-8F37-789E767F6368}
{04C59F6E-1C76-4F6A-AC21-2EA7F296A1B8} = {647810D0-5307-448F-99A2-E83917010DAE}
- {BED74F9E-A0D2-48E2-9EE7-449832100487} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
- {1D8D778E-8D6B-4A8C-88A6-BE578988FBE8} = {BED74F9E-A0D2-48E2-9EE7-449832100487}
- {C32806E0-71C2-40E4-AEC4-517F73F6A18A} = {BED74F9E-A0D2-48E2-9EE7-449832100487}
- {7B345E51-F2C0-4D4B-B0E0-05432EC9D5E1} = {BED74F9E-A0D2-48E2-9EE7-449832100487}
- {8EC30B2E-F1F9-4A98-BBB5-DD0CF6C84DDC} = {647810D0-5307-448F-99A2-E83917010DAE}
- {60BAFFA5-6631-4328-B044-2E012AB76DCA} = {B8DDA694-7939-42E3-95E5-265C2217C142}
- {AAF2D233-1C38-4090-8FFA-F7C545625E06} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
- {79255A92-ED00-40BA-9D64-12FCC664A976} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
+ {20B7BC36-CF51-4D75-9E13-66681C07977F} = {B8DDA694-7939-42E3-95E5-265C2217C142}
+ {09F56540-AFA5-4694-B7A6-0DBF6D4618C2} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
+ {DFA30881-C0B1-4813-B087-C21B5AF9B77F} = {3881429D-A97A-49EB-B7AE-A82BA5FE9C77}
+ {AF7AE565-E1C4-4A24-BD4B-D7983FC84768} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
+ {AA259A37-418F-4E18-87B2-C7D5F8C26CC4} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
+ {12EF27FD-A34B-4373-860A-F9FCE9651859} = {4C7B48D7-19AF-4AE7-9D1D-3BB289D5480D}
+ {44155269-9B30-43DA-B97F-4F36F887B211} = {12EF27FD-A34B-4373-860A-F9FCE9651859}
+ {B53D9D05-8EF7-43A6-9A5B-0B113CBC54F8} = {12EF27FD-A34B-4373-860A-F9FCE9651859}
+ {2937CBEC-262D-4C94-BE1D-291FAB72E3E8} = {12EF27FD-A34B-4373-860A-F9FCE9651859}
+ {C2F38485-5F87-4986-985B-55D7ED96D5CE} = {3881429D-A97A-49EB-B7AE-A82BA5FE9C77}
+ {0610FB97-7C15-422A-86FD-32335C6DF14D} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
+ {B5A9BBD9-2F45-4722-A6CA-BAE3C64CD4E2} = {3058BC79-8E79-4645-B05D-48CC182FA8A6}
+ {14F3D3D6-5C8E-43C2-98A2-17EA704D4DEA} = {CFE3259A-2D30-4EB0-80D5-E8B5F3D01449}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {48EDBBBE-C8EE-4E3C-8B19-97184A487B37}
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 87306e5c604..4f50708c392 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1,14 +1,49 @@
# CI and PR triggers
trigger:
-- master
-- dev16.1
-- feature/*
-- release/*
+ branches:
+ include:
+ - main
+ - dev16.1
+ - feature/*
+ - release/*
+ paths:
+ include:
+ - '*'
+ exclude:
+ - .github/*
+ - docs/compiler-guide.md
+ - attributions.md
+ - CODE_OF_CONDUCT.md
+ - DEVGUIDE.md
+ - INTERNAL.md
+ - Language-Version-History.md
+ - License.txt
+ - README.md
+ - release-notes.md
+ - TESTGUIDE.md
+
pr:
-- master
-- dev16.1
-- feature/*
-- release/*
+ branches:
+ include:
+ - main
+ - dev16.1
+ - feature/*
+ - release/*
+ paths:
+ include:
+ - '*'
+ exclude:
+ - .github/*
+ - docs/compiler-guide.md
+ - attributions.md
+ - CODE_OF_CONDUCT.md
+ - DEVGUIDE.md
+ - INTERNAL.md
+ - Language-Version-History.md
+ - License.txt
+ - README.md
+ - release-notes.md
+ - TESTGUIDE.md
variables:
- name: _TeamName
@@ -21,6 +56,13 @@ variables:
value: .NETCore
- name: VisualStudioDropName
value: Products/$(System.TeamProject)/$(Build.Repository.Name)/$(Build.SourceBranchName)/$(Build.BuildNumber)
+ - name: LegacyDotNetSdkVersion
+ value: 3.1.405
+ - name: DotNetSdkVersion
+ value: '5.0.100'
+ - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}:
+ - name: RunningAsPullRequest
+ value: true
# Variables defined in yml cannot be overridden at queue time; instead overridable variables must be defined in the web UI.
# Commenting out until something like this is supported: https://github.com/Microsoft/azure-pipelines-yaml/pull/129
@@ -28,285 +70,460 @@ variables:
#- name: SkipTests
# defaultValue: false
-jobs:
+stages:
+- stage: build
+ displayName: Build
+ jobs:
-#---------------------------------------------------------------------------------------------------------------------#
-# Signed build #
-#---------------------------------------------------------------------------------------------------------------------#
-- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - template: /eng/common/templates/jobs/jobs.yml
- parameters:
- enableMicrobuild: true
- enablePublishBuildArtifacts: true
- enablePublishTestResults: false
- enablePublishBuildAssets: true
- enablePublishUsingPipelines: $(_PublishUsingPipelines)
- enableTelemetry: true
- helixRepo: dotnet/fsharp
- jobs:
- - job: Full_Signed
- pool:
- name: NetCoreInternal-Int-Pool
- queue: buildpool.windows.10.amd64.vs2019
- timeoutInMinutes: 300
- variables:
- - group: DotNet-Blob-Feed
- - group: DotNet-Symbol-Server-Pats
- - name: _SignType
- value: Real
- - name: _DotNetPublishToBlobFeed
- value: true
- steps:
- - checkout: self
- clean: true
- - script: eng\CIBuild.cmd
- -configuration $(_BuildConfig)
- -prepareMachine
- -testAll
- -officialSkipTests $(SkipTests)
- /p:SignType=$(_SignType)
- /p:DotNetSignType=$(_SignType)
- /p:MicroBuild_SigningEnabled=true
- /p:OverridePackageSource=https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json
- /p:TeamName=$(_TeamName)
- /p:DotNetPublishBlobFeedKey=$(dotnetfeed-storage-access-key-1)
- /p:DotNetPublishBlobFeedUrl=https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json
- /p:DotNetPublishToBlobFeed=true
- /p:DotNetPublishUsingPipelines=$(_PublishUsingPipelines)
- /p:DotNetArtifactsCategory=$(_DotNetArtifactsCategory)
- /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
- /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
- /p:OfficialBuildId=$(BUILD.BUILDNUMBER)
- /p:PublishToSymbolServer=true
- /p:VisualStudioDropName=$(VisualStudioDropName)
- - task: PublishTestResults@2
- displayName: Publish Test Results
- inputs:
- testResultsFormat: 'NUnit'
- testResultsFiles: '*.xml'
- searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
- continueOnError: true
- condition: ne(variables['SkipTests'], 'true')
- - task: PublishBuildArtifacts@1
- displayName: Publish Test Logs
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)\artifacts\TestResults\$(_BuildConfig)'
- ArtifactName: 'Test Logs'
- publishLocation: Container
- continueOnError: true
- condition: ne(variables['SkipTests'], 'true')
- - task: PublishBuildArtifacts@1
- displayName: Publish Artifact Packages
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)\artifacts\packages\$(_BuildConfig)'
- ArtifactName: 'Packages'
- condition: succeeded()
- - task: PublishBuildArtifacts@1
- displayName: Publish Artifact VSSetup
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(_BuildConfig)\Insertion'
- ArtifactName: 'VSSetup'
- condition: succeeded()
- - task: PublishBuildArtifacts@1
- displayName: Publish Artifact Nightly
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(_BuildConfig)\VisualFSharpFull.vsix'
- ArtifactName: 'Nightly'
- condition: succeeded()
- - task: PublishBuildArtifacts@1
- displayName: Publish Artifact Symbols
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)\artifacts\SymStore\$(_BuildConfig)'
- ArtifactName: 'NativeSymbols'
- condition: succeeded()
+ #-------------------------------------------------------------------------------------------------------------------#
+ # Signed build #
+ #-------------------------------------------------------------------------------------------------------------------#
+ - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - template: /eng/common/templates/jobs/jobs.yml
+ parameters:
+ enableMicrobuild: true
+ enablePublishBuildArtifacts: true
+ enablePublishTestResults: false
+ enablePublishBuildAssets: true
+ enablePublishUsingPipelines: $(_PublishUsingPipelines)
+ enableTelemetry: true
+ helixRepo: dotnet/fsharp
+ jobs:
+ - job: Full_Signed
+ pool:
+ name: NetCoreInternal-Pool
+ queue: buildpool.windows.10.amd64.vs2019
+ timeoutInMinutes: 300
+ variables:
+ - group: DotNet-Blob-Feed
+ - group: DotNet-Symbol-Server-Pats
+ - group: DotNet-DevDiv-Insertion-Workflow-Variables
+ - name: _SignType
+ value: Real
+ - name: _DotNetPublishToBlobFeed
+ value: true
+ steps:
+ - checkout: self
+ clean: true
+ - task: UseDotNet@2
+ displayName: Add legacy .NET SDK
+ inputs:
+ packageType: sdk
+ version: $(LegacyDotNetSdkVersion)
+ installationPath: $(Agent.ToolsDirectory)/dotnet
+ - script: eng\CIBuild.cmd
+ -configuration $(_BuildConfig)
+ -prepareMachine
+ -testAll
+ -officialSkipTests $(SkipTests)
+ /p:SignType=$(_SignType)
+ /p:DotNetSignType=$(_SignType)
+ /p:MicroBuild_SigningEnabled=true
+ /p:OverridePackageSource=https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json
+ /p:TeamName=$(_TeamName)
+ /p:DotNetPublishBlobFeedKey=$(dotnetfeed-storage-access-key-1)
+ /p:DotNetPublishBlobFeedUrl=https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json
+ /p:DotNetPublishToBlobFeed=true
+ /p:DotNetPublishUsingPipelines=$(_PublishUsingPipelines)
+ /p:DotNetArtifactsCategory=$(_DotNetArtifactsCategory)
+ /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
+ /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
+ /p:OfficialBuildId=$(BUILD.BUILDNUMBER)
+ /p:PublishToSymbolServer=true
+ /p:VisualStudioDropName=$(VisualStudioDropName)
+ - script: .\tests\EndToEndBuildTests\EndToEndBuildTests.cmd -c $(_BuildConfig)
+ displayName: End to end build tests
+ - task: PublishTestResults@2
+ displayName: Publish Test Results
+ inputs:
+ testResultsFormat: 'NUnit'
+ testResultsFiles: '*.xml'
+ searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
+ continueOnError: true
+ condition: ne(variables['SkipTests'], 'true')
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Test Logs
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\TestResults\$(_BuildConfig)'
+ ArtifactName: 'Test Logs'
+ publishLocation: Container
+ continueOnError: true
+ condition: ne(variables['SkipTests'], 'true')
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Artifact Packages
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\packages\$(_BuildConfig)'
+ ArtifactName: 'Packages'
+ condition: succeeded()
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Artifact VSSetup
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(_BuildConfig)\Insertion'
+ ArtifactName: 'VSSetup'
+ condition: succeeded()
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Artifact Nightly
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(_BuildConfig)\VisualFSharpFull.vsix'
+ ArtifactName: 'Nightly'
+ condition: succeeded()
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Artifact Symbols
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\SymStore\$(_BuildConfig)'
+ ArtifactName: 'NativeSymbols'
+ condition: succeeded()
+ - task: ms-vseng.MicroBuildTasks.4305a8de-ba66-4d8b-b2d1-0dc4ecbbf5e8.MicroBuildUploadVstsDropFolder@1
+ displayName: Upload VSTS Drop
+ inputs:
+ DropName: $(VisualStudioDropName)
+ DropFolder: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(_BuildConfig)\Insertion'
+ AccessToken: $(dn-bot-devdiv-drop-rw-code-rw)
+ condition: succeeded()
-#---------------------------------------------------------------------------------------------------------------------#
-# PR builds #
-#---------------------------------------------------------------------------------------------------------------------#
-- ${{ if eq(variables['System.TeamProject'], 'public') }}:
- - template: /eng/common/templates/jobs/jobs.yml
- parameters:
- enableMicrobuild: true
- enablePublishBuildArtifacts: true
- enablePublishTestResults: false
- enablePublishBuildAssets: true
- enablePublishUsingPipelines: $(_PublishUsingPipelines)
- enableTelemetry: true
- helixRepo: dotnet/fsharp
- jobs:
+ #-------------------------------------------------------------------------------------------------------------------#
+ # PR builds #
+ #-------------------------------------------------------------------------------------------------------------------#
+ - ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ - template: /eng/common/templates/jobs/jobs.yml
+ parameters:
+ enableMicrobuild: true
+ enablePublishBuildArtifacts: true
+ enablePublishTestResults: false
+ enablePublishBuildAssets: true
+ enablePublishUsingPipelines: $(_PublishUsingPipelines)
+ enableTelemetry: true
+ helixRepo: dotnet/fsharp
+ jobs:
- # Windows
- - job: Windows
- pool:
- vmImage: windows-2019
- timeoutInMinutes: 120
- strategy:
- maxParallel: 4
- matrix:
- desktop_release:
- _configuration: Release
- _testKind: testDesktop
- coreclr_release:
- _configuration: Release
- _testKind: testCoreclr
- fsharpqa_release:
- _configuration: Release
- _testKind: testFSharpQA
- vs_release:
- _configuration: Release
- _testKind: testVs
- steps:
- - checkout: self
- clean: true
- - script: eng\CIBuild.cmd -configuration $(_configuration) -$(_testKind)
- displayName: Build / Test
- - task: PublishTestResults@2
- displayName: Publish Test Results
- inputs:
- testResultsFormat: 'NUnit'
- testResultsFiles: '*.xml'
- searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_configuration)'
- continueOnError: true
- condition: ne(variables['_testKind'], 'testFSharpQA')
- - task: PublishBuildArtifacts@1
- displayName: Publish Test Logs
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)\artifacts\TestResults\$(_configuration)'
- ArtifactName: 'Windows $(_configuration) $(_testKind) test logs'
- publishLocation: Container
- continueOnError: true
- condition: eq(variables['_testKind'], 'testFSharpQA')
+ # Windows
+ - job: Windows
+ pool:
+ vmImage: windows-latest
+ timeoutInMinutes: 120
+ strategy:
+ maxParallel: 4
+ matrix:
+ desktop_release:
+ _configuration: Release
+ _testKind: testDesktop
+ coreclr_release:
+ _configuration: Release
+ _testKind: testCoreclr
+ fsharpqa_release:
+ _configuration: Release
+ _testKind: testFSharpQA
+ vs_release:
+ _configuration: Release
+ _testKind: testVs
+ steps:
+ - checkout: self
+ clean: true
+ - task: UseDotNet@2
+ displayName: Add legacy .NET SDK
+ inputs:
+ packageType: sdk
+ version: $(LegacyDotNetSdkVersion)
+ installationPath: $(Agent.ToolsDirectory)/dotnet
+ - script: eng\CIBuild.cmd -configuration $(_configuration) -$(_testKind)
+ displayName: Build / Test
+ - task: PublishTestResults@2
+ displayName: Publish Test Results
+ inputs:
+ testResultsFormat: 'NUnit'
+ testResultsFiles: '*.xml'
+ searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_configuration)'
+ continueOnError: true
+ condition: ne(variables['_testKind'], 'testFSharpQA')
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Test Logs
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\artifacts\TestResults\$(_configuration)'
+ ArtifactName: 'Windows $(_configuration) $(_testKind) test logs'
+ publishLocation: Container
+ continueOnError: true
+ condition: eq(variables['_testKind'], 'testFSharpQA')
+ - 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 $(_testKind)'
+ publishLocation: Container
+ continueOnError: true
+ condition: failed()
- # Linux
- - job: Linux
- pool:
- vmImage: ubuntu-16.04
- variables:
- - name: _SignType
- value: Test
- steps:
- - checkout: self
- clean: true
- - script: ./eng/cibuild.sh --configuration $(_BuildConfig) --testcoreclr
- displayName: Build / Test
- - task: PublishTestResults@2
- displayName: Publish Test Results
- inputs:
- testResultsFormat: 'NUnit'
- testResultsFiles: '*.xml'
- searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
- continueOnError: true
- condition: always()
+ # Mock official build
+ - job: MockOfficial
+ pool:
+ vmImage: windows-latest
+ steps:
+ - checkout: self
+ clean: true
+ - pwsh: .\eng\MockBuild.ps1
+ displayName: Build with OfficialBuildId
- # MacOS
- - job: MacOS
- pool:
- vmImage: macOS-10.13
- variables:
- - name: _SignType
- value: Test
- steps:
- - checkout: self
- clean: true
- - script: ./eng/cibuild.sh --configuration $(_BuildConfig) --testcoreclr
- displayName: Build / Test
- - task: PublishTestResults@2
- displayName: Publish Test Results
- inputs:
- testResultsFormat: 'NUnit'
- testResultsFiles: '*.xml'
- searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
- continueOnError: true
- condition: always()
+ # Linux
+ - job: Linux
+ pool:
+ vmImage: ubuntu-latest
+ variables:
+ - name: _SignType
+ value: Test
+ steps:
+ - checkout: self
+ clean: true
+ - task: UseDotNet@2
+ displayName: Add legacy .NET SDK
+ inputs:
+ packageType: sdk
+ version: $(LegacyDotNetSdkVersion)
+ installationPath: $(Agent.ToolsDirectory)/dotnet
+ - script: ./eng/cibuild.sh --configuration $(_BuildConfig) --testcoreclr
+ displayName: Build / Test
+ - task: PublishTestResults@2
+ displayName: Publish Test Results
+ inputs:
+ testResultsFormat: 'NUnit'
+ testResultsFiles: '*.xml'
+ searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
+ 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 Linux'
+ publishLocation: Container
+ continueOnError: true
+ condition: failed()
- # Source Build Linux
- - job: SourceBuild_Linux
- pool:
- vmImage: ubuntu-16.04
- steps:
- - checkout: self
- clean: true
- - script: ./eng/cibuild.sh --configuration Release /p:DotNetBuildFromSource=true /p:FSharpSourceBuild=true
- displayName: Build
+ # MacOS
+ - job: MacOS
+ pool:
+ vmImage: macOS-latest
+ variables:
+ - name: _SignType
+ value: Test
+ steps:
+ - checkout: self
+ clean: true
+ - task: UseDotNet@2
+ displayName: Add legacy .NET SDK
+ inputs:
+ packageType: sdk
+ version: $(LegacyDotNetSdkVersion)
+ installationPath: $(Agent.ToolsDirectory)/dotnet
+ - script: ./eng/cibuild.sh --configuration $(_BuildConfig) --testcoreclr
+ displayName: Build / Test
+ - task: PublishTestResults@2
+ displayName: Publish Test Results
+ inputs:
+ testResultsFormat: 'NUnit'
+ testResultsFiles: '*.xml'
+ searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
+ 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 Mac'
+ publishLocation: Container
+ continueOnError: true
+ condition: failed()
- # Source Build Windows
- - job: SourceBuild_Windows
- pool:
- vmImage: windows-2019
- steps:
- - checkout: self
- clean: true
- - script: eng\CIBuild.cmd -configuration Release -noSign /p:DotNetBuildFromSource=true /p:FSharpSourceBuild=true
- displayName: Build
+ # End to end build
+ - job: EndToEndBuildTests
+ pool:
+ vmImage: windows-latest
+ steps:
+ - checkout: self
+ clean: true
+ - script: .\Build.cmd -c Release
+ - script: .\tests\EndToEndBuildTests\EndToEndBuildTests.cmd -c Release
+ displayName: End to end build tests
- # Up-to-date
- - job: UpToDate_Windows
- pool:
- vmImage: windows-2019
- steps:
- - checkout: self
- clean: true
- - task: PowerShell@2
- displayName: Run up-to-date build check
- inputs:
- filePath: eng\tests\UpToDate.ps1
- arguments: -configuration $(_BuildConfig) -ci -binaryLog
+ # Source Build Windows
+ - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
+ - job: SourceBuild_Windows
+ pool:
+ vmImage: windows-latest
+ steps:
+ - checkout: self
+ clean: true
+ - script: eng\CIBuild.cmd -configuration Release -noSign -prepareMachine -sourceBuild
+ displayName: Build
+ - task: PublishPipelineArtifact@1
+ displayName: Publish Logs
+ inputs:
+ targetPath: '$(Build.SourcesDirectory)/artifacts/log/Release'
+ artifactName: 'SourceBuild_Windows Logs'
+ continueOnError: true
+ condition: not(succeeded())
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Logs
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/Release'
+ ArtifactName: 'SourceBuild_Windows_Test'
+ publishLocation: Container
+ continueOnError: true
+ condition: not(succeeded())
-#---------------------------------------------------------------------------------------------------------------------#
-# FCS builds #
-#---------------------------------------------------------------------------------------------------------------------#
+ # Up-to-date - disabled due to it being flaky
+ #- job: UpToDate_Windows
+ # pool:
+ # vmImage: windows-latest
+ # steps:
+ # - checkout: self
+ # clean: true
+ # - task: PowerShell@2
+ # displayName: Run up-to-date build check
+ # inputs:
+ # filePath: eng\tests\UpToDate.ps1
+ # arguments: -configuration $(_BuildConfig) -ci -binaryLog
-- ${{ if eq(variables['System.TeamProject'], 'public') }}:
- - template: /eng/common/templates/jobs/jobs.yml
- parameters:
- enableMicrobuild: true
- enablePublishTestResults: false
- enablePublishBuildAssets: true
- enablePublishUsingPipelines: false
- enableTelemetry: true
- helixRepo: dotnet/fsharp
- jobs:
+ # Source Build Semi-Official
+ - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
+ - job: SourceBuild_Official
+ # used until https://github.com/dotnet/source-build/issues/1795 is fixed
+ pool:
+ name: NetCorePublic-Pool
+ queue: BuildPool.Ubuntu.1604.amd64.Open
+ timeoutInMinutes: 90
+ steps:
+ - checkout: self
+ clean: true
+ - script: ./eng/cibuild.sh --configuration Release --prepareMachine --docker --sourceBuild
+ displayName: Build
+ - task: PublishPipelineArtifact@1
+ displayName: Publish Logs
+ inputs:
+ targetPath: '$(Build.SourcesDirectory)/artifacts/log/Release'
+ artifactName: 'SourceBuild_Official Logs'
+ continueOnError: true
+ condition: not(succeeded())
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Logs
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/Release'
+ ArtifactName: 'SourceBuild_Official_Test'
+ publishLocation: Container
+ continueOnError: true
+ condition: not(succeeded())
- - job: Windows_FCS
- pool:
- vmImage: windows-2019
- variables:
- - name: _SignType
- value: Test
- steps:
- - checkout: self
- clean: true
- - script: fcs\build.cmd TestAndNuget
- displayName: Build / Test
- - task: PublishTestResults@2
- displayName: Publish Test Results
- inputs:
- testResultsFormat: 'NUnit'
- testResultsFiles: '*.xml'
- searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/Release'
- continueOnError: true
- condition: always()
+ # Plain build Windows
+ # Disabled until the Windows Proto compiler is coreclr
+ # - job: Plain_Build_Windows
+ # pool:
+ # vmImage: windows-latest
+ # variables:
+ # - name: _BuildConfig
+ # value: Debug
+ # steps:
+ # - checkout: self
+ # clean: true
+ # - script: .\Build.cmd
+ # displayName: Initial build
+ # - script: dotnet --list-sdks
+ # displayName: Report dotnet SDK versions
+ # - task: UseDotNet@2
+ # displayName: install SDK
+ # inputs:
+ # packageType: sdk
+ # version: $(DotNetSdkVersion)
+ # installationPath: $(Agent.ToolsDirectory)/dotnet
+ # - script: dotnet build .\FSharp.sln /bl:\"artifacts/log/$(_BuildConfig)/RegularBuild.binlog\"
+ # displayName: Regular rebuild
- - job: Linux_FCS
- pool:
- vmImage: ubuntu-16.04
- variables:
- - name: _SignType
- value: Test
- steps:
- - checkout: self
- clean: true
- - script: ./fcs/build.sh Build
- displayName: Build
+ # Plain build Linux
+ - job: Plain_Build_Linux
+ pool:
+ vmImage: ubuntu-latest
+ variables:
+ - name: _BuildConfig
+ value: Debug
+ steps:
+ - checkout: self
+ clean: true
+ - script: ./build.sh
+ displayName: Initial build
+ - script: dotnet --list-sdks
+ displayName: Report dotnet SDK versions
+ - task: UseDotNet@2
+ displayName: install SDK
+ inputs:
+ packageType: sdk
+ version: $(DotNetSdkVersion)
+ installationPath: $(Agent.ToolsDirectory)/dotnet
+ - script: dotnet build ./FSharp.sln /bl:\"artifacts/log/$(_BuildConfig)/RegularBuild.binlog\"
+ displayName: Regular rebuild
- - job: MacOS_FCS
- pool:
- vmImage: macOS-10.13
- variables:
- - name: _SignType
- value: Test
- steps:
- - checkout: self
- clean: true
- - script: ./fcs/build.sh Build
- displayName: Build
+ # Plain build Mac
+ - job: Plain_Build_MacOS
+ pool:
+ vmImage: macos-latest
+ variables:
+ - name: _BuildConfig
+ value: Debug
+ steps:
+ - checkout: self
+ clean: true
+ - script: ./build.sh
+ displayName: Initial build
+ - script: dotnet --list-sdks
+ displayName: Report dotnet SDK versions
+ - task: UseDotNet@2
+ displayName: install SDK
+ inputs:
+ packageType: sdk
+ version: $(DotNetSdkVersion)
+ installationPath: $(Agent.ToolsDirectory)/dotnet
+ - script: dotnet build ./FSharp.sln /bl:\"artifacts/log/$(_BuildConfig)/RegularBuild.binlog\"
+ displayName: Regular rebuild
+
+ # Arcade-powered source build
+ # turned off until https://github.com/dotnet/source-build/issues/1795 is fixed
+ # - template: /eng/common/templates/jobs/jobs.yml
+ # parameters:
+ # enablePublishUsingPipelines: true
+ # enablePublishBuildArtifacts: true
+ # enablePublishBuildAssets: true
+ # artifacts:
+ # publish:
+ # artifacts: true
+ # manifests: true
+ # runSourceBuild: true
+ # sourceBuildParameters:
+ # includeDefaultManagedPlatform: true
+
+#---------------------------------------------------------------------------------------------------------------------#
+# Post Build #
+#---------------------------------------------------------------------------------------------------------------------#
+- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - template: eng/common/templates/post-build/post-build.yml
+ parameters:
+ publishingInfraVersion: 3
+ # Symbol validation is not entirely reliable as of yet, so should be turned off until https://github.com/dotnet/arcade/issues/2871 is resolved.
+ enableSymbolValidation: false
+ # SourceLink improperly looks for generated files. See https://github.com/dotnet/arcade/issues/3069
+ enableSourceLinkValidation: false
+
+#---------------------------------------------------------------------------------------------------------------------#
+# VS Insertion #
+#---------------------------------------------------------------------------------------------------------------------#
+- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - template: eng/release/insert-into-vs.yml
+ parameters:
+ componentBranchName: refs/heads/release/dev16.9
+ insertTargetBranch: rel/d16.9
+ insertTeamEmail: fsharpteam@microsoft.com
+ insertTeamName: 'F#'
diff --git a/benchmarks/Benchmarks.sln b/benchmarks/Benchmarks.sln
deleted file mode 100644
index 3d490e60b8c..00000000000
--- a/benchmarks/Benchmarks.sln
+++ /dev/null
@@ -1,44 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.28407.52
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "CompilerServiceBenchmarks", "CompilerServiceBenchmarks\CompilerServiceBenchmarks.fsproj", "{9A3C565C-B514-4AE0-8B01-CA80E8453EB0}"
-EndProject
-Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Core", "..\src\fsharp\FSharp.Core\FSharp.Core.fsproj", "{DED3BBD7-53F4-428A-8C9F-27968E768605}"
-EndProject
-Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Compiler.Private", "..\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj", "{2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Proto|Any CPU = Proto|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {9A3C565C-B514-4AE0-8B01-CA80E8453EB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {9A3C565C-B514-4AE0-8B01-CA80E8453EB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {9A3C565C-B514-4AE0-8B01-CA80E8453EB0}.Proto|Any CPU.ActiveCfg = Release|Any CPU
- {9A3C565C-B514-4AE0-8B01-CA80E8453EB0}.Proto|Any CPU.Build.0 = Release|Any CPU
- {9A3C565C-B514-4AE0-8B01-CA80E8453EB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {9A3C565C-B514-4AE0-8B01-CA80E8453EB0}.Release|Any CPU.Build.0 = Release|Any CPU
- {DED3BBD7-53F4-428A-8C9F-27968E768605}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {DED3BBD7-53F4-428A-8C9F-27968E768605}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {DED3BBD7-53F4-428A-8C9F-27968E768605}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
- {DED3BBD7-53F4-428A-8C9F-27968E768605}.Proto|Any CPU.Build.0 = Debug|Any CPU
- {DED3BBD7-53F4-428A-8C9F-27968E768605}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {DED3BBD7-53F4-428A-8C9F-27968E768605}.Release|Any CPU.Build.0 = Release|Any CPU
- {2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Proto|Any CPU.ActiveCfg = Debug|Any CPU
- {2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Proto|Any CPU.Build.0 = Debug|Any CPU
- {2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {049A4D02-709F-418C-AD59-7FB0DBE956B1}
- EndGlobalSection
-EndGlobal
diff --git a/benchmarks/CompilerServiceBenchmarks/Program.fs b/benchmarks/CompilerServiceBenchmarks/Program.fs
deleted file mode 100644
index 201856e3f98..00000000000
--- a/benchmarks/CompilerServiceBenchmarks/Program.fs
+++ /dev/null
@@ -1,321 +0,0 @@
-open System
-open System.IO
-open System.Text
-open FSharp.Compiler.ErrorLogger
-open FSharp.Compiler.SourceCodeServices
-open FSharp.Compiler.Text
-open FSharp.Compiler.AbstractIL
-open FSharp.Compiler.AbstractIL.IL
-open FSharp.Compiler.AbstractIL.ILBinaryReader
-open Microsoft.CodeAnalysis.Text
-open BenchmarkDotNet.Attributes
-open BenchmarkDotNet.Running
-
-module private SourceText =
-
- open System.Runtime.CompilerServices
-
- let weakTable = ConditionalWeakTable()
-
- let create (sourceText: SourceText) =
-
- let sourceText =
- { new ISourceText with
-
- member __.Item with get index = sourceText.[index]
-
- member __.GetLineString(lineIndex) =
- sourceText.Lines.[lineIndex].ToString()
-
- member __.GetLineCount() =
- sourceText.Lines.Count
-
- member __.GetLastCharacterPosition() =
- if sourceText.Lines.Count > 0 then
- (sourceText.Lines.Count, sourceText.Lines.[sourceText.Lines.Count - 1].Span.Length)
- else
- (0, 0)
-
- member __.GetSubTextString(start, length) =
- sourceText.GetSubText(TextSpan(start, length)).ToString()
-
- member __.SubTextEquals(target, startIndex) =
- if startIndex < 0 || startIndex >= sourceText.Length then
- raise (ArgumentOutOfRangeException("startIndex"))
-
- if String.IsNullOrEmpty(target) then
- raise (ArgumentException("Target is null or empty.", "target"))
-
- let lastIndex = startIndex + target.Length
- if lastIndex <= startIndex || lastIndex >= sourceText.Length then
- raise (ArgumentException("Target is too big.", "target"))
-
- let mutable finished = false
- let mutable didEqual = true
- let mutable i = 0
- while not finished && i < target.Length do
- if target.[i] <> sourceText.[startIndex + i] then
- didEqual <- false
- finished <- true // bail out early
- else
- i <- i + 1
-
- didEqual
-
- member __.ContentEquals(sourceText) =
- match sourceText with
- | :? SourceText as sourceText -> sourceText.ContentEquals(sourceText)
- | _ -> false
-
- member __.Length = sourceText.Length
-
- member __.CopyTo(sourceIndex, destination, destinationIndex, count) =
- sourceText.CopyTo(sourceIndex, destination, destinationIndex, count)
- }
-
- sourceText
-
-type SourceText with
-
- member this.ToFSharpSourceText() =
- SourceText.weakTable.GetValue(this, Runtime.CompilerServices.ConditionalWeakTable<_,_>.CreateValueCallback(SourceText.create))
-
-[]
-module Helpers =
-
- let createProject name referencedProjects =
- let tmpPath = Path.GetTempPath()
- let file = Path.Combine(tmpPath, Path.ChangeExtension(name, ".fs"))
- {
- ProjectFileName = Path.Combine(tmpPath, Path.ChangeExtension(name, ".dll"))
- ProjectId = None
- SourceFiles = [|file|]
- OtherOptions =
- Array.append [|"--optimize+"; "--target:library" |] (referencedProjects |> Array.ofList |> Array.map (fun x -> "-r:" + x.ProjectFileName))
- ReferencedProjects =
- referencedProjects
- |> List.map (fun x -> (x.ProjectFileName, x))
- |> Array.ofList
- IsIncompleteTypeCheckEnvironment = false
- UseScriptResolutionRules = false
- LoadTime = DateTime()
- UnresolvedReferences = None
- OriginalLoadReferences = []
- ExtraProjectInfo = None
- Stamp = Some 0L (* set the stamp to 0L on each run so we don't evaluate the whole project again *)
- }
-
- let generateSourceCode moduleName =
- sprintf """
-module Benchmark.%s
-
-type %s =
-
- val X : int
-
- val Y : int
-
- val Z : int
-
-let function%s (x: %s) =
- let x = 1
- let y = 2
- let z = x + y
- z""" moduleName moduleName moduleName moduleName
-
-[]
-type CompilerService() =
-
- let mutable checkerOpt = None
-
- let mutable sourceOpt = None
-
- let parsingOptions =
- {
- SourceFiles = [|"TypeChecker.fs"|]
- ConditionalCompilationDefines = []
- ErrorSeverityOptions = FSharpErrorSeverityOptions.Default
- IsInteractive = false
- LightSyntax = None
- CompilingFsLib = false
- IsExe = false
- }
-
- let mutable assembliesOpt = None
-
- let readerOptions =
- {
- pdbDirPath = None
- ilGlobals = mkILGlobals ILScopeRef.Local
- reduceMemoryUsage = ReduceMemoryFlag.No
- metadataOnly = MetadataOnlyFlag.Yes
- tryGetMetadataSnapshot = fun _ -> None
- }
-
- []
- member __.Setup() =
- match checkerOpt with
- | None -> checkerOpt <- Some(FSharpChecker.Create(projectCacheSize = 200))
- | _ -> ()
-
- match sourceOpt with
- | None ->
- sourceOpt <- Some <| SourceText.From(File.OpenRead("""..\..\..\..\..\src\fsharp\TypeChecker.fs"""), Encoding.Default, SourceHashAlgorithm.Sha1, true)
- | _ -> ()
-
- match assembliesOpt with
- | None ->
- assembliesOpt <-
- System.AppDomain.CurrentDomain.GetAssemblies()
- |> Array.map (fun x -> (x.Location))
- |> Some
- | _ -> ()
-
- []
- member __.ParsingTypeCheckerFs() =
- match checkerOpt, sourceOpt with
- | None, _ -> failwith "no checker"
- | _, None -> failwith "no source"
- | Some(checker), Some(source) ->
- let results = checker.ParseFile("TypeChecker.fs", source.ToFSharpSourceText(), parsingOptions) |> Async.RunSynchronously
- if results.ParseHadErrors then failwithf "parse had errors: %A" results.Errors
-
- []
- member __.ParsingTypeCheckerFsSetup() =
- match checkerOpt with
- | None -> failwith "no checker"
- | Some(checker) ->
- checker.InvalidateAll()
- checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients()
- checker.ParseFile("dummy.fs", SourceText.ofString "dummy", parsingOptions) |> Async.RunSynchronously |> ignore
- ClearAllILModuleReaderCache()
-
- []
- member __.ILReading() =
- match assembliesOpt with
- | None -> failwith "no assemblies"
- | Some(assemblies) ->
- // We try to read most of everything in the assembly that matter, mainly types with their properties, methods, and fields.
- // CustomAttrs and SecurityDecls are lazy until you call them, so we call them here for benchmarking.
- assemblies
- |> Array.iter (fun (fileName) ->
- let reader = OpenILModuleReader fileName readerOptions
-
- let ilModuleDef = reader.ILModuleDef
-
- let ilAssemblyManifest = ilModuleDef.Manifest.Value
-
- ilAssemblyManifest.CustomAttrs |> ignore
- ilAssemblyManifest.SecurityDecls |> ignore
- ilAssemblyManifest.ExportedTypes.AsList
- |> List.iter (fun x ->
- x.CustomAttrs |> ignore
- )
-
- ilModuleDef.CustomAttrs |> ignore
- ilModuleDef.TypeDefs.AsArray
- |> Array.iter (fun ilTypeDef ->
- ilTypeDef.CustomAttrs |> ignore
- ilTypeDef.SecurityDecls |> ignore
-
- ilTypeDef.Methods.AsArray
- |> Array.iter (fun ilMethodDef ->
- ilMethodDef.CustomAttrs |> ignore
- ilMethodDef.SecurityDecls |> ignore
- )
-
- ilTypeDef.Fields.AsList
- |> List.iter (fun ilFieldDef ->
- ilFieldDef.CustomAttrs |> ignore
- )
-
- ilTypeDef.Properties.AsList
- |> List.iter (fun ilPropertyDef ->
- ilPropertyDef.CustomAttrs |> ignore
- )
- )
- )
-
- []
- member __.ILReadingSetup() =
- // With caching, performance increases an order of magnitude when re-reading an ILModuleReader.
- // Clear it for benchmarking.
- ClearAllILModuleReaderCache()
-
- member val TypeCheckFileWith100ReferencedProjectsOptions =
- createProject "MainProject"
- [ for i = 1 to 100 do
- yield
- createProject ("ReferencedProject" + string i) []
- ]
-
- member this.TypeCheckFileWith100ReferencedProjectsRun() =
- let options = this.TypeCheckFileWith100ReferencedProjectsOptions
- let file = options.SourceFiles.[0]
-
- match checkerOpt with
- | None -> failwith "no checker"
- | Some checker ->
- let parseResult, checkResult =
- checker.ParseAndCheckFileInProject(file, 0, SourceText.ofString (File.ReadAllText(file)), options)
- |> Async.RunSynchronously
-
- if parseResult.Errors.Length > 0 then
- failwithf "%A" parseResult.Errors
-
- match checkResult with
- | FSharpCheckFileAnswer.Aborted -> failwith "aborted"
- | FSharpCheckFileAnswer.Succeeded checkFileResult ->
-
- if checkFileResult.Errors.Length > 0 then
- failwithf "%A" checkFileResult.Errors
-
- []
- member this.TypeCheckFileWith100ReferencedProjectsSetup() =
- this.TypeCheckFileWith100ReferencedProjectsOptions.SourceFiles
- |> Seq.iter (fun file ->
- File.WriteAllText(file, generateSourceCode (Path.GetFileNameWithoutExtension(file)))
- )
-
- this.TypeCheckFileWith100ReferencedProjectsOptions.ReferencedProjects
- |> Seq.iter (fun (_, referencedProjectOptions) ->
- referencedProjectOptions.SourceFiles
- |> Seq.iter (fun file ->
- File.WriteAllText(file, generateSourceCode (Path.GetFileNameWithoutExtension(file)))
- )
- )
-
- this.TypeCheckFileWith100ReferencedProjectsRun()
-
- []
- member this.TypeCheckFileWith100ReferencedProjects() =
- // Because the checker's projectcachesize is set to 200, this should be fast.
- // If set to 3, it will be almost as slow as re-evaluating all project and it's projects references on setup; this could be a bug or not what we want.
- this.TypeCheckFileWith100ReferencedProjectsRun()
-
- []
- member this.TypeCheckFileWith100ReferencedProjectsCleanup() =
- this.TypeCheckFileWith100ReferencedProjectsOptions.SourceFiles
- |> Seq.iter (fun file ->
- try File.Delete(file) with | _ -> ()
- )
-
- this.TypeCheckFileWith100ReferencedProjectsOptions.ReferencedProjects
- |> Seq.iter (fun (_, referencedProjectOptions) ->
- referencedProjectOptions.SourceFiles
- |> Seq.iter (fun file ->
- try File.Delete(file) with | _ -> ()
- )
- )
-
- match checkerOpt with
- | None -> failwith "no checker"
- | Some(checker) ->
- checker.InvalidateAll()
- checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients()
- ClearAllILModuleReaderCache()
-
-[]
-let main argv =
- let _ = BenchmarkRunner.Run()
- 0
diff --git a/docs/compiler-guide.md b/docs/compiler-guide.md
new file mode 100644
index 00000000000..68831ec4beb
--- /dev/null
+++ b/docs/compiler-guide.md
@@ -0,0 +1,598 @@
+# F# compiler guide
+
+This guide discusses the F# compiler source code and implementation from a technical point of view.
+
+## Overview
+
+There are several artifacts involved in the development of F#:
+
+* The [F# compiler library](https://github.com/dotnet/fsharp/tree/master/src/fsharp/FSharp.Compiler.Private), called `FSharp.Compiler.Private`. Contains all logic for F# compilation - including parsing, syntax tree processing, typechecking, constraint solving, optimizations, IL importing, IL writing, pretty printing of F# constructs, and F# metadata format processing - and the F# compiler APIs for tooling.
+
+* The [F# compiler executable](https://github.com/dotnet/fsharp/tree/master/src/fsharp/fsc), called `fsc`, which is called as a console app. It sets the .NET GC into batch mode and then invokes `FSharp.Compiler.Private` with command-line arguments.
+
+* The [F# Core Library](https://github.com/dotnet/fsharp/tree/master/src/fsharp/FSharp.Core), called `FSharp.Core`. Contains all primitive F# types and logic for how they interact, core data structures and library functions for operating on them, structured printing logic, units of measure for scientific programming, core numeric functionality, F# quotations, F# type reflection logic, and asynchronous programming types and logic.
+
+* The [F# Interactive tool](https://github.com/dotnet/fsharp/tree/master/src/fsharp/fsi), called `fsi`. A REPL for F# that supports execution and pretty-printing of F# code and results, loading F# script files, referencing assemblies, and referencing packages from NuGet.
+
+* The [F# Compiler Service](https://github.com/dotnet/fsharp/tree/master/fcs), called `FSharp.Compiler.Service` or abbreviated to FCS. It is mostly identical to `FSharp.Compiler.Private`, but critically contains the "Expression API" that allows other environments to inspect and operate on type-checked F# expressions (such as transpiling F# code to a different runtime target).
+
+The `FSharp.Compiler.Private` is by far the largest of these components and contains nearly all logic that `fsc` and `fsi` use. It is the primary subject of this guide.
+
+## Resources for learning
+
+* Video: [Learn me some F# Compiler, an online chat with Vlad and Don](https://www.youtube.com/watch?v=-dKf15xSWPY)
+
+* Video: [Understanding the F# Optimizer, and online chat with Vlad and Don](https://www.youtube.com/watch?v=sfAe5lDue7k)
+
+## Key data formats and representations
+
+The following are the key data formats and internal data representations of the F# compiler code in its various configurations:
+
+* _Input source files_ Read as Unicode text, or binary for referenced assemblies.
+
+* _Input command-line arguments_ See [CompileOptions.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/CompileOptions.fs) for the full code implementing the arguments table. Command-line arguments are also accepted by the F# Compiler Service API in project specifications, and as optional input to F# Interactive.
+
+* _Tokens_, see [pars.fsy](https://github.com/dotnet/fsharp/blob/master/src/fsharp/pars.fsy), [lex.fsl](https://github.com/dotnet/fsharp/blob/master/src/fsharp/lex.fsl), [lexhelp.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/lexhelp.fs) and related files.
+
+* _Abstract Syntax Tree (AST)_, see [SyntaxTree.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/SyntaxTree.fs), the untyped syntax tree resulting from parsing.
+
+* _Typed Abstract Syntax Tree (Typed Tree)_, see [TypedTree.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/TypedTree.fs), [TypedTreeBasics.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/TypedTree.fs), [TypedTreeOps.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/TypedTreeOps.fs), and related files. The typed, bound syntax tree including both type/module definitions and their backing expressions, resulting from type checking and the subject of successive phases of optimization and representation change.
+
+* _Type checking context/state_, see for example [`TcState` in CompileOps.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/CompileOps.fsi) and its constituent parts, particularly `TcEnv` in [CheckExpressions.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/CheckExpressions.fsi) and `NameResolutionEnv` in [NameResolution.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/NameResolution.fsi). A set of tables representing the available names, assemblies etc. in scope during type checking, plus associated information.
+
+* _Abstract IL_, the output of code generation, then used for binary generation, and the input format when reading .NET assemblies, see [`ILModuleDef` in il.fs](https://github.com/dotnet/fsharp/blob/master/src/absil/il.fsi).
+
+* _The .NET Binary format_ (with added "pickled" F# Metadata resource), the final output of fsc.exe, see the ECMA 335 specification and the [ilread.fs](https://github.com/dotnet/fsharp/blob/master/src/absil/ilread.fs) and [ilwrite.fs](https://github.com/dotnet/fsharp/blob/master/src/absil/ilwrite.fs) binary reader/generator implementations. The added F# metadata is stored in a binary resource, see [TypedTreePickle.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/TypedTreePickle.fs).
+
+* _The incrementally emitted .NET reflection assembly,_ the incremental output of fsi.exe. See [ilreflect.fs](https://github.com/dotnet/fsharp/blob/master/src/absil/ilreflect.fs).
+
+## Key constructs and APIs for F# tooling
+
+The following are the most relevant parts of the F# compiler tooling, making up the "engine" and API surface area of `FSharp.Compiler.Service`.
+
+* The incremental project build engine state in [IncrementalBuild.fsi](https://github.com/fsharp/FSharp.Compiler.Service/tree/master/src/fsharp/service/IncrementalBuild.fsi)/[IncrementalBuild.fs](https://github.com/fsharp/FSharp.Compiler.Service/tree/master/src/fsharp/service/IncrementalBuild.fs), a part of the F# Compiler Service API.
+
+* The corresponding APIs wrapping and accessing these structures in the public-facing [`FSharp.Compiler.Service` API](https://github.com/dotnet/fsharp/tree/master/src/fsharp/service) and [Symbol API](https://github.com/dotnet/fsharp/tree/master/src/fsharp/symbols).
+
+* The [F# Compiler Service Operations Queue](fsharp-compiler-service-queue.md), the mechanism used to sequentially process requests that require semantic information.
+
+* The [F# Compiler Service Caches](fsharp-compiler-service-caches.md), the various caches maintained by an instance of an `FSharpChecker`.
+
+## Key compiler phases
+
+The following is a diagram of how different phases of F# compiler work:
+
+
+
+The following are the key phases and high-level logical operations of the F# compiler code in its various configurations:
+
+* _Basic lexing_. Produces a token stream from input source file text.
+
+* _White-space sensitive lexing_. Accepts and produces a token stream, augmenting per the F# Language Specification.
+
+* _Parsing_. Accepts a token stream and produces an AST per the grammar in the F# Language Specification.
+
+* _Resolving references_. For .NET SDK generally references are resolved explicitly by external tooling.
+ There is a legacy aspect to this if references use old .NET Framework references including for
+ scripting. See [ReferenceResolver.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/ReferenceResolver.fs) for the abstract definition of compiler reference resolution. See [LegacyMSBuildReferenceResolver.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/LegacyMSBuildReferenceResolver.fs) for reference resolution used by the .NET Framework F# compiler when running on .NET Framework. See [SimulatedMSBuildReferenceResolver.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/SimulatedMSBuildReferenceResolver.fs) when not using the .NET Framework F# compiler.
+ See [Microsoft.DotNet.DependencyManager](https://github.com/dotnet/fsharp/tree/master/src/fsharp/Microsoft.DotNet.DependencyManager) for reference resolution and package management used in `fsi`.
+
+* _Importing referenced .NET binaries_, see [import.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/import.fsi)/[import.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/import.fs). Accepts file references and produces a Typed Tree node for each referenced assembly, including information about its type definitions (and type forwarders if any).
+
+* _Importing referenced F# binaries and optimization information as Typed Tree data structures_, see [TypedTreePickle.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/TypedTreePickle.fs). Accepts binary data and produces Typed Tree nodes for each referenced assembly, including information about its type/module/function/member definitions.
+
+* _Sequentially type checking files_, see [CheckDeclarations.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/CheckDeclarations.fsi)/[CheckDeclarations.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/CheckDeclarations.fs). Accepts an AST plus a type checking context/state and produces new Typed Tree nodes
+ incorporated into an updated type checking state, plus additional Typed Tree Expression nodes used during code generation. A key part of this is
+ checking syntactic types and expressions, see [CheckExpressions.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/CheckDeclarations.fsi)/[CheckExpressions.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/CheckDeclarations.fs) including the state held across the checking of a file (see `TcFileState`) and the
+ environment active as we traverse declarations and expressions (see `TcEnv`).
+
+* _Pattern match compilation_, see [PatternMatchCompilation.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/PatternMatchCompilation.fsi)/[PatternMatchCompilation.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/PatternMatchCompilation.fs). Accepts a subset of checked Typed Tree nodes representing F# pattern matching and produces Typed Tree expressions implementing the pattern matching. Called during type checking as each construct involving pattern matching is processed.
+
+* _Constraint solving_, see [ConstraintSolver.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/ConstraintSolver.fsi)/[ConstraintSolver.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/ConstraintSolver.fs).A constraint solver state is maintained during type checking of a single file, and constraints are progressively asserted (i.e. added to this state). Fresh inference variables are generated and variables are eliminated (solved). Variables are also generalized at various language constructs, or explicitly declared, making them "rigid". Called during type checking as each construct is processed.
+
+* _Post-inference type checks_, see [PostInferenceChecks.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/PostInferenceChecks.fsi)/[PostInferenceChecks.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/PostInferenceChecks.fs). Called at the end of type checking/inference for each file. A range of checks that can only be enforced after type checking on a file is complete, such as analysis when using `byref<'T>` or other `IsByRefLike` structs.
+
+* _Quotation translation_, see [QuotationTranslator.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/QuotationTranslator.fsi)/[QuotationTranslator.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/QuotationTranslator.fs)/[QuotationPickler.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/QuotationPickler.fsi)/[QuotationPickler.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/QuotationPickler.fs). Generates the stored information for F# quotation nodes, generated from the Typed Tree expression structures of the F# compiler. Quotations are ultimately stored as binary data plus some added type references. "ReflectedDefinition" quotations are collected and stored in a single blob.
+
+* _Optimization phases_, primarily the "Optimize" (peephole/inlining) and "Top Level Representation" (lambda lifting) phases, see [Optimizer.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/Optimizer.fsi)/[Optimizer.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/Optimizer.fs) and [InnerLambdasToTopLevelFuncs.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/InnerLambdasToTopLevelFuncs.fsi)/[InnerLambdasToTopLevelFuncs.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/InnerLambdasToTopLevelFuncs.fs) and [LowerCallsAndSeqs.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/LowerCallsAndSeqs.fs). Each of these takes Typed Tree nodes for types and expressions and either modifies the nodes in place or produces new Typed Tree nodes. These phases are orchestrated in [CompileOptions.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/CompileOptions.fs)
+
+* _Code generation_, see [IlxGen.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/IlxGen.fsi)/[IlxGen.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/IlxGen.fs). Accepts Typed Tree nodes and produces Abstract IL nodes, sometimes applying optimizations.
+
+* _Abstract IL code rewriting_, see [EraseClosures.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/ilx/EraseClosures.fs) and
+ [EraseUnions.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/ilx/EraseUnions.fs). Eliminates some constructs by rewriting Abstract IL nodes.
+
+* _Binary emit_, see [ilwrite.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/absil/ilwrite.fsi)/[ilwrite.fs](https://github.com/dotnet/fsharp/blob/master/src/absil/ilwrite.fs).
+
+* _Reflection-Emit_, see [ilreflect.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/absil/ilreflect.fs).
+
+These and transformations used to build the following:
+
+* _The F# Compiler Service API_, see the [Symbol API](https://github.com/dotnet/fsharp/tree/master/src/fsharp/symbols) and [Service API](https://github.com/dotnet/fsharp/tree/master/src/fsharp/service)
+
+* _The F# Interactive Shell_, see [fsi.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/fsi/fsi.fs).
+
+* _The F# Compiler Shell_, see [fsc.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/fsc.fs) and [fscmain.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/fscmain.fs).
+
+## Tools to help work with the compiler
+
+* [sharplab.io](https://sharplab.io/) can be used to decompile code.
+
+* [fantomas-tools](https://fsprojects.github.io/fantomas-tools/#/ast) can be used to view the Untyped & Typed Abstract Syntax Tree.
+
+
+## Coding standards and idioms
+
+The compiler codebase uses various abbreviations. Here are some of the most common ones.
+
+| Abbreviation | Meaning |
+|:------------------------------|:-----------|
+| `ad` | Accessor domain, meaning the permissions the accessing code has to access other constructs |
+| `amap` | Assembly map, saying how to map IL references to F# CCUs |
+| `arg` | Argument (parameter) |
+| `argty` | Argument (parameter) type |
+| `arginfo` | Argument (parameter) metadata |
+| `ccu` | Reference to an F# compilation unit = an F# DLL (possibly including the DLL being compiled) |
+| `celem` | Custom attribute element |
+| `cenv` | Compilation environment. Means different things in different contexts, but usually a parameter for a singlecompilation state object being passed through a set of related functions in a single phase. The compilation state is often mutable. |
+| `cpath` | Compilation path, meaning A.B.C for the overall names containing a type or module definition |
+| `css` | Constraint solver state. |
+| `denv` | Display Environment. Parameters guiding the formatting of types |
+| `einfo` | An info object for an event (whether a .NET event, an F# event or a provided event) |
+| `e` | Expression |
+| `env` | Environment. Means different things in different contexts, but usually immutable state being passed and adjusted through a set of related functions in a single phase. |
+| `finfo` | An info object for a field (whether a .NET field or a provided field) |
+| `fref` | A reference to an ILFieldRef Abstract IL node for a field reference. Would normally be modernized to `ilFieldRef` |
+| `g` | The TcGlobals value |
+| `id` | Identifier |
+| `lid` | Long Identifier |
+| `m` | A source code range marker |
+| `mimpl` | IL interface method implementation |
+| `minfo` | An info object for a method (whet a .NET method, an F# method or a provided method) |
+| `modul` | a Typed Tree structure for a namespace or F# module |
+| `pat` | Pattern, a syntactic AST node representing part of a pattern in a pattern match |
+| `pinfo` | An info object for a property (whether a .NET property, an F# property or a provided property) |
+| `rfref` | Record or class field reference, a reference to a Typed Tree node for a record or class field |
+| `scoref` | The scope of a reference in IL metadata, either assembly, `.netmodule` or local |
+| `spat` | Simple Pattern, a syntactic AST node representing part of a pattern in a pattern match |
+| `tau` | A type with the "forall" nodes stripped off (i.e. the nodes which represent generic type parameters). Comes from the notation _𝛕_ used in type theory |
+| `tcref` | Type constructor reference (an `EntityRef`) |
+| `tinst` | Type instantiation |
+| `tpenv` | Type parameter environment, tracks the type parameters in scope during type checking |
+| `ty`, `typ` | Type, usually a Typed Tree type |
+| `tys`, `typs` | List of types, usually Typed Tree types |
+| `typar` | Type Parameter |
+| `tyvar` | Type Variable, usually referring to an IL type variable, the compiled form of an F# type parameter |
+| `ucref` | Union case reference, a reference to a Typed Tree node for a union case |
+| `vref` | Value reference, a reference to a Typed Tree node for a value |
+
+| Phase Abbreviation | Meaning |
+|:------------------------------|:-----------|
+| `Syn` | Abstract Syntax Tree |
+| `Tc` | Type-checker |
+| `IL` | Abstract IL = F# representation of .NET IL |
+| `Ilx` | Extended Abstract IL = .NET IL plus a coulpe of contructs that get erased |
+
+## Adding Error Messages
+
+Adding or adjusting errors emitted by the compiler is usually straightforward (though it can sometimes imply deeper compiler work). Here's the general process:
+
+1. Reproduce the compiler error or warning with the latest F# compiler built from the [F# compiler repository](https://github.com/dotnet/fsharp).
+2. Find the error code (such as `FS0020`) in the message.
+3. Use a search tool and search for a part of the message. You should find it in `FSComp.fs` with a title, such as `parsMissingTypeArgs`.
+4. Use another search tool or a tool like Find All References / Find Usages to see where it's used in the compiler source code.
+5. Set a breakpoint at the location in source you found. If you debug the compiler with the same steps, it should trigger the breakpoint you set. This verifies that the location you found is the one that emits the error or warning you want to improve.
+
+From here, you can either simply update the error test, or you can use some of the information at the point in the source code you identified to see if there is more information to include in the error message. For example, if the error message doesn't contain information about the identifier the user is using incorrectly, you may be able to include the name of the identifier based on data the compiler has available at that stage of compilation.
+
+If you're including data from user code in an error message, it's important to also write a test that verifies the exact error message for a given string of F# code.
+
+## Formatting User Text from Typed Tree items
+
+When formatting Typed Tree objects such as `TyconRef`s as text, you normally use either
+
+* The functions in the `NicePrint` module such as `NicePrint.outputTyconRef`. These take a `DisplayEnv` that records the context in which a type was referenced, for example, the open namespaces. Opened namespaces are not shown in the displayed output.
+
+* The `DisplayName` properties on the relevant object. This drops the `'n` text that .NET adds to the compiled name of a type, and uses the F#-facing name for a type rather than the compiled name for a type (for example, the name given in a `CompiledName` attribute).
+
+* The functions such as `Tastops.fullTextOfTyconRef`, used to show the full, qualified name of an item.
+
+When formatting "info" objects, see the functions in the `NicePrint` module.
+
+## Notes on displaying types
+
+When displaying a type, you will normally want to "prettify" the type first. This converts any remaining type inference variables to new, better user-friendly type variables with names like `'a`. Various functions prettify types prior to display, for example, `NicePrint.layoutPrettifiedTypes` and others.
+
+When displaying multiple types in a comparative way, for example, two types that didn't match, you will want to display the minimal amount of infomation to convey the fact that the two types are different, for example, `NicePrint.minimalStringsOfTwoTypes`.
+
+When displaying a type, you have the option of displaying the constraints implied by any type variables mentioned in the types, appended as `when ...`. For example, `NicePrint.layoutPrettifiedTypeAndConstraints`.
+
+## Processing large inputs
+
+The compiler accepts large inputs such as:
+
+* Large literals, such as `let str = "a1" + "a2" + ... + "a1000"`
+* Large array expressions
+* Large list expressions
+* Long lists of sequential expressions
+* Long lists of bindings, such as `let v1 = e1 in let v2 = e2 in ....`
+* Long sequences of `if .. then ... else` expressions
+* Long sequences of `match x with ... | ...` expressions
+* Combinations of these
+
+The compiler performs constant folding for large constants so there are no costs to using them at runtime. However, this is subject to a machine's stack size when compiling, leading to `StackOverflow` exceptions if those constants are very large. The same can be observed for certain kinds of array, list, or sequence expressions. This appears to be more prominent when compiling on macOS because macOS has a smaller stack size.
+
+Many sources of `StackOverflow` exceptions prior to F# 4.7 when processing these kinds of constructs were resolved by processing them on the heap via continuation passing techniques. This avoids filling data on the stack and appears to have negligible effects on overall throughout or memory usage of the compiler.
+
+Aside from array expressions, most of the previously-listed inputs are called "linear" expressions. This means that there is a single linear hole in the shape of expressions. For example:
+
+* `expr :: HOLE` (list expressions or other right-linear constructions)
+* `expr; HOLE` (sequential expressions)
+* `let v = expr in HOLE` (let expressions)
+* `if expr then expr else HOLE` (conditional expression)
+* `match expr with pat[vs] -> e1[vs] | pat2 -> HOLE` (for example, `match expr with Some x -> ... | None -> ...`)
+
+Processing these constructs with continuation passing is more difficult than a more "natural" approach that would use the stack.
+
+For example, consider the following contrived example:
+
+```fsharp
+and remapLinearExpr g compgen tmenv expr contf =
+ match expr with
+ | Expr.Let (bind, bodyExpr, m, _) ->
+ ...
+ // tailcall for the linear position
+ remapLinearExpr g compgen tmenvinner bodyExpr (contf << (fun bodyExpr' ->
+ ...))
+
+ | Expr.Sequential (expr1, expr2, dir, spSeq, m) ->
+ ...
+ // tailcall for the linear position
+ remapLinearExpr g compgen tmenv expr2 (contf << (fun expr2' ->
+ ...))
+
+ | LinearMatchExpr (spBind, exprm, dtree, tg1, expr2, sp2, m2, ty) ->
+ ...
+ // tailcall for the linear position
+ remapLinearExpr g compgen tmenv expr2 (contf << (fun expr2' -> ...))
+
+ | LinearOpExpr (op, tyargs, argsFront, argLast, m) ->
+ ...
+ // tailcall for the linear position
+ remapLinearExpr g compgen tmenv argLast (contf << (fun argLast' -> ...))
+
+ | _ -> contf (remapExpr g compgen tmenv e)
+
+and remapExpr (g: TcGlobals) (compgen:ValCopyFlag) (tmenv:Remap) expr =
+ match expr with
+ ...
+ | LinearOpExpr _
+ | LinearMatchExpr _
+ | Expr.Sequential _
+ | Expr.Let _ -> remapLinearExpr g compgen tmenv expr (fun x -> x)
+```
+
+The `remapExpr` operation becomes two functions, `remapExpr` (for non-linear cases) and `remapLinearExpr` (for linear cases). `remapLinearExpr` uses tailcalls for constructs in the `HOLE` positions mentioned previously, passing the result to the continuation.
+
+Some common aspects of this style of programming are:
+
+* The tell-tale use of `contf` (continuation function)
+* The processing of the body expression `e` of a let-expression is tail-recursive, if the next construct is also a let-expression.
+* The processing of the `e2` expression of a sequential-expression is tail-recursive
+* The processing of the second expression in a cons is tail-recursive
+
+The previous example is considered incomplete, because arbitrary _combinations_ of `let` and sequential expressions aren't going to be dealt with in a tail-recursive way. The compiler generally tries to do these combinations as well.
+
+## Code Optimizations
+
+Code optimizations are performed in [`Optimizer.fs`](https://github.com/dotnet/fsharp/blob/master/src/fsharp/Optimizer.fs), [`DetupleArgs.fs`](https://github.com/dotnet/fsharp/blob/master/src/fsharp/DetupleArgs.fs), [`InnerLambdasToTopLevelFuncs.fs`](https://github.com/dotnet/fsharp/blob/master/src/fsharp/InnerLambdasToTopLevelFuncs.fs) and [`LowerCallsAndSeqs.fs`](https://github.com/dotnet/fsharp/blob/master/src/fsharp/LowerCallsAndSeqs.fs).
+
+Some of the optimizations performed in [`Optimizer.fs`](https://github.com/dotnet/fsharp/blob/master/src/fsharp/Optimizer.fs) are:
+
+* Propagation of known values (constants, x = y, lambdas, tuples/records/union-cases of known values)
+* Inlining of known lambda values
+* Eliminating unused bindings
+* Eliminating sequential code when there is no side-effect
+* Eliminating switches when we determine definite success or failure of pattern matching
+* Eliminating getting fields from an immutable record/tuple/union-case of known value
+* Expansion of tuple bindings "let v = (x1,...x3)" to avoid allocations if it's not used as a first class value
+* Splitting large functions into multiple methods, especially at match cases, to avoid massive methods that take a long time to JIT
+* Removing tailcalls when it is determined that no code in the transitive closure does a tailcall nor recurses
+
+In [`DetupleArgs.fs`](https://github.com/dotnet/fsharp/blob/master/src/fsharp/DetupleArgs.fs), tuples at call sites are eliminated if possible. Concretely, functions that accept a tuple at all call sites are replaced by functions that accept each of the tuple's arguments individually. This may require inlining to activate.
+
+Considering the following example:
+
+```fsharp
+let max3 t =
+ let (x, y, z) = t
+ max x (max y z)
+
+max3 (1, 2, 3)
+```
+
+The `max3` function gets rewritten to simply accept three arguments, and depending on how it gets called it will either get inlined at the call site or called with 3 arguments instead of a new tuple. In either case, the tuple allocation is eliminated.
+
+However, sometimes this optimization is not applied unless a function is marked `inline`. Consider a more complicated case:
+
+```fsharp
+let rec runWithTuple t offset times =
+ let offsetValues x y z offset =
+ (x + offset, y + offset, z + offset)
+ if times <= 0 then
+ t
+ else
+ let (x, y, z) = t
+ let r = offsetValues x y z offset
+ runWithTuple r offset (times - 1)
+```
+
+The inner function `offsetValues` will allocate a new tuple when called. However, if `offsetValues` is marked as `inline` then it will no longer allocate a tuple.
+
+Currently, these optimizations are not applied to `struct` tuples or explicit `ValueTuple`s passed to a function. In most cases, this doesn't matter because the handling of `ValueTuple` is well-optimized and may be erased at runtime. However, in the previous `runWithTuple` function, the overhead of allocating a `ValueTuple` each call ends up being higher than the previous example with `inline` applied to `offsetValues`. This may be addressed in the future.
+
+In [`InnerLambdasToTopLevelFuncs.fs`](https://github.com/dotnet/fsharp/blob/master/src/fsharp/InnerLambdasToTopLevelFuncs.fs), inner functions and lambdas are analyzed and, if possible, rewritten into separate methods that do not require an `FSharpFunc` allocation.
+
+Consider the following implementation of `sumBy` on an F# list:
+
+```fsharp
+let sumBy f xs =
+ let rec loop xs acc =
+ match xs with
+ | [] -> acc
+ | x :: t -> loop t (f x + acc)
+ loop xs 0
+```
+
+The inner `loop` function is emitted as a separate static method named `loop@2` and incurs no overhead involved with allocatin an `FSharpFunc` at runtime.
+
+In [`LowerCallsAndSeqs.fs`](https://github.com/dotnet/fsharp/blob/master/src/fsharp/LowerCallsAndSeqs.fs), a few optimizations are performed:
+
+* Performs eta-expansion on under-applied values applied to lambda expressions and does a beta-reduction to bind any known arguments
+* Analyzes a sequence expression and translates it into a state machine so that operating on sequences doesn't incur significant closure overhead
+
+### Potential future optimizations: Better Inlining
+
+Consider the following example:
+
+```fsharp
+let inline f k = (fun x -> k (x + 1))
+let inline g k = (fun x -> k (x + 2))
+
+let res = (f << g) id 1 // 4
+```
+
+Intermediate values that inherit from `FSharpFunc` are allocated at the call set of `res` to support function composition, even if the functions are marked as `inline`. Currently, if this overhead needs removal, you need to rewrite the code to be more like this:
+
+```fsharp
+let f x = x + 1
+let g x = x + 2
+
+let res = id 1 |> g |> f // 4
+```
+
+The downside of course being that the `id` function can't propagate to composed functions, meaning the code is now different despite yielding the same result.
+
+More generally, any time a first-order function is passed as an argument to a second-order function, the first-order function is not inlined even if everything is marked as `inline`. This results in a performance penalty.
+
+## Compiler Startup Performance
+
+Compiler startup performance is a key factor affecting happiness of F# users. If the compiler took 10sec to start up, then far fewer people would use F#.
+
+On all platforms, the following factors affect startup performance:
+
+* Time to load compiler binaries. This depends on the size of the generated binaries, whether they are pre-compiled (for example, using NGEN or CrossGen), and the way the .NET implementation loads them.
+
+* Time to open referenced assemblies (for example, `mscorlib.dll`, `FSharp.Core.dll`) and analyze them for the types and namespaces defined. This depends particularly on whether this is correctly done in an on-demand way.
+
+* Time to process "open" declarations are the top of each file. Processing these declarations have been observed to take time in some cases of F# compilation.
+
+* Factors specific to the specific files being compiled.
+
+On Windows, the compiler delivered with Visual Studio currently uses NGEN to pre-compile `fsc`, `fsi`, and some assemblies used in Visual Studio tooling. For .NET Core, the CrossGen tool is used to accomplish the same thing. Visual Studio will use _delayed_ NGEN, meaning that it does not run NGEN on every binary up front. This means that F# compilation through Visual Studio may be slow for a few times before it gets NGENed.
+
+## Compiler Memory Usage
+
+Overall memory usage is a primary determinant of the usability of the F# compiler and instances of the F# compiler service. Overly high memory usage results in poor throughput (particularly due to increased GC times) and low user interface responsivity in tools such as Visual Studio or other editing environments. In some extreme cases, it can lead to Visual Studio crashing or another IDE becoming unusable due to constant paging from absurdly high memory usage. Luckily, these extreme cases are very rare.
+
+### Why memory usage matters
+
+When you do a single compilation to produce a binary, memory usage typically doesn't matter much. It's often fine to allocate a lot of memory because it will just be reclaimed after compilation is over.
+
+However, the F# compiler is not simply a batch process that accepts source code as input and produces an assembly as output. When you consider the needs of editor and project tooling in IDEs, the F# compiler is:
+
+* An engine that processes syntax trees and outputs data at various stages of compilation
+* A database of syntactic and semantic data about the code hosted in an IDE
+* A server process that accepts requests for syntactic and semantic information
+* An API layer for tools to request tooling-specific data (e.g., F# tooltip information)
+
+Thinking about the F# compiler in these ways makes performance far more complicated than just throughput of a batch compilation process.
+
+### Kinds of data processed and served in F# tooling
+
+The following tables are split into two categories: syntactic and semantic. They contain common kinds of information requested, the kind of data that is involved, and roughly how expensive the operation is.
+
+#### IDE actions based on syntax
+
+| Action | Data inspected | Data returned | Cost (S/M/L/XL) |
+|---------|---------------|---------------|-----------------|
+| Syntactic Classification | Current document's source text | Text span and classification type for each token in the document | S |
+| Breakpoint Resolution | Current document's syntax tree | Text span representing where breakpoing where resolve | S |
+| Debugging data tip info | Current document's source text | Text span representing the token being inspected | S |
+| Brace pair matching | Current document's source text | Text spans representing brace pairs that match in the input document | S |
+| "Smart" indentation | Current document's source text | Indentation location in a document | S |
+| Code fixes operating only on syntax | Current document's source text | Small text change for document | S |
+| XML doc template generation | Current document's syntax tree | Small (usually) text change for document | S |
+| Brace pair completion | Current line in a source document | Additional brace pair inserted into source text | S |
+| Souce document navigation (usually via dropdowns) | Current document's syntax tree | "Navigation Items" with optional child navigation items containing ranges in source code | S |
+| Code outlining | Current document's source text | Text spans representing blocks of F# code that are collapsable as a group | S - M |
+| Editor formatting | Current document's source text | New source text for the document | S - L |
+| Syntax diagnostics | Current document's source text | List of diagnostic data including the span of text corresponding to the diagnostic | S |
+| Global construct search and navigation | All syntax trees for all projects | All items that match a user's search pattern with spans of text that represent where a given item is located | S-L |
+
+You likely noticed that nearly all of the syntactical operations are marked `S`. Aside from extreme cases, like files with 50k lines or higher, syntax-only operations typically finish very quickly. In addition to being computationally inexpensive, they are also run asynchronously and free-threaded.
+
+Editor formatting is a bit of an exception. Most IDEs offer common commands for format an entire document, and although they also offer commands to format a given text selection, users typically choose to format the whole document. This means an entire document has to be inspected and potentially rewritten based on often complex rules. In practice this isn't bad when working with a document that has already been formatted, but it can be expensive for larger documents with strange stylistic choices.
+
+Most of the syntax operations require an entire document's source text or parse tree. It stands to reason that this could be improved by operating on a diff of a parse tree instead of the whole thing. This is likely a very complex thing to implement though, since none of the F# compiler infrastructure works in this way today.
+
+#### IDE actions based on semantics
+
+| Action | Data inspected | Data returned | Cost (S/M/L/XL) |
+|---------|---------------|---------------|-----------------|
+| Most code fixes | Current document's typecheck data | Set (1 or more) of suggested text replacements | S-M |
+| Semantic classification | Current document's typecheck data | Spans of text with semantic classification type for all constructs in a document | S-L |
+| Code lenses | Current document's typecheck data and top-level declarations (for showing signatures); graph of all projects that reference the current one (for showing references) | Signature data for each top-level construct; spans of text for each reference to a top-level construct with navigation information | S-XL |
+| Code generation / refactorings | Current document's typecheck data and/or current resolved symbol/symbols | Text replacement(s) | S-L |
+| Code completion | Current document's typecheck data and currently-resolved symbol user is typing at | List of all symbols in scope that are "completable" based on where completion is invoked | S-L |
+| Editor tooltips | Current document's typecheck data and resolved symbol where user invoked a tooltip | F# tooltip data based on inspecting a type and its declarations, then pretty-printing them | S-XL |
+| Diagnostics based on F# semantics | Current document's typecheck data | Diagnostic info for each symbol with diagnostics to show, including the range of text associated with the diagnostic | M-XL |
+| Symbol highlighting in a document | Current document's typecheck data and currently-resolved symbol where user's caret is located | Ranges of text representing instances of that symbol in the document | S-M |
+| Semantic navigation (for example, Go to Definition) | Current document's typecheck data and currently-resolved symbol where the user invoked navigation | Location of a symbol's declaration | S-M |
+| Rename | Graph of all projects that use the symbol that rename is triggered on and the typecheck data for each of those projects | List of all uses of all symbols that are to be renamed | S-XL |
+| Find all references | Graph of all projects that Find References is triggered on and the typecheck data for each of those projects | List of all uses of all symbols that are found | S-XL |
+| Unused value/symbol analysis | Typecheck data for the current document | List of all symbols that aren't a public API and are unused | S-M |
+| Unused `open` analysis | Typecheck data for the current document and all symbol data brought into scope by each `open` declaration | List of `open` declarations whose symbols it exposes aren't used in the current document | S-L |
+| Missing `open` analysis | Typecheck data for the current document, resolved symbol with an error, and list of available namespaces or modules | List of candidate namespaces or modules that can be opened | S-M |
+| Misspelled name suggestion analysis | Typecheck data for the current document and resolved symbol with an error | List of candidates that are in scope and best match the misspelled name based on a string distance algorithm | S-M |
+| Name simplification analysis | Typecheck data for the current document and all symbol data brought into scope by each `open` declaration | List of text changes available for any fully- or partially-qualified symbol that can be simplified | S-XL |
+
+You likely noticed that every cost associated with an action has a range. This is based on two factors:
+
+1. If the semantic data being operated on is cached
+2. How much semantic data must be processed for the action to be completed
+
+Most actions are `S` if they operate on cached data and the compiler determines that no data needs to be re-computed. The size of their range is influenced largely by the _kind_ of semantic operations each action has to do, such as:
+
+* Typechecking a single document and processing the resulting data
+* Typechecking a document and its containing project and then processing the resulting data
+* Resolving a single symbol in a document
+* Resolving the definition of a single symbol in a codebase
+* Inspecting all symbols brought into scope by a given `open` declaration
+* Inspecting all symbols in a document
+* Inspecting all symbols in all documents contained in a graph of projects
+
+For example, commands like Find All References and Rename can be cheap if a codebase is small, hence the lower bound being `S`. But if the symbol in question is used across many documents in a large project graph, they are very expensive because the entire graph must be crawled and all symbols contained in its documents must be inspected.
+
+In contrast, actions like highlighting all symbols in a document aren't terribly expensive even for very large file files. That's because the symbols to be inspected are ultimately only in a single document.
+
+Operations that use typecheck data execute on a single background thread (see [Reactor.fsi](https://github.com/dotnet/fsharp/blob/master/src/fsharp/service/Reactor.fsi)/[Reactor.fs](https://github.com/dotnet/fsharp/blob/master/src/fsharp/service/Reactor.fs)). Each operation is cancellable - for example, if you run an expensive Find All References but decide to do something else, the next action you take that requires semantic data will cancel the Find All References operation and start the one you requested.
+
+TODO for don --> why single-threaded? why no priority queue if can't be multithreaded?
+
+### Analyzing compiler memory usage
+
+In general, the F# compiler allocates a lot of memory. More than it needs to. However, most of the "easy" sources of allocations have been squashed out and what remains are many smaller sources of allocations. The remaining "big" pieces allocate as a result of their current architecture, so it isn't straightforward to address them.
+
+To analyze memory usage of F# tooling, you have two primary avenues:
+
+1. Take a process dump on your machine and analyze it with process dump analysis tools like [dotMemory](https://www.jetbrains.com/dotmemory/)
+2. Use a sampling tool like [PerfView](https://github.com/Microsoft/perfview) or [dotTrace](https://www.jetbrains.com/profiler/) to collect a trace of your system while you perform various tasks in an IDE, ideally for 60 seconds or more.
+
+#### Analyzing a process dump file
+
+Process dump files are extremely information-rich data files that can be used to see the distribution of memory usage across various types. Tools like [dotMemory](https://www.jetbrains.com/dotmemory/) will show these distributions and intelligently group things to help identify the biggest areas worth improving. Additionally, they will notice things like duplicate strings and sparse arrays, which are often great ways to improve memory usage since it means more memory is being used than is necessary.
+
+As of F# 5, one of the most prominent sources of memory usage is `ILModuleReader`, often making up more than 20% of total memory usage for a given session. There is a considerably large "long tail" of small chunks of memory usage that in aggreate add up to a lot of resource utilization. Many can be improved.
+
+#### Analyzing a sample trace of IDE usage
+
+The other important tool to understand memory and CPU usage for a given sample of IDE usage is a trace file. These are collected and analyzed by tools like [PerfView](https://github.com/Microsoft/perfview) and [dotTrace](https://www.jetbrains.com/profiler/).
+
+When analyzing a trace, there are a few things to look out for:
+
+1. Overall GC statistics for the sample to give an overall picture of what was going on in the IDE for your sample:
+ a. How much CPU time was spent in the GC as a percentage of total CPU time for the IDE process?
+ b. What was the peak working set (total memory usage)?
+ c. What was the peak allocations per second?
+ d. How many allocations were Gen0? Gen1? Gen2?
+2. Memory allocations for the sample, typically also ignoring object deaths:
+ a. Is `LargeObject` showing up anywhere prominently? If so, that's a problem!
+ b. Which objects show up highest on the list? Does their presence that high make sense?
+ c. For a type such as `System.String`, which caller allocates it the most? Can that be improved?
+3. CPU sampling data, sorted by most CPU time
+ a. Are any methods showing up that correspond with high memory allocations? Something showing up prominently in both places is often a sign that it needs work!
+
+After analyzing a trace, you should have a good idea of places that could see improvement. Often times a tuple can be made into a struct tuple, or some convenient string processing could be adjusted to use a `ReadonlySpan<'T>` or turned into a more verbose loop that avoids allocations.
+
+### The cross-project references problem
+
+The compiler is generally built to compile one assembly: the assumption that the compiler is compiling one assembly is baked into several aspects of the design of the Typed Tree.
+
+In contract, FCS supports compiling a graph of projects, each for a different assembly. The Typed Tree nodes are **not** shared between different project compilations. This means that representation of project references is roughly O(n^2) in memory usage. In practice it's not strictly O(n^2), but for very large codebases the proportionality is felt.
+
+Some key things to understand are:
+
+* The `RawFSharpAssemblyData` is the data blob that would normally be stuffed in the F# resource in the generated DLL in a normal compilation. That's the "output" of checking each project.
+
+* This is used as "input" for the assembly reference of each consuming project (instead of an on-disk DLL)
+
+* Within each consuming project that blob is then resurrected to Typed Tree nodes in `TypedTreePickle.fs`.
+
+The biggest question is: could the compiler share this data across projects? In theory, yes. In practice, it's very tricky business.
+
+From a correctness point of view: the process of generating this blob (TypedTreePickle `p_XYZ`) and resurrecting it (TypedTreePickle `u_*`) does some transformations to the Typed Tree that are necessary for correctness of compilation, for example, [in `TypedTreePickle`](https://github.com/dotnet/fsharp/blob/master/src/fsharp/TypedTreePickle.fs#L737). Basically, the Typed Tree nodes from the compilation of one assembly are _not_ valid when compiling a different assembly.
+
+The Typed Tree nodes include `CcuData` nodes, which have access to a number of callbacks into the `TcImports` compilation context for the assembly being compiled. TypedTree nodes are effectively tied to a particular compilation of a particular assembly due to this.
+
+There isn't any way to share this data without losing correctness and invalidating many invariants held in the current design.
+
+From a lifetime point of view: the Typed Tree nodes are tied together in a graph, so sharing one or two of them might drag across the entire graph and extend lifetimes of that graph. None of these interrelated nodes were designed to be shared across assemblies.
+
+## `eventually` computations
+
+Some parts of the F# codebase (specifically, the type checker) are written using `eventually` computation expressions. These define resumption-like computations which can be time-sliced, suspended or discarded at "bind" points.
+
+This is done to ensure that long-running type-checking and other computations in the F# Compiler Service can be interrupted and cancelled. The documentation of the [F# Compiler Service Operations Queue](fsharp-compiler-service-queue.md) covers some aspects of this.
+
+When compiling code with `fsc` or executing code with `fsi`, these computations are not time-sliced and simply run synchronously and without interruption (unless the user requests it).
+
+TODO for don --> is the below stuff still accurate?
+
+Instances of the F# compiler service use time slicing for two things:
+
+1. The low-priority computations of the reactor thread (i.e. the background typechecking of the incremental builder)
+2. The typechecking phase of TypeCheckOneFile which are high-priority computations on the reactor thread.
+
+The first can be interrupted by having the incremental builder dependency graph
+(see [IncrementalBuild.fsi](https://github.com/fsharp/FSharp.Compiler.Service/tree/master/src/fsharp/service/IncrementalBuild.fsi)/[IncrementalBuild.fs](https://github.com/fsharp/FSharp.Compiler.Service/tree/master/src/fsharp/service/IncrementalBuild.fs))
+decide not to bother continuing with the computation (it drops it on the floor)
+
+The second can be interrupted via having `isResultObsolete` to the F# Compiler Service API return true.
+
+### The F# Compiler Service Public Surface Area
+
+The "intended" FCS API is the parts under the namespaces
+
+* FSharp.Compiler.SourceCodeServices.* (analysis, compilation, tooling, lexing)
+* FSharp.Compiler.Interactive.Shell.* (scripting support)
+* FSharp.Compiler.AbstractIL.* (for ILAssemblyReader hook for Rider)
+* FSharp.Compiler.SyntaxTree.* (direct access to full untyped tree)
+
+These sections are generally designed with F#/.NET design conventions (e.g. types in namespaces, not modules, no nesting of modules etc.)
+and we will continue to iterate to make this so.
+
+In contrast, the public parts of the compiler directly under `FSharp.Compiler.*` and `FSharp.AbstractIL.*` are
+"incidental" and not really designed for public use apart from the hook for Jet Brains Rider
+(Aside: In theory all these other parts could be renamed to FSharp.Compiler.Internal though there's no need to do that right now).
+These internal parts tend to be implemented with the "module containing lots of stuff in one big file" approach for layers of the compiler.
+
+
+### The F# Compiler Service Operations Queue
+
+See [F# Compiler Service Queue](fsharp-compiler-service-queue.md).
+
+### The F# Compiler Service Caches
+
+See [F# Compiler Service Caches](fsharp-compiler-service-caches.md).
+
+## Bootstrapping
+
+The F# compiler is boostrapped. That is, an existing F# compiler is used to build a "proto" compiler from the current source code. That "proto" compiler is then used to compile itself, producing a "final" compiler. This ensures the final compiler is compiled with all relevant optimizations and fixes.
+
+## FSharp.Build
+
+`FSharp.Build.dll` and `Microsoft.FSharp.targets` give MSBuild support for F# projects (`.fsproj`) and contain the. Although not strictly part of the F# compiler, they are essential for using F# in all contexts for .NET, aside from some more targeted scripting scenarios. The targets expose things like the `CoreCompile` and `Fsc` tasks called by MSBuild.
+
+### Attribution
+
+This document is based heavily on an [original document](http://fsharp.github.io/2015/09/29/fsharp-compiler-guide.html) published in 2015 by the [F# Software Foundation](http://fsharp.org).
diff --git a/fcs/docsrc/content/caches.fsx b/docs/fcs/caches.fsx
similarity index 96%
rename from fcs/docsrc/content/caches.fsx
rename to docs/fcs/caches.fsx
index a0a198896cb..442015bda58 100644
--- a/fcs/docsrc/content/caches.fsx
+++ b/docs/fcs/caches.fsx
@@ -1,5 +1,5 @@
(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
(**
Compiler Services: Notes on the FSharpChecker caches
=================================================
@@ -9,7 +9,7 @@ This is a design note on the FSharpChecker component and its caches. See also t
Each FSharpChecker object maintains a set of caches. These are
* ``scriptClosureCache`` - an MRU cache of default size ``projectCacheSize`` that caches the
- computation of GetProjectOptionsFromScript. This computation can be lengthy as it can involve processing the transative closure
+ computation of GetProjectOptionsFromScript. This computation can be lengthy as it can involve processing the transitive closure
of all ``#load`` directives, which in turn can mean parsing an unbounded number of script files
* ``incrementalBuildersCache`` - an MRU cache of projects where a handle is being kept to their incremental checking state,
@@ -50,7 +50,7 @@ The sizes of some of these caches can be adjusted by giving parameters to FSharp
the cache sizes above indicate the "strong" size of the cache, where memory is held regardless of the memory
pressure on the system. Some of the caches can also hold "weak" references which can be collected at will by the GC.
-> Note: Because of these caches, uou should generally use one global, shared FSharpChecker for everything in an IDE application.
+> Note: Because of these caches, you should generally use one global, shared FSharpChecker for everything in an IDE application.
Low-Memory Condition
diff --git a/docs/fcs/compiler.fsx b/docs/fcs/compiler.fsx
new file mode 100644
index 00000000000..67885abf88f
--- /dev/null
+++ b/docs/fcs/compiler.fsx
@@ -0,0 +1,101 @@
+(*** hide ***)
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+Hosted Compiler
+===============
+
+This tutorial demonstrates how to host the F# compiler.
+
+> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published
+*)
+
+(**
+> **NOTE:** There are several options for hosting the F# compiler. The easiest one is to use the
+`fsc.exe` process and pass arguments.
+*)
+
+(**
+
+> **NOTE:** By default [compilations using FSharp.Compiler.Service reference FSharp.Core 4.3.0.0](https://github.com/fsharp/FSharp.Compiler.Service/issues/156) (matching F# 3.0). You can override
+this choice by passing a reference to FSharp.Core for 4.3.1.0 or later explicitly in your command-line arguments.
+
+*)
+
+(**
+---------------------------
+
+First, we need to reference the libraries that contain F# interactive service:
+*)
+
+#r "FSharp.Compiler.Service.dll"
+open System.IO
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+
+// Create an interactive checker instance
+let checker = FSharpChecker.Create()
+
+(**
+Now write content to a temporary file:
+
+*)
+let fn = Path.GetTempFileName()
+let fn2 = Path.ChangeExtension(fn, ".fsx")
+let fn3 = Path.ChangeExtension(fn, ".dll")
+
+File.WriteAllText(fn2, """
+module M
+
+type C() =
+ member x.P = 1
+
+let x = 3 + 4
+""")
+
+(**
+Now invoke the compiler:
+*)
+
+let errors1, exitCode1 =
+ checker.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |])
+ |> Async.RunSynchronously
+
+(**
+
+If errors occur you can see this in the 'exitCode' and the returned array of errors:
+
+*)
+File.WriteAllText(fn2, """
+module M
+
+let x = 1.0 + "" // a type error
+""")
+
+let errors1b, exitCode1b =
+ checker.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |])
+ |> Async.RunSynchronously
+
+(**
+
+Compiling to a dynamic assembly
+===============================
+
+You can also compile to a dynamic assembly, which uses the F# Interactive code generator.
+This can be useful if you are, for example, in a situation where writing to the file system
+is not really an option.
+
+You still have to pass the "-o" option to name the output file, but the output file is not actually written to disk.
+
+The 'None' option indicates that the initialization code for the assembly is not executed.
+*)
+let errors2, exitCode2, dynAssembly2 =
+ checker.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], execute=None)
+ |> Async.RunSynchronously
+
+(*
+Passing 'Some' for the 'execute' parameter executes the initialization code for the assembly.
+*)
+let errors3, exitCode3, dynAssembly3 =
+ checker.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], Some(stdout,stderr))
+ |> Async.RunSynchronously
+
diff --git a/docs/fcs/corelib.fsx b/docs/fcs/corelib.fsx
new file mode 100644
index 00000000000..cfcdba13557
--- /dev/null
+++ b/docs/fcs/corelib.fsx
@@ -0,0 +1,90 @@
+(*** hide ***)
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+Compiler Services: Notes on FSharp.Core.dll
+=================================================
+
+Versions of FSharp.Core involved in the operation of FSharp.Compiler.Service
+---------------------------------------------
+
+There are three versions of FSharp.Core relevant to the operation of FSharp.Compiler.Service:
+
+1. **The FSharp.Compiler.Service.dll static reference to FSharp.Core** - The FCS DLL and nuget have a static minbound dependency on FSharp.Core.
+
+ This is just a normal .NET dependency like any other, it expresses the minimum surface area of FSharp.Core that the implementation of FSharp.Compiler.Service (and any components that depend on it) needs. It could be a reference to a reference assembly if we supported that. In theory this could be very low and all is cool - if we could implement FCS in terms of FSharp.Core 2.0.0.0 then that could be the minbound (indeed in theory we could implement FCS pretty almost without any use of FSharp.Core functionality at all, though obviously we don't)
+
+ In practice this is 0-2 versions behind latest FSharp.Core.
+
+2. **The runtime reference to FSharp.Core in a tool, application or test suite that includes FSharp.Compiler.Service** - This is the actual version of FSharp.Core used when, say, fsc.exe or devenv.exe or fsi.exe or fsdocs.exe runs.
+
+ This must be at least as high as (1) and is usually the very latest FSharp.Core available (in or out of repo tree). This is important to the operation of the FCS-based tool because it is used for execution of scripts, and the default compilation reference for scripts. If scripts are going to use a particular language feature then this must be sufficient to support the language feature
+
+3. **The FSharp.Core reference in a compilation or analysis being processed by FSharp.Compiler.Service**.
+
+ This can be anything - 2.0.0.0, 4.0.0.0 or 5.0.0 or whatever. For script compilation and execution is is the same as (2). It must be sufficient to support language features used in the compilation.
+
+Shipping an FSharp.Core with your application
+---------------------------------------------
+
+When building applications or plug-in components which use FSharp.Compiler.Service.dll, you will normally also
+include a copy of FSharp.Core.dll as part of your application.
+
+For example, if you build a ``HostedCompiler.exe``, you will normally place an FSharp.Core.dll (say 4.3.1.0) alongside
+your ``HostedCompiler.exe``.
+
+
+Which FSharp.Core and .NET Framework gets referenced in compilation?
+--------------------------------------
+
+The FSharp.Compiler.Service component can be used to do more or less any sort of F# compilation.
+In particular you can reference an explicit FSharp.Core and/or framework
+assemblies in the command line arguments (different to the FSharp.Core and a .NET Framework being used to run your tool).
+
+To target a specific FSharp.Core and/or .NET Framework assemblies, use the ``--noframework`` argument
+and the appropriate command-line arguments:
+
+ []
+ let fsharpCorePath =
+ @"C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.1.0\FSharp.Core.dll"
+ let errors2, exitCode2 =
+ scs.Compile(
+ [| "fsc.exe"; "--noframework";
+ "-r"; fsharpCorePath;
+ "-r"; @"C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll";
+ "-o"; fn3;
+ "-a"; fn2 |])
+
+You will need to determine the location of these assemblies. The easiest way to locate these DLLs in a cross-platform way and
+convert them to command-line arguments is to [crack an F# project file](https://fsharp.github.io/FSharp.Compiler.Service/project.html).
+Alternatively you can compute SDK paths yourself, and some helpers to do this are in [the tests for FSharp.Compiler.Service.dll](https://github.com/fsharp/FSharp.Compiler.Service/blob/8a943dd3b545648690cb3bed652a469bdb6dd869/tests/service/Common.fs#L54).
+
+
+What about if I am processing a script or using ``GetCheckOptionsFromScriptRoot``
+-------------------------------------------------------------------------
+
+If you do _not_ explicitly reference an FSharp.Core.dll from an SDK location, or if you are processing a script
+using ``FsiEvaluationSession`` or ``GetCheckOptionsFromScriptRoot``, then an implicit reference to FSharp.Core will be made
+by the following choice:
+
+1. The version of FSharp.Core.dll statically referenced by the host assembly returned by ``System.Reflection.Assembly.GetEntryAssembly()``.
+
+2. If there is no static reference to FSharp.Core in the host assembly, then
+
+ - For FSharp.Compiler.Service 1.4.0.x above (F# 4.0 series), a reference to FSharp.Core version 4.4.0.0 is added
+
+Do I need to include FSharp.Core.optdata and FSharp.Core.sigdata?
+--------------------------------------
+
+No, unless you are doing something with very old FSharp.Core.dll.
+
+Summary
+-------
+
+In this design note we have discussed three things:
+
+- the versions of FSharp.Core relevant to the operation of FSharp.Compiler.Service.dll
+- which FSharp.Core.dll is used to run your compilation tools
+- how to configure binding redirects for the FSharp.Core.dll used to run your compilation tools
+- which FSharp.Core.dll and/or framework assemblies are referenced during the checking and compilations performed by your tools.
+
+*)
diff --git a/fcs/docsrc/content/devnotes.md b/docs/fcs/devnotes.md
similarity index 88%
rename from fcs/docsrc/content/devnotes.md
rename to docs/fcs/devnotes.md
index d086b577968..98684f9f358 100644
--- a/fcs/docsrc/content/devnotes.md
+++ b/docs/fcs/devnotes.md
@@ -20,7 +20,7 @@ This repo should be _identical_ to 'fsharp' except:
- No bootstrap or proto compiler is used - an installed F# compiler is assumed
- Build script using FAKE that builds everything, produces NuGet package and
- generates documentation, files for publising NuGet packages etc.
+ generates documentation, files for publishing NuGet packages etc.
(following [F# project scaffold](https://github.com/fsprojects/FSharp.ProjectScaffold))
- Changes to compiler source code to expose new functionality; Changes to the
@@ -30,7 +30,7 @@ This repo should be _identical_ to 'fsharp' except:
- Additions to compiler source code which add new functionality to the compiler service API
-If language or compiler addiitons are committed to `fsharp/fsharp`, they should be merged into
+If language or compiler additions are committed to `fsharp/fsharp`, they should be merged into
this repo and a new NuGet package released.
## Building and NuGet
@@ -54,4 +54,4 @@ Release checklist to publish a new version on nuget.org
1. Update `RELEASE_NOTES.md`
2. Check the version numbers are correct across the source (some files duplicate them)
3. Commit and add the necessary tag to the repo
-4. Publish the nupkgs for `FSharp.Compiler.Service` and `FSharp.Compiler.Service.ProjectCracker` once they appear in AppVeyor artifacts
+4. Publish the nupkgs for `FSharp.Compiler.Service` once it appears in AppVeyor artifacts
diff --git a/docs/fcs/editor.fsx b/docs/fcs/editor.fsx
new file mode 100644
index 00000000000..81820fa7304
--- /dev/null
+++ b/docs/fcs/editor.fsx
@@ -0,0 +1,251 @@
+(*** hide ***)
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+Compiler Services: Editor services
+==================================
+
+This tutorial demonstrates how to use the editor services provided by the F# compiler.
+This API is used to provide auto-complete, tool-tips, parameter info help, matching of
+brackets and other functions in F# editors including Visual Studio, Xamarin Studio and Emacs
+(see [fsharpbindings](https://github.com/fsharp/fsharpbinding) project for more information).
+Similarly to [the tutorial on using untyped AST](untypedtree.html), we start by
+getting the `InteractiveChecker` object.
+
+> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published
+
+
+Type checking sample source code
+--------------------------------
+
+As in the [previous tutorial (using untyped AST)](untypedtree.html), we start by referencing
+`FSharp.Compiler.Service.dll`, opening the relevant namespace and creating an instance
+of `InteractiveChecker`:
+
+*)
+// Reference F# compiler API
+#r "FSharp.Compiler.Service.dll"
+
+open System
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+
+// Create an interactive checker instance
+let checker = FSharpChecker.Create()
+
+(**
+
+As [previously](untypedtree.html), we use `GetProjectOptionsFromScriptRoot` to get a context
+where the specified input is the only file passed to the compiler (and it is treated as a
+script file or stand-alone F# source code).
+
+*)
+// Sample input as a multi-line string
+let input =
+ """
+ open System
+
+ let foo() =
+ let msg = String.Concat("Hello"," ","world")
+ if true then
+ printfn "%s" msg.
+ """
+// Split the input & define file name
+let inputLines = input.Split('\n')
+let file = "/home/user/Test.fsx"
+
+let projOptions, errors =
+ checker.GetProjectOptionsFromScript(file, SourceText.ofString input)
+ |> Async.RunSynchronously
+
+let parsingOptions, _errors = checker.GetParsingOptionsFromProjectOptions(projOptions)
+
+(**
+To perform type checking, we first need to parse the input using
+`ParseFile`, which gives us access to the [untyped AST](untypedtree.html). However,
+then we need to call `CheckFileInProject` to perform the full type checking. This function
+also requires the result of `ParseFileInProject`, so the two functions are often called
+together.
+*)
+// Perform parsing
+
+let parseFileResults =
+ checker.ParseFile(file, SourceText.ofString input, parsingOptions)
+ |> Async.RunSynchronously
+(**
+Before we look at the interesting operations provided by `TypeCheckResults`, we
+need to run the type checker on a sample input. On F# code with errors, you would get some type checking
+result (but it may contain incorrectly "guessed" results).
+*)
+
+// Perform type checking
+let checkFileAnswer =
+ checker.CheckFileInProject(parseFileResults, file, 0, SourceText.ofString input, projOptions)
+ |> Async.RunSynchronously
+
+(**
+Alternatively you can use `ParseAndCheckFileInProject` to check both in one step:
+*)
+
+let parseResults2, checkFileAnswer2 =
+ checker.ParseAndCheckFileInProject(file, 0, SourceText.ofString input, projOptions)
+ |> Async.RunSynchronously
+
+(**
+
+The function returns both the untyped parse result (which we do not use in this
+tutorial), but also a `CheckFileAnswer` value, which gives us access to all
+the interesting functionality...
+*)
+
+let checkFileResults =
+ match checkFileAnswer with
+ | FSharpCheckFileAnswer.Succeeded(res) -> res
+ | res -> failwithf "Parsing did not finish... (%A)" res
+
+(**
+
+Here, we type check a simple function that (conditionally) prints "Hello world".
+On the last line, we leave an additional dot in `msg.` so that we can get the
+completion list on the `msg` value (we expect to see various methods on the string
+type there).
+
+
+Using type checking results
+---------------------------
+
+Let's now look at some of the API that is exposed by the `TypeCheckResults` type. In general,
+this is the type that lets you implement most of the interesting F# source code editor services.
+
+### Getting a tool tip
+
+To get a tool tip, you can use `GetToolTipTextAlternate` method. The method takes a line number and character
+offset. Both of the numbers are zero-based. In the sample code, we want to get tooltip for the `foo`
+function that is defined on line 3 (line 0 is blank) and the letter `f` starts at index 7 (the tooltip
+would work anywhere inside the identifier).
+
+In addition, the method takes a tag of token which is typically `IDENT`, when getting tooltip for an
+identifier (the other option lets you get tooltip with full assembly location when using `#r "..."`).
+
+*)
+// Get tag of the IDENT token to be used as the last argument
+let identToken = FSharpTokenTag.Identifier
+
+// Get tool tip at the specified location
+let tip = checkFileResults.GetToolTipText(4, 7, inputLines.[1], ["foo"], identToken)
+printfn "%A" tip
+
+(**
+
+> **NOTE:** `GetToolTipTextAlternate` is an alternative name for the old `GetToolTipText`. The old `GetToolTipText` was
+deprecated because it accepted zero-based line numbers. At some point it will be removed, and `GetToolTipTextAlternate` will be renamed back to `GetToolTipText`.
+*)
+
+(**
+Aside from the location and token kind, the function also requires the current contents of the line
+(useful when the source code changes) and a `Names` value, which is a list of strings representing
+the current long name. For example to get tooltip for the `Random` identifier in a long name
+`System.Random`, you would use location somewhere in the string `Random` and you would pass
+`["System"; "Random"]` as the `Names` value.
+
+The returned value is of type `ToolTipText` which contains a discriminated union `ToolTipElement`.
+The union represents different kinds of tool tips that you can get from the compiler.
+
+### Getting auto-complete lists
+
+The next method exposed by `TypeCheckResults` lets us perform auto-complete on a given location.
+This can be called on any identifier or in any scope (in which case you get a list of names visible
+in the scope) or immediately after `.` to get a list of members of some object. Here, we get a
+list of members of the string value `msg`.
+
+To do this, we call `GetDeclarationListInfo` with the location of the `.` symbol on the last line
+(ending with `printfn "%s" msg.`). The offsets are one-based, so the location is `7, 23`.
+We also need to specify a function that says that the text has not changed and the current identifier
+where we need to perform the completion.
+*)
+// Get declarations (autocomplete) for a location
+let decls =
+ checkFileResults.GetDeclarationListInfo
+ (Some parseFileResults, 7, inputLines.[6], PartialLongName.Empty 23, (fun () -> []))
+
+// Print the names of available items
+for item in decls.Items do
+ printfn " - %s" item.Name
+
+(**
+
+> **NOTE:** `v` is an alternative name for the old `GetDeclarations`. The old `GetDeclarations` was
+deprecated because it accepted zero-based line numbers. At some point it will be removed, and `GetDeclarationListInfo` will be renamed back to `GetDeclarations`.
+*)
+
+(**
+When you run the code, you should get a list containing the usual string methods such as
+`Substring`, `ToUpper`, `ToLower` etc. The fourth argument of `GetDeclarations`, here `([], "msg")`,
+specifies the context for the auto-completion. Here, we want a completion on a complete name
+`msg`, but you could for example use `(["System"; "Collections"], "Generic")` to get a completion list
+for a fully qualified namespace.
+
+### Getting parameter information
+
+The next common feature of editors is to provide information about overloads of a method. In our
+sample code, we use `String.Concat` which has a number of overloads. We can get the list using
+`GetMethods` operation. As previously, this takes zero-indexed offset of the location that we are
+interested in (here, right at the end of the `String.Concat` identifier) and we also need to provide
+the identifier again (so that the compiler can provide up-to-date information when the source code
+changes):
+
+*)
+// Get overloads of the String.Concat method
+let methods =
+ checkFileResults.GetMethods(5, 27, inputLines.[4], Some ["String"; "Concat"])
+
+// Print concatenated parameter lists
+for mi in methods.Methods do
+ [ for p in mi.Parameters -> p.Display ]
+ |> String.concat ", "
+ |> printfn "%s(%s)" methods.MethodName
+(**
+The code uses the `Display` property to get the annotation for each parameter. This returns information
+such as `arg0: obj` or `params args: obj[]` or `str0: string, str1: string`. We concatenate the parameters
+and print a type annotation with the method name.
+*)
+
+(**
+
+## Asynchronous and immediate operations
+
+You may have noticed that `CheckFileInProject` is an asynchronous operation.
+This indicates that type checking of F# code can take some time.
+The F# compiler performs the work in background (automatically) and when
+we call `CheckFileInProject` method, it returns an asynchronous operation.
+
+There is also the `CheckFileInProjectIfReady` method. This returns immediately if the
+type checking operation can't be started immediately, e.g. if other files in the project
+are not yet type-checked. In this case, a background worker might choose to do other
+work in the meantime, or give up on type checking the file until the `FileTypeCheckStateIsDirty` event
+is raised.
+
+> The [fsharpbinding](https://github.com/fsharp/fsharpbinding) project has more advanced
+example of handling the background work where all requests are sent through an F# agent.
+This may be a more appropriate for implementing editor support.
+
+*)
+
+
+(**
+Summary
+-------
+
+The `CheckFileAnswer` object contains other useful methods that were not covered in this tutorial. You
+can use it to get location of a declaration for a given identifier, additional colorization information
+(the F# 3.1 colorizes computation builder identifiers & query operators) and others.
+
+Using the FSharpChecker component in multi-project, incremental and interactive editing situations may involve
+knowledge of the [FSharpChecker operations queue](queue.html) and the [FSharpChecker caches](caches.html).
+
+
+Finally, if you are implementing an editor support for an editor that cannot directly call .NET API,
+you can call many of the methods discussed here via a command line interface that is available in the
+[FSharp.AutoComplete](https://github.com/fsharp/fsharpbinding/tree/master/FSharp.AutoComplete) project.
+
+
+*)
diff --git a/docs/fcs/filesystem.fsx b/docs/fcs/filesystem.fsx
new file mode 100644
index 00000000000..e547e2ae998
--- /dev/null
+++ b/docs/fcs/filesystem.fsx
@@ -0,0 +1,190 @@
+(*** hide ***)
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+Compiler Services: Virtualized File System
+==========================================
+
+The `FSharp.Compiler.Service` component has a global variable
+representing the file system. By setting this variable you can host the compiler in situations where a file system
+is not available.
+
+> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published.
+
+
+Setting the FileSystem
+----------------------
+
+In the example below, we set the file system to an implementation which reads from disk
+*)
+#r "FSharp.Compiler.Service.dll"
+open System
+open System.IO
+open System.Collections.Generic
+open System.Text
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+
+let defaultFileSystem = FileSystem
+
+let fileName1 = @"c:\mycode\test1.fs" // note, the path doesn't exist
+let fileName2 = @"c:\mycode\test2.fs" // note, the path doesn't exist
+
+type MyFileSystem() =
+ let file1 = """
+module File1
+
+let A = 1"""
+ let file2 = """
+module File2
+let B = File1.A + File1.A"""
+ let files = dict [(fileName1, file1); (fileName2, file2)]
+
+ interface IFileSystem with
+ // Implement the service to open files for reading and writing
+ member __.FileStreamReadShim(fileName) =
+ match files.TryGetValue fileName with
+ | true, text -> new MemoryStream(Encoding.UTF8.GetBytes(text)) :> Stream
+ | _ -> defaultFileSystem.FileStreamReadShim(fileName)
+
+ member __.FileStreamCreateShim(fileName) =
+ defaultFileSystem.FileStreamCreateShim(fileName)
+
+ member __.FileStreamWriteExistingShim(fileName) =
+ defaultFileSystem.FileStreamWriteExistingShim(fileName)
+
+ member __.ReadAllBytesShim(fileName) =
+ match files.TryGetValue fileName with
+ | true, text -> Encoding.UTF8.GetBytes(text)
+ | _ -> defaultFileSystem.ReadAllBytesShim(fileName)
+
+ // Implement the service related to temporary paths and file time stamps
+ member __.GetTempPathShim() =
+ defaultFileSystem.GetTempPathShim()
+
+ member __.GetLastWriteTimeShim(fileName) =
+ defaultFileSystem.GetLastWriteTimeShim(fileName)
+
+ member __.GetFullPathShim(fileName) =
+ defaultFileSystem.GetFullPathShim(fileName)
+
+ member __.IsInvalidPathShim(fileName) =
+ defaultFileSystem.IsInvalidPathShim(fileName)
+
+ member __.IsPathRootedShim(fileName) =
+ defaultFileSystem.IsPathRootedShim(fileName)
+
+ member __.IsStableFileHeuristic(fileName) =
+ defaultFileSystem.IsStableFileHeuristic(fileName)
+
+ // Implement the service related to file existence and deletion
+ member __.SafeExists(fileName) =
+ files.ContainsKey(fileName) || defaultFileSystem.SafeExists(fileName)
+
+ member __.FileDelete(fileName) =
+ defaultFileSystem.FileDelete(fileName)
+
+ // Implement the service related to assembly loading, used to load type providers
+ // and for F# interactive.
+ member __.AssemblyLoadFrom(fileName) =
+ defaultFileSystem.AssemblyLoadFrom fileName
+
+ member __.AssemblyLoad(assemblyName) =
+ defaultFileSystem.AssemblyLoad assemblyName
+
+let myFileSystem = MyFileSystem()
+FileSystem <- MyFileSystem()
+
+(**
+
+Doing a compilation with the FileSystem
+---------------------------------------
+
+*)
+
+let checker = FSharpChecker.Create()
+
+let projectOptions =
+ let sysLib nm =
+ if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then // file references only valid on Windows
+ System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86) +
+ @"\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\" + nm + ".dll"
+ else
+ let sysDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()
+ let (++) a b = System.IO.Path.Combine(a,b)
+ sysDir ++ nm + ".dll"
+
+ let fsCore4300() =
+ if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then // file references only valid on Windows
+ System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86) +
+ @"\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.0.0\FSharp.Core.dll"
+ else
+ sysLib "FSharp.Core"
+
+ let allFlags =
+ [| yield "--simpleresolution";
+ yield "--noframework";
+ yield "--debug:full";
+ yield "--define:DEBUG";
+ yield "--optimize-";
+ yield "--doc:test.xml";
+ yield "--warn:3";
+ yield "--fullpaths";
+ yield "--flaterrors";
+ yield "--target:library";
+ let references =
+ [ sysLib "mscorlib"
+ sysLib "System"
+ sysLib "System.Core"
+ fsCore4300() ]
+ for r in references do
+ yield "-r:" + r |]
+
+ { ProjectFileName = @"c:\mycode\compilation.fsproj" // Make a name that is unique in this directory.
+ ProjectId = None
+ SourceFiles = [| fileName1; fileName2 |]
+ OriginalLoadReferences = []
+ ExtraProjectInfo=None
+ Stamp = None
+ OtherOptions = allFlags
+ ReferencedProjects = [| |]
+ IsIncompleteTypeCheckEnvironment = false
+ UseScriptResolutionRules = true
+ LoadTime = System.DateTime.Now // Note using 'Now' forces reloading
+ UnresolvedReferences = None }
+
+let results = checker.ParseAndCheckProject(projectOptions) |> Async.RunSynchronously
+
+results.Errors
+results.AssemblySignature.Entities.Count //2
+results.AssemblySignature.Entities.[0].MembersFunctionsAndValues.Count //1
+results.AssemblySignature.Entities.[0].MembersFunctionsAndValues.[0].DisplayName // "B"
+
+(**
+Summary
+-------
+In this tutorial, we've seen how to globally customize the view of the file system used by the FSharp.Compiler.Service
+component.
+
+At the time of writing, the following System.IO operations are not considered part of the virtualized file system API.
+Future iterations on the compiler service implementation may add these to the API.
+
+ - Path.Combine
+ - Path.DirectorySeparatorChar
+ - Path.GetDirectoryName
+ - Path.GetFileName
+ - Path.GetFileNameWithoutExtension
+ - Path.HasExtension
+ - Path.GetRandomFileName (used only in generation compiled win32 resources in assemblies)
+
+**NOTE:** Several operations in the `SourceCodeServices` API accept the contents of a file to parse
+or check as a parameter, in addition to a file name. In these cases, the file name is only used for
+error reporting.
+
+**NOTE:** Type provider components do not use the virtualized file system.
+
+**NOTE:** The compiler service may use MSBuild for assembly resolutions unless `--simpleresolution` is
+provided. When using the `FileSystem` API you will normally want to specify `--simpleresolution` as one
+of your compiler flags. Also specify `--noframework`. You will need to supply explicit resolutions of all
+referenced .NET assemblies.
+
+*)
\ No newline at end of file
diff --git a/fcs/docsrc/content/index.md b/docs/fcs/index.md
similarity index 100%
rename from fcs/docsrc/content/index.md
rename to docs/fcs/index.md
diff --git a/docs/fcs/interactive.fsx b/docs/fcs/interactive.fsx
new file mode 100644
index 00000000000..911728b90ff
--- /dev/null
+++ b/docs/fcs/interactive.fsx
@@ -0,0 +1,279 @@
+(*** hide ***)
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+Interactive Service: Embedding F# Interactive
+=============================================
+
+This tutorial demonstrates how to embed F# interactive in your application. F# interactive
+is an interactive scripting environment that compiles F# code into highly efficient IL code
+and executes it on the fly. The F# interactive service allows you to embed F# evaluation in
+your application.
+
+> **NOTE:** There is a number of options for embedding F# Interactive. The easiest one is to use the
+`fsi.exe` process and communicate with it using standard input and standard output. In this
+tutorial, we look at calling F# Interactive directly through .NET API. However, if you have
+no control over the input, it is a good idea to run F# interactive in a separate process.
+One reason is that there is no way to handle `StackOverflowException` and so a poorly written
+script can terminate the host process. **Remember that while calling F# Interactive through .NET API,
+` --shadowcopyreferences` option will be ignored**. For detailed discussion, please take a look at
+[this thread](https://github.com/fsharp/FSharp.Compiler.Service/issues/292).
+> **NOTE:** If `FsiEvaluationSession.Create` fails with an error saying that `FSharp.Core.dll` cannot be found,
+add the `FSharp.Core.sigdata` and `FSharp.Core.optdata` files. More info [here](https://fsharp.github.io/FSharp.Compiler.Service/corelib.html).
+
+However, the F# interactive service is still useful, because you might want to wrap it in your
+own executable that is then executed (and communicates with the rest of your application), or
+if you only need to execute limited subset of F# code (e.g. generated by your own DSL).
+
+Starting the F# interactive
+---------------------------
+
+First, we need to reference the libraries that contain F# interactive service:
+*)
+
+#r "FSharp.Compiler.Service.dll"
+open FSharp.Compiler.Interactive.Shell
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+
+(**
+To communicate with F# interactive, we need to create streams that represent input and
+output. We will use those later to read the output printed as a result of evaluating some
+F# code that prints:
+*)
+open System
+open System.IO
+open System.Text
+
+// Initialize output and input streams
+let sbOut = new StringBuilder()
+let sbErr = new StringBuilder()
+let inStream = new StringReader("")
+let outStream = new StringWriter(sbOut)
+let errStream = new StringWriter(sbErr)
+
+// Build command line arguments & start FSI session
+let argv = [| "C:\\fsi.exe" |]
+let allArgs = Array.append argv [|"--noninteractive"|]
+
+let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
+let fsiSession = FsiEvaluationSession.Create(fsiConfig, allArgs, inStream, outStream, errStream)
+
+
+
+(**
+Evaluating and executing code
+-----------------------------
+
+The F# interactive service exposes several methods that can be used for evaluation. The first
+is `EvalExpression` which evaluates an expression and returns its result. The result contains
+the returned value (as `obj`) and the statically inferred type of the value:
+*)
+/// Evaluate expression & return the result
+let evalExpression text =
+ match fsiSession.EvalExpression(text) with
+ | Some value -> printfn "%A" value.ReflectionValue
+ | None -> printfn "Got no result!"
+
+(**
+This takes a string as an argument and evaluates (i.e. executes) it as F# code.
+*)
+evalExpression "42+1" // prints '43'
+
+(**
+This can be used in a strongly typed way as follows:
+*)
+
+/// Evaluate expression & return the result, strongly typed
+let evalExpressionTyped<'T> (text) =
+ match fsiSession.EvalExpression(text) with
+ | Some value -> value.ReflectionValue |> unbox<'T>
+ | None -> failwith "Got no result!"
+
+evalExpressionTyped "42+1" // gives '43'
+
+
+(**
+The `EvalInteraction` method can be used to evaluate side-effectful operations
+such as printing, declarations, or other interactions that are not valid F# expressions, but can be entered in
+the F# Interactive console. Such commands include `#time "on"` (and other directives), `open System`
+all declarations and other top-level statements. The code
+does not require `;;` at the end. Just enter the code that you want to execute:
+*)
+fsiSession.EvalInteraction "printfn \"bye\""
+
+
+(**
+The `EvalScript` method allows to evaluate a complete .fsx script.
+*)
+
+File.WriteAllText("sample.fsx", "let twenty = 10 + 10")
+fsiSession.EvalScript "sample.fsx"
+
+(**
+Catching errors
+------------------
+
+``EvalExpression``, ``EvalInteraction`` and ``EvalScript`` are awkward if the
+code has type checking warnings or errors, or if evaluation fails with an exception.
+In these cases you can use ``EvalExpressionNonThrowing``, ``EvalInteractionNonThrowing``
+and ``EvalScriptNonThrowing``. These return a tuple of a result and an array of ``FSharpDiagnostic`` values.
+These represent the errors and warnings. The result part is a ``Choice<_,_>`` between an actual
+result and an exception.
+
+The result part of ``EvalExpression`` and ``EvalExpressionNonThrowing`` is an optional ``FSharpValue``.
+If that value is not present then it just indicates that the expression didn't have a tangible
+result that could be represented as a .NET object. This situation shouldn't actually
+occur for any normal input expressions, and only for primitives used in libraries.
+*)
+
+File.WriteAllText("sample.fsx", "let twenty = 'a' + 10.0")
+let result, warnings = fsiSession.EvalScriptNonThrowing "sample.fsx"
+
+// show the result
+match result with
+| Choice1Of2 () -> printfn "checked and executed ok"
+| Choice2Of2 exn -> printfn "execution exception: %s" exn.Message
+
+
+(**
+Gives:
+
+ execution exception: Operation could not be completed due to earlier error
+*)
+
+// show the errors and warnings
+for w in warnings do
+ printfn "Warning %s at %d,%d" w.Message w.StartLineAlternate w.StartColumn
+
+(**
+Gives:
+
+ Warning The type 'float' does not match the type 'char' at 1,19
+ Warning The type 'float' does not match the type 'char' at 1,17
+
+For expressions:
+*)
+
+
+let evalExpressionTyped2<'T> text =
+ let res, warnings = fsiSession.EvalExpressionNonThrowing(text)
+ for w in warnings do
+ printfn "Warning %s at %d,%d" w.Message w.StartLineAlternate w.StartColumn
+ match res with
+ | Choice1Of2 (Some value) -> value.ReflectionValue |> unbox<'T>
+ | Choice1Of2 None -> failwith "null or no result"
+ | Choice2Of2 (exn:exn) -> failwith (sprintf "exception %s" exn.Message)
+
+evalExpressionTyped2 "42+1" // gives '43'
+
+
+(**
+Executing in parallel
+------------------
+
+By default the code passed to ``EvalExpression`` is executed immediately. To execute in parallel, submit a computation that starts a task:
+*)
+
+open System.Threading.Tasks
+
+let sampleLongRunningExpr =
+ """
+async {
+ // The code of what you want to run
+ do System.Threading.Thread.Sleep 5000
+ return 10
+}
+ |> Async.StartAsTask"""
+
+let task1 = evalExpressionTyped>(sampleLongRunningExpr)
+let task2 = evalExpressionTyped>(sampleLongRunningExpr)
+
+(**
+Both computations have now started. You can now fetch the results:
+*)
+
+
+task1.Result // gives the result after completion (up to 5 seconds)
+task2.Result // gives the result after completion (up to 5 seconds)
+
+(**
+Type checking in the evaluation context
+------------------
+
+Let's assume you have a situation where you would like to typecheck code
+in the context of the F# Interactive scripting session. For example, you first
+evaluation a declaration:
+*)
+
+fsiSession.EvalInteraction "let xxx = 1 + 1"
+
+(**
+
+Now you want to typecheck the partially complete code `xxx + xx`
+*)
+
+let parseResults, checkResults, checkProjectResults =
+ fsiSession.ParseAndCheckInteraction("xxx + xx")
+ |> Async.RunSynchronously
+
+(**
+The `parseResults` and `checkResults` have types `ParseFileResults` and `CheckFileResults`
+explained in [Editor](editor.html). You can, for example, look at the type errors in the code:
+*)
+checkResults.Errors.Length // 1
+
+(**
+The code is checked with respect to the logical type context available in the F# interactive session
+based on the declarations executed so far.
+
+You can also request declaration list information, tooltip text and symbol resolution:
+*)
+
+// get a tooltip
+checkResults.GetToolTipText(1, 2, "xxx + xx", ["xxx"], FSharpTokenTag.IDENT)
+
+checkResults.GetSymbolUseAtLocation(1, 2, "xxx + xx", ["xxx"]) // symbol xxx
+
+(**
+The 'fsi' object
+------------------
+
+If you want your scripting code to be able to access the 'fsi' object, you should pass in an implementation of this object explicitly.
+Normally the one from FSharp.Compiler.Interactive.Settings.dll is used.
+*)
+
+let fsiConfig2 = FsiEvaluationSession.GetDefaultConfiguration(fsiSession)
+
+(**
+Collectible code generation
+------------------
+
+Evaluating code in using FsiEvaluationSession generates a .NET dynamic assembly and uses other resources.
+You can make generated code collectible by passing `collectible=true`. However code will only
+be collected if there are no outstanding object references involving types, for example
+`FsiValue` objects returned by `EvalExpression`, and you must have disposed the `FsiEvaluationSession`.
+See also [Restrictions on Collectible Assemblies](https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/dd554932(v=vs.100)#restrictions).
+
+The example below shows the creation of 200 evaluation sessions. Note that `collectible=true` and
+`use session = ...` are both used.
+
+If collectible code is working correctly,
+overall resource usage will not increase linearly as the evaluation progresses.
+*)
+
+let collectionTest() =
+
+ for i in 1 .. 200 do
+ let defaultArgs = [|"fsi.exe";"--noninteractive";"--nologo";"--gui-"|]
+ use inStream = new StringReader("")
+ use outStream = new StringWriter()
+ use errStream = new StringWriter()
+
+ let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
+ use session = FsiEvaluationSession.Create(fsiConfig, defaultArgs, inStream, outStream, errStream, collectible=true)
+
+ session.EvalInteraction (sprintf "type D = { v : int }")
+ let v = session.EvalExpression (sprintf "{ v = 42 * %d }" i)
+ printfn "iteration %d, result = %A" i v.Value.ReflectionValue
+
+// collectionTest() <-- run the test like this
diff --git a/docs/fcs/ja/compiler.fsx b/docs/fcs/ja/compiler.fsx
new file mode 100644
index 00000000000..8b14ea3f007
--- /dev/null
+++ b/docs/fcs/ja/compiler.fsx
@@ -0,0 +1,89 @@
+(*** hide ***)
+#I "../../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+コンパイラの組み込み
+====================
+
+このチュートリアルではF#コンパイラをホストする方法を紹介します。
+
+> **注意:** 以下で使用しているAPIは実験的なもので、
+ 新しいnugetパッケージの公開に伴って変更される可能性があります。
+
+> **注意:** F#コンパイラをホストする方法はいくつかあります。
+ 一番簡単な方法は `fsc.exe` のプロセスを使って引数を渡す方法です。
+
+---------------------------
+
+まず、F# Interactiveサービスを含むライブラリへの参照を追加します:
+*)
+
+#r "FSharp.Compiler.Service.dll"
+open FSharp.Compiler.SourceCodeServices
+open System.IO
+
+let scs = FSharpChecker.Create()
+
+(**
+次に、一時ファイルへコンテンツを書き込みます:
+
+*)
+let fn = Path.GetTempFileName()
+let fn2 = Path.ChangeExtension(fn, ".fs")
+let fn3 = Path.ChangeExtension(fn, ".dll")
+
+File.WriteAllText(fn2, """
+module M
+
+type C() =
+ member x.P = 1
+
+let x = 3 + 4
+""")
+
+(**
+そしてコンパイラを呼び出します:
+*)
+
+let errors1, exitCode1 = scs.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |]) |> Async.RunSynchronously
+
+(**
+
+エラーが発生した場合は「終了コード」とエラーの配列から原因を特定できます:
+
+*)
+File.WriteAllText(fn2, """
+module M
+
+let x = 1.0 + "" // a type error
+""")
+
+let errors1b, exitCode1b = scs.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |]) |> Async.RunSynchronously
+
+if exitCode1b <> 0 then
+ errors1b
+ |> Array.iter (printfn "%A")
+
+(**
+
+動的アセンブリへのコンパイル
+============================
+
+コードを動的アセンブリとしてコンパイルすることもできます。
+動的アセンブリはF# Interactiveコードジェネレータでも使用されています。
+
+この機能はたとえばファイルシステムが必ずしも利用できないような状況で役に立ちます。
+
+出力ファイルの名前を指定する "-o" オプションを指定することは可能ですが、
+実際には出力ファイルがディスク上に書き込まれることはありません。
+
+'execute' 引数に 'None' を指定するとアセンブリ用の初期化コードが実行されません。
+*)
+let errors2, exitCode2, dynAssembly2 =
+ scs.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], execute=None) |> Async.RunSynchronously
+
+(**
+'Some' を指定するとアセンブリ用の初期化コードが実行されます。
+*)
+let errors3, exitCode3, dynAssembly3 =
+ scs.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], Some(stdout,stderr)) |> Async.RunSynchronously
+
diff --git a/docs/fcs/ja/corelib.fsx b/docs/fcs/ja/corelib.fsx
new file mode 100644
index 00000000000..f5a7bbd2890
--- /dev/null
+++ b/docs/fcs/ja/corelib.fsx
@@ -0,0 +1,72 @@
+(*** hide ***)
+#I "../../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+コンパイラサービス: FSharp.Core.dll についてのメモ
+==================================================
+
+あなたのアプリケーションとともに FSharp.Core を配布する
+-------------------------------------------------------
+
+FSharp.Compiler.Service.dll を利用するアプリケーションまたはプラグイン・コンポーネントをビルドする際、普通はアプリの一部として FSharp.Core.dll のコピーも含めることになるでしょう。
+
+例えば、 ``HostedCompiler.exe`` をビルドする場合、普通はあなたの ``HostedCompiler.exe`` と同じフォルダに FSharp.Core.dll (例えば 4.3.1.0)を配置します。
+
+動的コンパイルや動的実行を行う場合、FSharp.Core.optdata と FSharp.Core.sigdata も含める必要があるかもしれませんが、これらについては下記の指針をご覧ください。
+
+どの FSharp.Core と .NET フレームワークがコンパイル時に参照される?
+--------------------------------------
+
+FSharp.Combiler.Service コンポーネントは多かれ少なかれ、F#コードを コンパイルするために使われるに過ぎません。特に、コマンドライン引数(あなたのツールを実行するために使われる FSharp.Core や .NET フレームワークとは違います)に明示的に FSharp.Core および/またはフレームワークのアセンブリを参照することが出来ます。
+
+特定の FSharp.Core および .NET フレームワーク アセンブリ、またはそのいずれかをターゲットにする場合、 ``--noframework`` 引数と適切なコマンドライン引数を使います:
+
+ []
+ let fsharpCorePath =
+ @"C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.1.0\FSharp.Core.dll"
+ let errors2, exitCode2 =
+ scs.Compile(
+ [| "fsc.exe"; "--noframework";
+ "-r"; fsharpCorePath;
+ "-r"; @"C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll";
+ "-o"; fn3;
+ "-a"; fn2 |])
+
+これらのアセンブリが配置されている場所を指定する必要があります。クロスプラットフォームに対応した方法でDLL を配置して、それらをコマンドライン引数に変換する最も簡単な方法は、[F# プロジェクトファイルをクラックする](https://fsharp.github.io/FSharp.Compiler.Service/ja/project.html)ことです。
+自分で SDK のパスを処理する代わりに、[FSharp.Compiler.Service.dll 用のテスト](https://github.com/fsharp/FSharp.Compiler.Service/blob/8a943dd3b545648690cb3bed652a469bdb6dd869/tests/service/Common.fs#L54)で使用しているようなヘルパー関数も用意されています。
+
+
+スクリプトを処理しているか ``GetCheckOptionsFromScriptRoot`` を使っている場合
+-------------------------------------------------------------------------
+
+もし SDK 配置先にある FSharp.Core.dll を明示的に参照 *していない* 場合、または ``FsiEvaluationSession`` や ``GetCheckOptionsFromScriptRoot`` を使用してスクリプトを処理している場合、以下のいずれかの方法により、暗黙的にFSharp.Core が参照されます:
+
+1. ``System.Reflection.Assembly.GetEntryAssembly()`` によって返されるホストアセンブリから静的に参照されたFSharp.Core.dll のバージョン
+
+2. ホストアセンブリに FSharp.Core への静的な参照がない場合、
+
+ - FSharp.Compiler.Service 0.x シリーズでは、FSharp.Core バージョン 4.3.0.0 への参照が付与されます
+
+ - FSharp.Compiler.Service 1.3.1.x (F# 3.1 シリーズ)では、FSharp.Core バージョン 4.3.1.0 への参照が付与されます
+
+ - FSharp.Compiler.Service 1.4.0.x (F# 4.0 シリーズ)では、FSharp.Core バージョン 4.4.0.0 への参照が付与されます
+
+FSharp.Core.optdata と FSharp.Core.sigdata を含める必要はありますか?
+--------------------------------------
+
+もしあなたのコンパイル引数が SDK 配置先にある FSharp.Core.dll を明示的に参照している場合、FSharp.Core.sigdata と FSharp.Core.optdata はその DLL と同じフォルダになければいけません(これらのファイルがインストールされていない場合、F# SDKの インストールに問題があります)。もしコンパイル引数で常に明示的に参照していたなら、FSharp.Core.optdata と FSharp.Core.sigdata はあなたのアプリケーションの一部として含める必要は *ありません* 。
+
+もしあなたが暗黙的な参照(例えば、上記のスクリプト処理など)に頼っているのなら、これはあなたのツールがアプリケーションの一部として FSharp.Core.dll を参照しているかもしれない、ということです。この場合、FSharp.Core.optdata および FSharp.Core.sigdata が FSharp.Core.dll と同じフォルダに見つからないというエラーが発生するかもしれません。 **もしあなたがアプリケーションに含めている FSharp.Core.dll を暗黙的に参照したいのであれば、FSharp.Core.sigdata と FSharp.Core.optdata もアプリケーションに追加する2つのファイルとして追加しましょう。** ``CombileToDynamicAssembly`` を使用する場合、この問題によって[アセンブリ解決中のスタックオーバーフロー](https://github.com/fsharp/FSharp.Compiler.Service/issues/258)も引き起こされるでしょう。
+
+動的コンパイルと動的コード実行を行うツール(例: ``HostedExecution.exe``)はしばしば FSharp.Core.dll を暗黙的に参照するようになっています。
+これはつまり通常 FSharp.Core.optdata と FSharp.Core.sigdata を含んでいるということです。
+
+要約
+-------
+
+このデザインノートでは3つのポイントを検討しました:
+
+- どの FSharp.Core.dll があなたのコンパイルツールを実行するのに使われるか
+- あなたのコンパイルツールを実行するのに使われる FSharp.Core.dll へのバインド リダイレクトを設定する方法
+- あなたのツールによって実行されるチェック時およびコンパイル時にどの FSharp.Core.dll および/またはフレームワークのアセンブリが参照されるか
+
+*)
diff --git a/fcs/docsrc/content/ja/devnotes.md b/docs/fcs/ja/devnotes.md
similarity index 100%
rename from fcs/docsrc/content/ja/devnotes.md
rename to docs/fcs/ja/devnotes.md
diff --git a/docs/fcs/ja/editor.fsx b/docs/fcs/ja/editor.fsx
new file mode 100644
index 00000000000..fe6ad292ab0
--- /dev/null
+++ b/docs/fcs/ja/editor.fsx
@@ -0,0 +1,269 @@
+(*** hide ***)
+#I "../../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+コンパイラサービス: エディタサービス
+====================================
+
+このチュートリアルはF#コンパイラによって公開されるエディタサービスの
+使用方法についてのデモです。
+このAPIにより、Visual StudioやXamarin Studio、EmacsなどのF#エディタ内において、
+自動補完機能やツールチップ表示、引数情報のヘルプ表示、括弧の補完などの機能を
+実装することができます
+(詳細については [fsharpbindings](https://github.com/fsharp/fsharpbinding) のプロジェクトを参照してください)。
+[型無しASTを使用するチュートリアル](untypedtree.html) と同じく、
+今回も `FSharpChecker` オブジェクトを作成するところから始めます。
+
+> **注意:** 以下で使用しているAPIは試験的なもので、最新バージョンのnugetパッケージの
+公開に伴って変更されることがあります。
+
+サンプルソースコードの型チェック
+--------------------------------
+
+[前回の(型無しASTを使った)チュートリアル](untypedtree.html) と同じく、
+`FSharp.Compiler.Service.dll` への参照を追加した後に特定の名前空間をオープンし、
+`FSharpChecker` のインスタンスを作成します:
+
+*)
+// F#コンパイラAPIを参照
+#r "FSharp.Compiler.Service.dll"
+
+open System
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+
+// インタラクティブチェッカーのインスタンスを作成
+let checker = FSharpChecker.Create()
+
+(**
+
+[前回](untypedtree.html) 同様、
+コンパイラに渡されるファイルとしては特定の入力値だけであるという
+コンテキストを想定するため、 `GetCheckOptionsFromScriptRoot` を使います
+(この入力値はコンパイラによってスクリプトファイル、
+あるいはスタンドアロンのF#ソースコードとみなされます)。
+
+*)
+// サンプルの入力となる複数行文字列
+let input =
+ """
+open System
+
+let foo() =
+let msg = String.Concat("Hello"," ","world")
+if true then
+printfn "%s" msg.
+"""
+// 入力値の分割とファイル名の定義
+let inputLines = input.Split('\n')
+let file = "/home/user/Test.fsx"
+
+let projOptions, _errors1 = checker.GetProjectOptionsFromScript(file, SourceText.ofString input) |> Async.RunSynchronously
+
+let parsingOptions, _errors2 = checker.GetParsingOptionsFromProjectOptions(projOptions)
+
+(**
+
+型チェックを実行するには、まず `ParseFile` を使って
+入力値をパースする必要があります。
+このメソッドを使うと [型無しAST](untypedtree.html) にアクセスできるようになります。
+しかし今回は完全な型チェックを実行するため、続けて `CheckFileInProject`
+を呼び出す必要があります。
+このメソッドは `ParseFile` の結果も必要とするため、
+たいていの場合にはこれら2つのメソッドをセットで呼び出すことになります。
+
+*)
+// パースを実行
+let parseFileResults =
+ checker.ParseFile(file, SourceText.ofString input, parsingOptions)
+ |> Async.RunSynchronously
+(**
+`TypeCheckResults` に備えられた興味深い機能の紹介に入る前に、
+サンプル入力に対して型チェッカーを実行する必要があります。
+F#コードにエラーがあった場合も何らかの型チェックの結果が返されます
+(ただし間違って「推測された」結果が含まれることがあります)。
+*)
+
+// 型チェックを実行
+let checkFileAnswer =
+ checker.CheckFileInProject(parseFileResults, file, 0, SourceText.ofString input, projOptions)
+ |> Async.RunSynchronously
+
+(**
+あるいは `ParseAndCheckFileInProject` を使用すれば1つの操作で両方のチェックを行うことができます:
+*)
+
+let parseResults2, checkFileAnswer2 =
+ checker.ParseAndCheckFileInProject(file, 0, SourceText.ofString input, projOptions)
+ |> Async.RunSynchronously
+
+(**
+この返り値は `CheckFileAnswer` 型で、この型に機能的に興味深いものが揃えられています...
+*)
+
+let checkFileResults =
+ match checkFileAnswer with
+ | FSharpCheckFileAnswer.Succeeded(res) -> res
+ | res -> failwithf "パースが完了していません... (%A)" res
+
+(**
+
+今回は単に(状況に応じて)「Hello world」と表示するだけの
+単純な関数の型をチェックしています。
+最終行では値 `msg` に対する補完リストを表示することができるように、
+`msg.` というようにドットを追加している点に注意してください
+(今回の場合は文字列型に対する様々なメソッドが期待されます)。
+
+
+型チェックの結果を使用する
+--------------------------
+
+では `TypeCheckResults` 型で公開されているAPIをいくつか見ていきましょう。
+一般的に、F#ソースコードエディタサービスの実装に必要な機能は
+ほとんどこの型に備えられています。
+
+### ツールチップの取得
+
+ツールチップを取得するには `GetToolTipTextAlternate` メソッドを使用します。
+このメソッドには行数と文字オフセットを指定します。
+いずれも0から始まる数値です。
+サンプルコードでは3行目(0行目は空白行)、インデックス7にある文字 `f` から始まる関数
+`foo` のツールチップを取得しています
+(ツールチップは識別子の中であれば任意の位置で機能します)。
+
+またこのメソッドにはトークンタグを指定する必要もあります。
+トークンタグは一般的には `IDENT` を指定して、識別子に対する
+ツールチップが取得できるようにします
+(あるいは `#r "..."` を使用している場合にはアセンブリの完全パスを表示させるように
+することもできるでしょう)。
+
+*)
+// 最後の引数に指定する、IDENTトークンのタグを取得
+
+// 特定の位置におけるツールチップを取得
+let tip = checkFileResults.GetToolTipText(4, 7, inputLines.[1], ["foo"], FSharpTokenTag.Identifier)
+printfn "%A" tip
+
+(**
+
+> **注意:** `GetToolTipTextAlternate` は古い関数 `GetToolTipText` に代わるものです。
+`GetToolTipText` は0から始まる行番号を受け取るようになっていたため、非推奨になりました。
+
+この関数には位置とトークンの種類の他にも、
+(ソースコードの変更時に役立つように)特定行の現在の内容と、
+現時点における完全修飾された `名前` を表す文字列のリストを指定する必要があります。
+たとえば完全修飾名 `System.Random` という名前を持った識別子 `Random` に対する
+ツールチップを取得する場合、 `Random` という文字列が現れる場所の他に、
+`["System"; "Random"]` という値を指定する必要があります。
+
+返り値の型は `ToolTipText` で、この型には `ToolTipElement` という
+判別共用体が含まれます。
+この共用体は、コンパイラによって返されたツールチップの種類に応じて異なります。
+
+### 自動補完リストの取得
+
+次に紹介する `TypeCheckResults` のメソッドを使用すると、
+特定の位置における自動補完機能を実装できます。
+この機能は任意の識別子上、
+あるいは(特定のスコープ内で利用可能な名前の一覧を取得する場合には)任意のスコープ、
+あるいは特定のオブジェクトにおけるメンバーリストを取得する場合には
+`.` の直後で呼び出すことができます。
+今回は文字列の値 `msg` に対するメンバーリストを取得することにします。
+
+そのためには最終行( `printfn "%s" msg.` で終わっている行)にある
+シンボル `.` の位置を指定して `GetDeclarationListInfo` を呼び出します。
+オフセットは1から始まるため、位置は `7, 23` になります。
+また、テキストが変更されていないことを表す関数と、
+現時点において補完する必要がある識別子を指定する必要もあります。
+*)
+// 特定の位置における宣言(自動補完)を取得する
+let decls =
+ checkFileResults.GetDeclarationListInfo
+ (Some parseFileResults, 7, inputLines.[6], PartialLongName.Empty 23, (fun _ -> []))
+
+// 利用可能な項目を表示
+for item in decls.Items do
+ printfn " - %s" item.Name
+(**
+
+> **注意:** `GetDeclarationListInfo` は古い関数 `GetDeclarations` に代わるものです。
+`GetDeclarations` は0から始まる行番号を受け取るようになっていたため、非推奨になりました。
+また、将来的には現在の `GetDeclarations` が削除され、 `GetDeclarationListInfo` が
+`GetDeclarations` になる予定です。
+
+コードを実行してみると、 `Substring` や `ToUpper` 、 `ToLower` といった
+文字列に対するいつものメソッドのリストが取得できていることでしょう。
+`GetDeclarations` の5,6番目の引数( `[]` および `"msg"` )には
+自動補完用のコンテキストを指定します。
+今回の場合は完全名 `msg` に対する補完を行いましたが、
+たとえば `["System"; "Collections"]` と `"Generic"` というように
+完全修飾された名前空間を指定して補完リストを取得することもできます。
+
+### 引数の情報を取得する
+
+次に一般的なエディタの機能としては、メソッドのオーバーロードに
+関する情報を提供するというものでしょう。
+サンプルコード中では多数のオーバーロードを持った `String.Concat` を使っています。
+このオーバーロード一覧は `GetMethods` で取得できます。
+先ほどと同じく、このメソッドには対象とする項目の位置を0基準のオフセットで指定し
+(今回は `String.Concat` 識別子の右側の終端)、
+識別子もやはり指定します
+(これにより、コンパイラはソースコードが変更された場合でも最新の情報に追従できます):
+
+*)
+//String.Concatメソッドのオーバーロードを取得する
+let methods =
+ checkFileResults.GetMethods(5, 27, inputLines.[4], Some ["String"; "Concat"])
+
+// 連結された引数リストを表示
+for mi in methods.Methods do
+ [ for p in mi.Parameters -> p.Display ]
+ |> String.concat ", "
+ |> printfn "%s(%s)" methods.MethodName
+(**
+ここでは `Display` プロパティを使用することで各引数に対する
+アノテーションを取得しています。
+このプロパティは `arg0: obj` あるいは `params args: obj[]` 、
+`str0: string, str1: string` といった情報を返します。
+これらの引数を連結した後、メソッド名とメソッドの型情報とともに表示させています。
+*)
+
+(**
+
+## 非同期操作と即時操作
+
+`CheckFileInProject` が非同期操作であることを気にされる人もいるかもしれません。
+これはつまり、F#コードの型チェックにはある程度時間がかかることを示唆しています。
+F#コンパイラは型チェックを(自動的に)バックグラウンドで処理を進めているため、
+`CheckFileInProject` メソッドを呼び出すと非同期操作が返されることになります。
+
+また、 `CheckFileInProjectIfReady` というメソッドもあります。
+このメソッドは、型チェックの操作が即座に開始できない場合、
+つまりプロジェクト内の他のファイルがまだ型チェックされていない場合には
+処理が即座に返されます。
+この場合、バックグラウンドワーカーは一定期間他の作業を進めるか、
+`FileTypeCheckStateIsDirty` イベントが発生するまでは
+ファイルに対する型チェックを諦めるか、どちらか選択することになります。
+
+> [fsharpbinding](https://github.com/fsharp/fsharpbinding) プロジェクトには
+1つのF#エージェント経由ですべてのリクエストをバックグラウンドワークとして
+処理するような、より複雑な具体例も含まれています。
+エディタの機能を実装する方法としてはこちらのほうが適切です。
+
+*)
+
+
+(**
+まとめ
+------
+
+`CheckFileAnswer` にはチュートリアルで紹介していないような便利なメソッドが
+多数揃えられています。
+これらを使用すれば特定の識別子に対する宣言の位置を取得したり、
+付加的な色情報を取得したりすることができます
+(F# 3.1では式ビルダーの識別子やクエリ演算子も着色表示されます)。
+
+最後に、直接.NET APIを呼び出すことができないようなエディタに対するサポート機能を
+実装する場合、ここで紹介した様々な機能を
+[FSharp.AutoComplete](https://github.com/fsharp/fsharpbinding/tree/master/FSharp.AutoComplete)
+プロジェクトのコマンドラインインターフェイス経由で呼び出すこともできます。
+*)
diff --git a/docs/fcs/ja/filesystem.fsx b/docs/fcs/ja/filesystem.fsx
new file mode 100644
index 00000000000..f5e2365964b
--- /dev/null
+++ b/docs/fcs/ja/filesystem.fsx
@@ -0,0 +1,174 @@
+(*** hide ***)
+#I "../../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+コンパイラサービス: ファイルシステム仮想化
+==========================================
+
+`FSharp.Compiler.Service` にはファイルシステムを表すグローバル変数があります。
+この変数を設定するこにより、ファイルシステムが利用できない状況でも
+コンパイラをホストすることができるようになります。
+
+> **注意:** 以下で使用しているAPIは実験的なもので、
+ 新しいnugetパッケージの公開に伴って変更される可能性があります。
+
+FileSystemの設定
+----------------
+
+以下の例ではディスクからの読み取りを行うような実装をファイルシステムに設定しています:
+*)
+#r "FSharp.Compiler.Service.dll"
+open System.IO
+open System.Text
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+
+let defaultFileSystem = FileSystem
+
+let fileName1 = @"c:\mycode\test1.fs" // 注意: 実際には存在しないファイルのパス
+let fileName2 = @"c:\mycode\test2.fs" // 注意: 実際には存在しないファイルのパス
+
+type MyFileSystem() =
+ let file1 = """
+module File1
+
+let A = 1"""
+ let file2 = """
+module File2
+let B = File1.A + File1.A"""
+ let files = dict [(fileName1, file1); (fileName2, file2)]
+
+ interface IFileSystem with
+ // 読み取りおよび書き込み用にファイルをオープンする機能を実装
+ member __.FileStreamReadShim(fileName) =
+ match files.TryGetValue fileName with
+ | true, text -> new MemoryStream(Encoding.UTF8.GetBytes(text)) :> Stream
+ | _ -> defaultFileSystem.FileStreamReadShim(fileName)
+
+ member __.FileStreamCreateShim(fileName) =
+ defaultFileSystem.FileStreamCreateShim(fileName)
+
+ member __.IsStableFileHeuristic(fileName) =
+ defaultFileSystem.IsStableFileHeuristic(fileName)
+
+ member __.FileStreamWriteExistingShim(fileName) =
+ defaultFileSystem.FileStreamWriteExistingShim(fileName)
+
+ member __.ReadAllBytesShim(fileName) =
+ match files.TryGetValue fileName with
+ | true, text -> Encoding.UTF8.GetBytes(text)
+ | _ -> defaultFileSystem.ReadAllBytesShim(fileName)
+
+ // 一時パスおよびファイルのタイムスタンプに関連する機能を実装
+ member __.GetTempPathShim() =
+ defaultFileSystem.GetTempPathShim()
+
+ member __.GetLastWriteTimeShim(fileName) =
+ defaultFileSystem.GetLastWriteTimeShim(fileName)
+
+ member __.GetFullPathShim(fileName) =
+ defaultFileSystem.GetFullPathShim(fileName)
+
+ member __.IsInvalidPathShim(fileName) =
+ defaultFileSystem.IsInvalidPathShim(fileName)
+
+ member __.IsPathRootedShim(fileName) =
+ defaultFileSystem.IsPathRootedShim(fileName)
+
+ // ファイルの存在確認および削除に関連する機能を実装
+ member __.SafeExists(fileName) =
+ files.ContainsKey(fileName) || defaultFileSystem.SafeExists(fileName)
+
+ member __.FileDelete(fileName) =
+ defaultFileSystem.FileDelete(fileName)
+
+ // アセンブリのロードに関連する機能を実装。
+ // 型プロバイダやF# Interactiveで使用される。
+ member __.AssemblyLoadFrom(fileName) =
+ defaultFileSystem.AssemblyLoadFrom fileName
+
+ member __.AssemblyLoad(assemblyName) =
+ defaultFileSystem.AssemblyLoad assemblyName
+
+let myFileSystem = MyFileSystem()
+FileSystem <- MyFileSystem()
+
+(**
+
+FileSystemによるコンパイルの実行
+--------------------------------
+
+*)
+open FSharp.Compiler.SourceCodeServices
+
+let checker = FSharpChecker.Create()
+let projectOptions =
+ let allFlags =
+ [| yield "--simpleresolution";
+ yield "--noframework";
+ yield "--debug:full";
+ yield "--define:DEBUG";
+ yield "--optimize-";
+ yield "--doc:test.xml";
+ yield "--warn:3";
+ yield "--fullpaths";
+ yield "--flaterrors";
+ yield "--target:library";
+ let references =
+ [ @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\mscorlib.dll";
+ @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll";
+ @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll";
+ @"C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.0.0\FSharp.Core.dll"]
+ for r in references do
+ yield "-r:" + r |]
+
+ { ProjectFileName = @"c:\mycode\compilation.fsproj" // 現在のディレクトリで一意な名前を指定
+ ProjectId = None
+ SourceFiles = [| fileName1; fileName2 |]
+ OriginalLoadReferences = []
+ ExtraProjectInfo=None
+ Stamp = None
+ OtherOptions = allFlags
+ ReferencedProjects=[| |]
+ IsIncompleteTypeCheckEnvironment = false
+ UseScriptResolutionRules = true
+ LoadTime = System.DateTime.Now // 'Now' を指定して強制的に再読込させている点に注意
+ UnresolvedReferences = None }
+
+let results = checker.ParseAndCheckProject(projectOptions) |> Async.RunSynchronously
+
+results.Errors
+results.AssemblySignature.Entities.Count //2
+results.AssemblySignature.Entities.[0].MembersFunctionsAndValues.Count //1
+results.AssemblySignature.Entities.[0].MembersFunctionsAndValues.[0].DisplayName // "B"
+
+(**
+まとめ
+------
+このチュートリアルでは FSharp.Compiler.Service コンポーネントで使用される
+ファイルシステムに注目して、グローバルな設定を変更する方法について紹介しました。
+
+このチュートリアルの執筆時点では、以下に列挙したSystem.IOの操作に対しては
+仮想化されたファイルシステムAPIが用意されない予定になっています。
+将来のバージョンのコンパイラサービスではこれらのAPIが追加されるかもしれません。
+
+ - Path.Combine
+ - Path.DirectorySeparatorChar
+ - Path.GetDirectoryName
+ - Path.GetFileName
+ - Path.GetFileNameWithoutExtension
+ - Path.HasExtension
+ - Path.GetRandomFileName (アセンブリ内にコンパイル済みwin32リソースを生成する場合にのみ使用される)
+
+**注意:** `SourceCodeServices` API内の一部の操作では、
+引数にファイルの内容だけでなくファイル名を指定する必要があります。
+これらのAPIにおいて、ファイル名はエラーの報告のためだけに使用されます。
+
+**注意:** 型プロバイダーコンポーネントは仮想化されたファイルシステムを使用しません。
+
+**注意:** コンパイラサービスは `--simpleresolution` が指定されていない場合、
+MSBuildを使ってアセンブリの解決を試みることがあります。
+`FileSystem` APIを使用する場合、通常はコンパイラへのフラグとして
+`--simpleresolution` を指定することになります。
+それと同時に `--noframework` を指定します。
+.NETアセンブリに対するすべての参照を明示的に指定する必要があるでしょう。
+*)
diff --git a/fcs/docsrc/content/ja/index.md b/docs/fcs/ja/index.md
similarity index 100%
rename from fcs/docsrc/content/ja/index.md
rename to docs/fcs/ja/index.md
diff --git a/docs/fcs/ja/interactive.fsx b/docs/fcs/ja/interactive.fsx
new file mode 100644
index 00000000000..7b7133d3c14
--- /dev/null
+++ b/docs/fcs/ja/interactive.fsx
@@ -0,0 +1,299 @@
+(*** hide ***)
+#I "../../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+インタラクティブサービス: F# Interactiveの組み込み
+==================================================
+
+このチュートリアルでは、独自のアプリケーションに
+F# Interactiveを組み込む方法について紹介します。
+F# Interactiveは対話式のスクリプティング環境で、
+F#コードを高度に最適化されたILコードへとコンパイルしつつ、
+それを即座に実行することができます。
+F# Interactiveサービスを使用すると、独自のアプリケーションに
+F#の評価機能を追加できます。
+
+> **注意:** F# Interactiveは様々な方法で組み込むことができます。
+ 最も簡単な方法は `fsi.exe` プロセスとの間で標準入出力経由でやりとりする方法です。
+ このチュートリアルではF# Interactiveの機能を.NET APIで
+ 直接呼び出す方法について紹介します。
+ ただし入力用のコントロールを備えていない場合、別プロセスでF# Interactiveを
+ 起動するのはよい方法だといえます。
+ 理由の1つとしては `StackOverflowException` を処理する方法がないため、
+ 出来の悪いスクリプトによってはホストプロセスが停止させられてしまう
+ 場合があるからです。
+ **.NET APIを通じてF# Interactiveを呼び出すとしても、 `--shadowcopyreferences`
+ オプションは無視されることを覚えておきましょう。**
+ 詳細な議論については、[このスレッド](https://github.com/fsharp/FSharp.Compiler.Service/issues/292)
+ に目を通してみてください。
+ **注意:** もし`FSharp.Core.dll` が見つからないというエラーが出て `FsiEvaluationSession.Create`
+ に失敗した場合、 `FSharp.Core.sigdata` と `FSharp.Core.optdata` というファイルを追加してください。
+ 詳しい内容は[こちら](https://fsharp.github.io/FSharp.Compiler.Service/ja/corelib.html)
+ にあります。
+
+しかしそれでもF# InteractiveサービスにはF# Interactiveを実行ファイルに埋め込んで
+実行出来る(そしてアプリケーションの各機能とやりとり出来る)、あるいは
+機能限定されたF#コード(たとえば独自のDSLによって生成されたコード)だけを
+実行させることが出来るという便利さがあります。
+
+F# Interactiveの開始
+--------------------
+
+まずF# Interactiveサービスを含むライブラリへの参照を追加します:
+*)
+
+#r "FSharp.Compiler.Service.dll"
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+open FSharp.Compiler.Interactive.Shell
+
+(**
+F# Interactiveとやりとりするには、入出力を表すストリームを作成する必要があります。
+これらのストリームを使用することで、
+いくつかのF#コードに対する評価結果を後から出力することができます:
+*)
+open System
+open System.IO
+open System.Text
+
+// 入出力のストリームを初期化
+let sbOut = StringBuilder()
+let sbErr = StringBuilder()
+let inStream = new StringReader("")
+let outStream = new StringWriter(sbOut)
+let errStream = new StringWriter(sbErr)
+
+// コマンドライン引数を組み立てて、FSIセッションを開始する
+let argv = [| "C:\\fsi.exe" |]
+let allArgs = Array.append argv [|"--noninteractive"|]
+
+let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
+let fsiSession = FsiEvaluationSession.Create(fsiConfig, allArgs, inStream, outStream, errStream)
+
+(**
+コードの評価および実行
+----------------------
+
+F# Interactiveサービスにはコードを評価するためのメソッドがいくつか用意されています。
+最初の1つは `EvalExpression` で、式を評価してその結果を返します。
+結果には戻り値が( `obj` として)含まれる他、値に対して静的に推論された型も含まれます:
+*)
+/// 式を評価して結果を返す
+let evalExpression text =
+ match fsiSession.EvalExpression(text) with
+ | Some value -> printfn "%A" value.ReflectionValue
+ | None -> printfn "結果が得られませんでした!"
+
+(**
+これは引数に文字列を取り、それをF#コードとして評価(つまり実行)します。
+*)
+evalExpression "42+1" // '43' を表示する
+
+(**
+これは以下のように強く型付けされた方法で使うことができます:
+*)
+
+/// 式を評価して、強く型付けされた結果を返す
+let evalExpressionTyped<'T> (text) =
+ match fsiSession.EvalExpression(text) with
+ | Some value -> value.ReflectionValue |> unbox<'T>
+ | None -> failwith "結果が得られませんでした!"
+
+evalExpressionTyped "42+1" // '43' になる
+
+
+(**
+`EvalInteraction` メソッドは画面出力機能や宣言、
+F#の式としては不正なものの、F# Interactiveコンソールには入力できるようなものなど、
+副作用を伴う命令を評価する場合に使用できます。
+たとえば `#time "on"` (あるいはその他のディレクティブ)や `open System` 、
+その他の宣言やトップレベルステートメントなどが該当します。
+指定するコードの終端に `;;` を入力する必要はありません。
+実行したいコードだけを入力します:
+*)
+fsiSession.EvalInteraction "printfn \"bye\""
+
+
+(**
+`EvalScript` メソッドを使用すると、完全な .fsx スクリプトを評価することができます。
+*)
+
+File.WriteAllText("sample.fsx", "let twenty = 10 + 10")
+fsiSession.EvalScript "sample.fsx"
+
+(**
+例外処理
+--------
+
+コードに型チェックの警告やエラーがあった場合、または評価して例外で失敗した場合、
+`EvalExpression` 、 `EvalInteraction` そして `EvalScript` ではあまりうまく処理されません。
+これらのケースでは、 `EvalExpressionNonThrowing` 、 `EvalInteractionNonThrowing`
+そして `EvalScriptNonThrowing` を使うことが出来ます。
+これらは結果と `FSharpDiagnostic` 値の配列の組を返します。
+これらはエラーと警告を表します。結果の部分は実際の結果と例外のいずれかを表す
+`Choice<_,_>` です。
+
+`EvalExpression` および `EvalExpressionNonThrowing` の結果部分は
+オプションの `FSharpValue` 値です。
+その値が存在しない場合、式が .NET オブジェクトとして表現できる具体的な結果を
+持っていなかったということを指し示しています。
+この状況は実際には入力されたどんな通常の式に対しても発生すべきではなく、
+ライブラリ内で使われるプリミティブ値に対してのみ発生すべきです。
+*)
+
+File.WriteAllText("sample.fsx", "let twenty = 'a' + 10.0")
+let result, warnings = fsiSession.EvalScriptNonThrowing "sample.fsx"
+
+// 結果を表示する
+match result with
+| Choice1Of2 () -> printfn "チェックと実行はOKでした"
+| Choice2Of2 exn -> printfn "実行例外: %s" exn.Message
+
+
+(**
+は次のようになります:
+
+ 実行例外: Operation could not be completed due to earlier error
+*)
+
+// エラーと警告を表示する
+for w in warnings do
+ printfn "警告 %s 場所 %d,%d" w.Message w.StartLineAlternate w.StartColumn
+
+(**
+は次のようになります:
+
+ 警告 The type 'float' does not match the type 'char' 場所 1,19
+ 警告 The type 'float' does not match the type 'char' 場所 1,17
+
+式に対しては:
+*)
+
+
+let evalExpressionTyped2<'T> text =
+ let res, warnings = fsiSession.EvalExpressionNonThrowing(text)
+ for w in warnings do
+ printfn "警告 %s 場所 %d,%d" w.Message w.StartLineAlternate w.StartColumn
+ match res with
+ | Choice1Of2 (Some value) -> value.ReflectionValue |> unbox<'T>
+ | Choice1Of2 None -> failwith "null または結果がありません"
+ | Choice2Of2 (exn:exn) -> failwith (sprintf "例外 %s" exn.Message)
+
+evalExpressionTyped2 "42+1" // '43' になる
+
+
+(**
+並列実行
+--------
+
+デフォルトでは `EvalExpression` に渡したコードは即時実行されます。
+並列に実行するために、タスクを開始する計算を投入します:
+*)
+
+open System.Threading.Tasks
+
+let sampleLongRunningExpr =
+ """
+async {
+ // 実行したいコード
+ do System.Threading.Thread.Sleep 5000
+ return 10
+}
+ |> Async.StartAsTask"""
+
+let task1 = evalExpressionTyped>(sampleLongRunningExpr)
+let task2 = evalExpressionTyped>(sampleLongRunningExpr)
+
+(**
+両方の計算がいま開始しました。結果を取得することが出来ます:
+*)
+
+
+task1.Result // 完了後に結果が出てくる (最大5秒)
+task2.Result // 完了後に結果が出てくる (最大5秒)
+
+(**
+評価コンテキスト内での型チェック
+--------------------------------
+
+F# Interactiveの一連のスクリプティングセッション中で
+コードの型チェックを実行したいような状況を考えてみましょう。
+たとえばまず宣言を評価します:
+*)
+
+fsiSession.EvalInteraction "let xxx = 1 + 1"
+
+(**
+
+次に部分的に完全な `xxx + xx` というコードの型チェックを実行したいとします:
+*)
+
+let parseResults, checkResults, checkProjectResults =
+ fsiSession.ParseAndCheckInteraction("xxx + xx") |> Async.RunSynchronously
+
+(**
+`parseResults` と `checkResults` はそれぞれ [エディタ](editor.html)
+のページで説明している `ParseFileResults` と `CheckFileResults` 型です。
+たとえば以下のようなコードでエラーを確認出来ます:
+*)
+checkResults.Errors.Length // 1
+
+(**
+コードはF# Interactiveセッション内において、その時点までに実行された
+有効な宣言からなる論理的な型コンテキストと結びつく形でチェックされます。
+
+また、宣言リスト情報やツールチップテキスト、シンボルの解決といった処理を
+要求することもできます:
+
+*)
+
+// ツールチップを取得する
+checkResults.GetToolTipText(1, 2, "xxx + xx", ["xxx"], FSharpTokenTag.IDENT)
+
+checkResults.GetSymbolUseAtLocation(1, 2, "xxx + xx", ["xxx"]) // シンボル xxx
+
+(**
+'fsi'オブジェクト
+-----------------
+
+スクリプトのコードが'fsi'オブジェクトにアクセスできるようにしたい場合、
+このオブジェクトの実装を明示的に渡さなければなりません。
+通常、FSharp.Compiler.Interactive.Settings.dll由来の1つが使われます。
+*)
+
+let fsiConfig2 = FsiEvaluationSession.GetDefaultConfiguration(fsi)
+
+(**
+収集可能なコード生成
+--------------------
+
+FsiEvaluationSessionを使用してコードを評価すると、
+.NET の動的アセンブリを生成し、他のリソースを使用します。
+`collectible=true` を渡すことで、生成されたコードを収集可能に出来ます。
+しかしながら、例えば `EvalExpression` から返される `FsiValue` のような型を必要とする未解放のオブジェクト参照が無く、
+かつ `FsiEvaluationSession` を破棄したに違いない場合に限ってコードが収集されます。
+[収集可能なアセンブリに対する制限](https://msdn.microsoft.com/ja-jp/library/dd554932%28v=vs.110%29.aspx#Anchor_1)
+も参照してください。
+
+以下の例は200個の評価セッションを生成しています。 `collectible=true` と `use session = ...`
+の両方を使っていることに気をつけてください。
+
+収集可能なコードが正しく動いた場合、全体としてのリソース使用量は
+評価が進んでも線形には増加しないでしょう。
+*)
+
+let collectionTest() =
+
+ for i in 1 .. 200 do
+ let defaultArgs = [|"fsi.exe";"--noninteractive";"--nologo";"--gui-"|]
+ use inStream = new StringReader("")
+ use outStream = new StringWriter()
+ use errStream = new StringWriter()
+
+ let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
+ use session = FsiEvaluationSession.Create(fsiConfig, defaultArgs, inStream, outStream, errStream, collectible=true)
+
+ session.EvalInteraction (sprintf "type D = { v : int }")
+ let v = session.EvalExpression (sprintf "{ v = 42 * %d }" i)
+ printfn "その %d, 結果 = %A" i v.Value.ReflectionValue
+
+// collectionTest() <-- このようにテストを実行する
\ No newline at end of file
diff --git a/docs/fcs/ja/project.fsx b/docs/fcs/ja/project.fsx
new file mode 100644
index 00000000000..4f59e11da94
--- /dev/null
+++ b/docs/fcs/ja/project.fsx
@@ -0,0 +1,281 @@
+(*** hide ***)
+#I "../../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+コンパイラサービス: プロジェクトの分析
+======================================
+
+このチュートリアルではF#コンパイラによって提供されるサービスを使用して
+プロジェクト全体を分析する方法について紹介します。
+
+> **注意:** 以下で使用しているAPIは試験的なもので、
+ 最新のnugetパッケージの公開に伴って変更されることがあります。
+
+
+プロジェクト全体の結果を取得する
+--------------------------------
+
+[以前の(型無しASTを使った)チュートリアル](untypedtree.html) と同じく、
+まずは `FSharp.Compiler.Service.dll` への参照追加と、適切な名前空間のオープン、
+`FSharpChecker` インスタンスの作成を行います:
+
+*)
+// F#コンパイラAPIへの参照
+#r "FSharp.Compiler.Service.dll"
+
+open System
+open System.Collections.Generic
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+
+// インタラクティブチェッカーのインスタンスを作成
+let checker = FSharpChecker.Create()
+
+(**
+今回のサンプル入力は以下の通りです:
+*)
+
+module Inputs =
+ open System.IO
+
+ let base1 = Path.GetTempFileName()
+ let fileName1 = Path.ChangeExtension(base1, ".fs")
+ let base2 = Path.GetTempFileName()
+ let fileName2 = Path.ChangeExtension(base2, ".fs")
+ let dllName = Path.ChangeExtension(base2, ".dll")
+ let projFileName = Path.ChangeExtension(base2, ".fsproj")
+ let fileSource1 = """
+module M
+
+type C() =
+ member x.P = 1
+
+let xxx = 3 + 4
+let fff () = xxx + xxx
+ """
+ File.WriteAllText(fileName1, fileSource1)
+
+ let fileSource2 = """
+module N
+
+open M
+
+type D1() =
+ member x.SomeProperty = M.xxx
+
+type D2() =
+ member x.SomeProperty = M.fff()
+
+// 警告を発生させる
+let y2 = match 1 with 1 -> M.xxx
+ """
+ File.WriteAllText(fileName2, fileSource2)
+
+
+(**
+`GetProjectOptionsFromCommandLineArgs` を使用して、
+2つのファイルを1つのプロジェクトとして扱えるようにします:
+*)
+
+let projectOptions =
+ checker.GetProjectOptionsFromCommandLineArgs
+ (Inputs.projFileName,
+ [| yield "--simpleresolution"
+ yield "--noframework"
+ yield "--debug:full"
+ yield "--define:DEBUG"
+ yield "--optimize-"
+ yield "--out:" + Inputs.dllName
+ yield "--doc:test.xml"
+ yield "--warn:3"
+ yield "--fullpaths"
+ yield "--flaterrors"
+ yield "--target:library"
+ yield Inputs.fileName1
+ yield Inputs.fileName2
+ let references =
+ [ @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\mscorlib.dll"
+ @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll"
+ @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll"
+ @"C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.0.0\FSharp.Core.dll"]
+ for r in references do
+ yield "-r:" + r |])
+
+(**
+そして(ディスク上に保存されたファイルを使用して)
+プロジェクト全体をチェックします:
+*)
+
+let wholeProjectResults = checker.ParseAndCheckProject(projectOptions) |> Async.RunSynchronously
+
+(**
+発生したエラーと警告は以下のようにしてチェックできます:
+*)
+wholeProjectResults.Errors.Length // 1
+wholeProjectResults.Errors.[0].Message.Contains("Incomplete pattern matches on this expression") // true
+
+wholeProjectResults.Errors.[0].StartLineAlternate // 13
+wholeProjectResults.Errors.[0].EndLineAlternate // 13
+wholeProjectResults.Errors.[0].StartColumn // 15
+wholeProjectResults.Errors.[0].EndColumn // 16
+
+(**
+推測されたプロジェクトのシグネチャをチェックします:
+*)
+[ for x in wholeProjectResults.AssemblySignature.Entities -> x.DisplayName ] // ["N"; "M"]
+[ for x in wholeProjectResults.AssemblySignature.Entities.[0].NestedEntities -> x.DisplayName ] // ["D1"; "D2"]
+[ for x in wholeProjectResults.AssemblySignature.Entities.[1].NestedEntities -> x.DisplayName ] // ["C"]
+[ for x in wholeProjectResults.AssemblySignature.Entities.[0].MembersFunctionsAndValues -> x.DisplayName ] // ["y2"]
+
+(**
+プロジェクト内の全シンボルを取得することもできます:
+*)
+let rec allSymbolsInEntities (entities: IList) =
+ [ for e in entities do
+ yield (e :> FSharpSymbol)
+ for x in e.MembersFunctionsAndValues do
+ yield (x :> FSharpSymbol)
+ for x in e.UnionCases do
+ yield (x :> FSharpSymbol)
+ for x in e.FSharpFields do
+ yield (x :> FSharpSymbol)
+ yield! allSymbolsInEntities e.NestedEntities ]
+
+let allSymbols = allSymbolsInEntities wholeProjectResults.AssemblySignature.Entities
+(**
+プロジェクト全体のチェックが完了した後は、
+プロジェクト内の各ファイルに対する個別の結果を取得することもできます。
+この処理は即座に完了し、改めてチェックが実行されることもありません。
+*)
+
+let backgroundParseResults1, backgroundTypedParse1 =
+ checker.GetBackgroundCheckResultsForFileInProject(Inputs.fileName1, projectOptions)
+ |> Async.RunSynchronously
+
+
+(**
+そしてそれぞれのファイル内にあるシンボルを解決できます:
+*)
+
+let xSymbol =
+ backgroundTypedParse1.GetSymbolUseAtLocation(9,9,"",["xxx"])
+
+(**
+それぞれのシンボルに対して、シンボルへの参照を検索することもできます:
+*)
+let usesOfXSymbol = wholeProjectResults.GetUsesOfSymbol(xSymbol.Value.Symbol)
+
+(**
+推測されたシグネチャ内にあるすべての定義済みシンボルに対して、
+それらがどこで使用されているのかを探し出すこともできます:
+*)
+let allUsesOfAllSignatureSymbols =
+ [ for s in allSymbols do
+ yield s.ToString(), wholeProjectResults.GetUsesOfSymbol(s) ]
+
+(**
+(ローカルスコープで使用されているものも含めて)
+プロジェクト全体で使用されているすべてのシンボルを確認することもできます:
+*)
+let allUsesOfAllSymbols = wholeProjectResults.GetAllUsesOfAllSymbols()
+
+(**
+また、プロジェクト内のファイルに対して、更新後のバージョンに対して
+チェックを実行するようにリクエストすることもできます
+(なお [FileSystem API](filesystem.html) を使用していない場合には、
+プロジェクト内のその他のファイルがまだディスクから
+読み取り中であることに注意してください):
+
+*)
+let parseResults1, checkAnswer1 =
+ checker.ParseAndCheckFileInProject(Inputs.fileName1, 0, SourceText.ofString Inputs.fileSource1, projectOptions)
+ |> Async.RunSynchronously
+
+let checkResults1 =
+ match checkAnswer1 with
+ | FSharpCheckFileAnswer.Succeeded x -> x
+ | _ -> failwith "想定外の終了状態です"
+
+let parseResults2, checkAnswer2 =
+ checker.ParseAndCheckFileInProject(Inputs.fileName2, 0, SourceText.ofString Inputs.fileSource2, projectOptions)
+ |> Async.RunSynchronously
+
+let checkResults2 =
+ match checkAnswer2 with
+ | FSharpCheckFileAnswer.Succeeded x -> x
+ | _ -> failwith "想定外の終了状態です"
+
+(**
+そして再びシンボルを解決したり、参照を検索したりすることができます:
+*)
+
+let xSymbol2 =
+ checkResults1.GetSymbolUseAtLocation(9,9,"",["xxx"])
+
+let usesOfXSymbol2 = wholeProjectResults.GetUsesOfSymbol(xSymbol2.Value.Symbol)
+
+(**
+あるいは(ローカルスコープで使用されているシンボルも含めて)
+ファイル中で使用されているすべてのシンボルを検索することもできます:
+*)
+let allUsesOfAllSymbolsInFile1 = checkResults1.GetAllUsesOfAllSymbolsInFile()
+
+(**
+あるいは特定のファイル中で使用されているシンボルを検索することもできます:
+*)
+let allUsesOfXSymbolInFile1 = checkResults1.GetUsesOfSymbolInFile(xSymbol2.Value.Symbol)
+
+let allUsesOfXSymbolInFile2 = checkResults2.GetUsesOfSymbolInFile(xSymbol2.Value.Symbol)
+
+(**
+
+複数プロジェクトの分析
+----------------------
+
+複数のプロジェクトにまたがった参照があるような、
+複数のF# プロジェクトを分析したい場合、
+それらのプロジェクトを一旦ビルドして、
+ProjectOptionsで `-r:プロジェクト-出力-までの-パス.dll` 引数を指定して
+プロジェクトの相互参照を設定すると一番簡単です。
+しかしこの場合、それぞれのプロジェクトが正しくビルド出来、
+DLLファイルが参照可能なディスク上に生成されなければいけません。
+
+たとえばIDEを操作している場合など、状況によっては
+DLLのコンパイルが通るようになる前に
+プロジェクトを参照したいことがあるでしょう。
+この場合はProjectOptionsのReferencedProjectsを設定します。
+この値には依存するプロジェクトのオプションを再帰的に指定します。
+それぞれのプロジェクト参照にはやはり、
+ReferencedProjectsのエントリそれぞれに対応する
+`-r:プロジェクト-出力-までの-パス.dll` というコマンドライン引数を
+ProjectOptionsに設定する必要があります。
+
+プロジェクト参照が設定されると、ソースファイルからのF#プロジェクト分析処理が
+インクリメンタル分析の結果を使用して行われるようになります。
+その際にはソースファイルファイルをDLLへとコンパイルする必要はありません。
+
+相互参照を含むようなF#プロジェクトを効率よく分析するには、
+ReferencedProjectsを正しく設定した後、
+それぞれのプロジェクトを順番通りに分析していくとよいでしょう。
+
+> **注意:** プロジェクトの参照機能は試作段階です。
+ プロジェクトの参照を使用すると、依存先のプロジェクトがまだ分析中で、
+ 要求したサービスがまだ利用できないことがあるため、
+ コンパイラサービスの性能が低下することがあります。
+
+> **注意:** アセンブリが型プロバイダーのコンポーネントを含む場合、
+ プロジェクト参照機能は利用できません。
+ プロジェクトの分析処理を強制しない限りはプロジェクト参照を設定しても
+ 効果がありません。
+ また、分析を強制する場合にはディスク上にDLLが存在しなければいけません。
+
+*)
+
+(**
+まとめ
+------
+
+これまで説明してきた通り、 `ParseAndCheckProject` を使用すると
+シンボルの参照などのようなプロジェクト全体の解析結果にアクセスできるようになります。
+シンボルに対する処理の詳細については [シンボル](symbols.html) のページを参照してください。
+
+*)
diff --git a/docs/fcs/ja/symbols.fsx b/docs/fcs/ja/symbols.fsx
new file mode 100644
index 00000000000..bc5994c612d
--- /dev/null
+++ b/docs/fcs/ja/symbols.fsx
@@ -0,0 +1,237 @@
+(*** hide ***)
+#I "../../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+コンパイラサービス: シンボルの処理
+==================================
+
+このチュートリアルでは、F#コンパイラによって提供される
+シンボルの扱い方についてのデモを紹介します。
+シンボルの参照に関する情報については [プロジェクト全体の分析](project.html)
+も参考にしてください。
+
+> **注意:** 以下で使用しているAPIは試験的なもので、
+ 最新のnugetパッケージの公開に伴って変更されることがあります。
+
+これまでと同じく、 `FSharp.Compiler.Service.dll` への参照を追加した後、
+適切な名前空間をオープンし、 `FSharpChecker` のインスタンスを作成します:
+
+*)
+// F#コンパイラAPIへの参照
+#r "FSharp.Compiler.Service.dll"
+
+open System
+open System.IO
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+
+// インタラクティブチェッカーのインスタンスを作成
+let checker = FSharpChecker.Create()
+
+(**
+
+そして特定の入力値に対して型チェックを行います:
+
+*)
+
+let parseAndTypeCheckSingleFile (file, input) =
+ // スタンドアロンの(スクリプト)ファイルを表すコンテキストを取得
+ let projOptions, _errors =
+ checker.GetProjectOptionsFromScript(file, input)
+ |> Async.RunSynchronously
+
+ let parseFileResults, checkFileResults =
+ checker.ParseAndCheckFileInProject(file, 0, input, projOptions)
+ |> Async.RunSynchronously
+
+ // 型チェックが成功(あるいは100%に到達)するまで待機
+ match checkFileResults with
+ | FSharpCheckFileAnswer.Succeeded(res) -> parseFileResults, res
+ | res -> failwithf "Parsing did not finish... (%A)" res
+
+let file = "/home/user/Test.fsx"
+
+(**
+## ファイルに対する解決済みのシグネチャ情報を取得する
+
+ファイルに対する型チェックが完了すると、
+`TypeCheckResults` の `PartialAssemblySignature` プロパティを参照することにより、
+チェック中の特定のファイルを含む、推論されたプロジェクトのシグネチャに
+アクセスすることができます。
+
+モジュールや型、属性、メンバ、値、関数、共用体、レコード型、測定単位、
+およびその他のF#言語要素に対する完全なシグネチャ情報が参照できます。
+
+ただし型付き式ツリーに対する情報は(今のところ)この方法では利用できません。
+
+*)
+
+let input2 =
+ """
+[]
+let foo(x, y) =
+ let msg = String.Concat("Hello"," ","world")
+ if true then
+ printfn "x = %d, y = %d" x y
+ printfn "%s" msg
+
+type C() =
+ member x.P = 1
+ """
+let parseFileResults, checkFileResults =
+ parseAndTypeCheckSingleFile(file, SourceText.ofString input2)
+
+(**
+これでコードに対する部分的なアセンブリのシグネチャが取得できるようになります:
+*)
+let partialAssemblySignature = checkFileResults.PartialAssemblySignature
+
+partialAssemblySignature.Entities.Count = 1 // エンティティは1つ
+
+(**
+そしてコードを含むモジュールに関連したエンティティを取得します:
+*)
+let moduleEntity = partialAssemblySignature.Entities.[0]
+
+moduleEntity.DisplayName = "Test"
+
+(**
+そしてコード内の型定義に関連したエンティティを取得します:
+*)
+let classEntity = moduleEntity.NestedEntities.[0]
+
+(**
+そしてコード内で定義された関数に関連した値を取得します:
+*)
+let fnVal = moduleEntity.MembersFunctionsAndValues.[0]
+
+(**
+関数値に関するプロパティの値を確認してみましょう。
+*)
+fnVal.Attributes.Count // 1
+fnVal.CurriedParameterGroups.Count // 1
+fnVal.CurriedParameterGroups.[0].Count // 2
+fnVal.CurriedParameterGroups.[0].[0].Name // "x"
+fnVal.CurriedParameterGroups.[0].[1].Name // "y"
+fnVal.DeclarationLocation.StartLine // 3
+fnVal.DisplayName // "foo"
+fnVal.DeclaringEntity.Value.DisplayName // "Test"
+fnVal.DeclaringEntity.Value.DeclarationLocation.StartLine // 1
+fnVal.GenericParameters.Count // 0
+fnVal.InlineAnnotation // FSharpInlineAnnotation.OptionalInline
+fnVal.IsActivePattern // false
+fnVal.IsCompilerGenerated // false
+fnVal.IsDispatchSlot // false
+fnVal.IsExtensionMember // false
+fnVal.IsPropertyGetterMethod // false
+fnVal.IsImplicitConstructor // false
+fnVal.IsInstanceMember // false
+fnVal.IsMember // false
+fnVal.IsModuleValueOrMember // true
+fnVal.IsMutable // false
+fnVal.IsPropertySetterMethod // false
+fnVal.IsTypeFunction // false
+
+(**
+次に、この関数の型がファーストクラスの値として使用されているかどうかチェックします。
+(ちなみに `CurriedParameterGroups` プロパティには引数の名前など、
+より多くの情報も含まれています)
+*)
+fnVal.FullType // int * int -> unit
+fnVal.FullType.IsFunctionType // true
+fnVal.FullType.GenericArguments.[0] // int * int
+fnVal.FullType.GenericArguments.[0].IsTupleType // true
+let argTy1 = fnVal.FullType.GenericArguments.[0].GenericArguments.[0]
+
+argTy1.TypeDefinition.DisplayName // int
+
+(**
+というわけで `int * int -> unit` という型を表現するオブジェクトが取得できて、
+その1つめの 'int' を確認できたわけです。
+また、以下のようにすると 'int' 型についてのより詳細な情報が取得でき、
+それが名前付きの型であり、F#の型省略形 `type int = int32` であることがわかります:
+*)
+
+argTy1.HasTypeDefinition // true
+argTy1.TypeDefinition.IsFSharpAbbreviation // true
+
+(**
+型省略形の右辺、つまり `int32` についてもチェックしてみましょう:
+*)
+
+let argTy1b = argTy1.TypeDefinition.AbbreviatedType
+argTy1b.TypeDefinition.Namespace // Some "Microsoft.FSharp.Core"
+argTy1b.TypeDefinition.CompiledName // "int32"
+
+(**
+そして再び型省略形 `type int32 = System.Int32` から型に関する完全な情報が取得できます:
+*)
+let argTy1c = argTy1b.TypeDefinition.AbbreviatedType
+argTy1c.TypeDefinition.Namespace // Some "System"
+argTy1c.TypeDefinition.CompiledName // "Int32"
+
+(**
+ファイルに対する型チェックの結果には、
+コンパイル時に使用されたプロジェクト(あるいはスクリプト)のオプションに関する
+`ProjectContext` と呼ばれる情報も含まれています:
+*)
+let projectContext = checkFileResults.ProjectContext
+
+for assembly in projectContext.GetReferencedAssemblies() do
+ match assembly.FileName with
+ | None -> printfn "コンパイル時にファイルの存在しないアセンブリを参照しました"
+ | Some s -> printfn "コンパイル時にアセンブリ '%s' を参照しました" s
+
+(**
+**注意:**
+
+ - 不完全なコードが存在する場合、一部あるいはすべての属性が意図したとおりには
+ 並ばないことがあります。
+ - (実際には非常によくあることですが)一部のアセンブリが見つからない場合、
+ 外部アセンブリに関連する値やメンバ、エンティティにおける 'IsUnresolved' が
+ trueになることがあります。
+ IsUnresolvedによる例外に対処できるよう、堅牢なコードにしておくべきです。
+
+*)
+
+(**
+
+## プロジェクト全体に対するシンボル情報を取得する
+
+プロジェクト全体をチェックする場合、チェッカーを作成した後に `parseAndCheckScript`
+を呼び出します。
+今回の場合は単に1つのスクリプトだけが含まれたプロジェクトをチェックします。
+異なる "projOptions" を指定すると、巨大なプロジェクトに対する設定を
+構成することもできます。
+*)
+let parseAndCheckScript (file, input) =
+ let projOptions, errors =
+ checker.GetProjectOptionsFromScript(file, SourceText.ofString input)
+ |> Async.RunSynchronously
+
+ let projResults =
+ checker.ParseAndCheckProject(projOptions)
+ |> Async.RunSynchronously
+
+ projResults
+
+(**
+そして特定の入力に対してこの関数を呼び出します:
+*)
+
+let tmpFile = Path.ChangeExtension(System.IO.Path.GetTempFileName() , "fs")
+File.WriteAllText(tmpFile, input2)
+
+let projectResults = parseAndCheckScript(tmpFile, input2)
+
+
+(**
+結果は以下の通りです:
+*)
+
+let assemblySig = projectResults.AssemblySignature
+
+assemblySig.Entities.Count = 1 // エンティティは1つ
+assemblySig.Entities.[0].Namespace // null
+assemblySig.Entities.[0].DisplayName // "Tmp28D0"
+assemblySig.Entities.[0].MembersFunctionsAndValues.Count // 1
+assemblySig.Entities.[0].MembersFunctionsAndValues.[0].DisplayName // "foo"
diff --git a/docs/fcs/ja/tokenizer.fsx b/docs/fcs/ja/tokenizer.fsx
new file mode 100644
index 00000000000..e2c83b5f6c3
--- /dev/null
+++ b/docs/fcs/ja/tokenizer.fsx
@@ -0,0 +1,146 @@
+(*** hide ***)
+#I "../../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+コンパイラサービス:F#トークナイザを使用する
+============================================
+
+このチュートリアルではF#言語トークナイザの呼び出し方を紹介します。
+F#のソースコードに対して、トークナイザは
+コードの各行にあるトークンに関する情報を含んだソースコード行のリストを生成します。
+各トークンに対してはトークンの種類や位置を取得したり、
+トークンの種類(キーワード、識別子、数値、演算子など)に応じた
+色を取得したりすることができます。
+
+> **注意:** 以下で使用しているAPIは実験的なもので、
+ 新しいnugetパッケージの公開に伴って変更される可能性があります。
+
+トークナイザの作成
+------------------
+
+トークナイザを使用するには、 `FSharp.Compiler.Service.dll` への参照を追加した後に
+`SourceCodeServices` 名前空間をオープンします:
+*)
+#r "FSharp.Compiler.Service.dll"
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+(**
+すると `FSharpSourceTokenizer` のインスタンスを作成できるようになります。
+このクラスには2つの引数を指定します。
+最初の引数には定義済みのシンボルのリスト、
+2番目の引数にはソースコードのファイル名を指定します。
+定義済みのシンボルのリストを指定するのは、
+トークナイザが `#if` ディレクティブを処理する必要があるからです。
+ファイル名はソースコードの位置を特定する場合にのみ指定する必要があります
+(存在しないファイル名でも指定できます):
+*)
+let sourceTok = FSharpSourceTokenizer([], Some "C:\\test.fsx")
+(**
+`sourceTok` オブジェクトを使用することでF#ソースコードの各行を
+(繰り返し)トークン化することができます。
+
+F#コードのトークン化
+--------------------
+
+トークナイザはソースファイル全体ではなく、行単位で処理を行います。
+トークンを取得した後、トークナイザは新しいステートを( `int64` 値として)返します。
+この値を使うとF#コードをより効率的にトークン化できます。
+つまり、ソースコードが変更された場合もファイル全体を
+再度トークン化する必要はありません。
+変更された部分だけをトークン化すればよいのです。
+
+### 1行をトークン化する
+
+1行をトークン化するには、先ほど作成した `FSharpSourceTokenizer` オブジェクトに対して
+`CreateLineTokenizer` を呼び、 `FSharpLineTokenizer` を作成します:
+*)
+let tokenizer = sourceTok.CreateLineTokenizer("let answer=42")
+(**
+そして `tokenizer` の `ScanToken` を繰り返し `None` を返すまで
+(つまり最終行に到達するまで)繰り返し呼び出すような単純な再帰関数を用意します。
+この関数が成功すると、必要な詳細情報をすべて含んだ `FSharpTokenInfo` オブジェクトが
+返されます:
+*)
+/// F#コード1行をトークン化します
+let rec tokenizeLine (tokenizer:FSharpLineTokenizer) state =
+ match tokenizer.ScanToken(state) with
+ | Some tok, state ->
+ // トークン名を表示
+ printf "%s " tok.TokenName
+ // 新しい状態で残りをトークン化
+ tokenizeLine tokenizer state
+ | None, state -> state
+(**
+この関数は、複数行コードや複数行コメント内の前方の行をトークン化する場合に
+必要となるような新しい状態を返します。
+初期値としては `0L` を指定します:
+*)
+tokenizeLine tokenizer FSharpTokenizerLexState.Initial
+(**
+この結果は LET WHITESPACE IDENT EQUALS INT32 という
+トークン名のシーケンスになります。
+`FSharpTokenInfo` にはたとえば以下のような興味深いプロパティが多数あります:
+
+ - `CharClass` および `ColorClass` はF#コードを色づけする場合に使用できるような、
+ トークンのカテゴリに関する情報を返します。
+ - `LeftColumn` および `RightColumn` は行内におけるトークンの位置を返します。
+ - `TokenName` は(F# レキサ内で定義された)トークンの名前を返します。
+
+なおトークナイザはステートフルであることに注意してください。
+つまり、1行を複数回トークン化したい場合にはその都度 `CreateLineTokenizer` を
+呼び出す必要があります。
+
+### サンプルコードのトークン化
+
+トークナイザをもっと長いサンプルコードやファイル全体に対して実行する場合、
+サンプル入力を `string` のコレクションとして読み取る必要があります:
+*)
+let lines = """
+ // Hello world
+ let hello() =
+ printfn "Hello world!" """.Split('\r','\n')
+(**
+複数行の入力値をトークン化する場合も、現在の状態を保持するような
+再帰関数が必要になります。
+以下の関数はソースコード行を文字列のリストとして受け取ります
+(また、行番号および現在の状態も受け取ります)。
+各行に対して新しいトークナイザを作成して、
+直前の行における **最後** の状態を使って `tokenizeLine` を呼び出します:
+*)
+/// 複数行のコードに対してトークンの名前を表示します
+let rec tokenizeLines state count lines =
+ match lines with
+ | line::lines ->
+ // トークナイザを作成して1行をトークン化
+ printfn "\nLine %d" count
+ let tokenizer = sourceTok.CreateLineTokenizer(line)
+ let state = tokenizeLine tokenizer state
+ // 新しい状態を使って残りをトークン化
+ tokenizeLines state (count+1) lines
+ | [] -> ()
+(**
+ここでは単に(先ほど定義した) `tokenizeLine` を呼び出して、
+各行にあるすべてのトークンの名前を表示しています。
+この関数は先と同じく、初期状態の値 `0L` と、1行目を表す `1` を
+指定して呼び出すことができます:
+*)
+lines
+|> List.ofSeq
+|> tokenizeLines FSharpTokenizerLexState.Initial 1
+(**
+重要ではない部分(各行の先頭にある空白文字や、1行目のように空白文字しかない行)
+を除けば、このコードを実行すると以下のような出力になります:
+
+ [lang=text]
+ Line 1
+ LINE_COMMENT LINE_COMMENT (...) LINE_COMMENT
+ Line 2
+ LET WHITESPACE IDENT LPAREN RPAREN WHITESPACE EQUALS
+ Line 3
+ IDENT WHITESPACE STRING_TEXT (...) STRING_TEXT STRING
+
+注目すべきは、単一行コメントや文字列に対して、
+トークナイザが複数回(大まかにいって単語単位で) `LINE_COMMENT` や
+`STRING_TEXT` を返しているところです。
+したがって、コメントや文字列全体をテキストとして取得したい場合には
+それぞれのトークンを連結する必要があります。
+*)
\ No newline at end of file
diff --git a/docs/fcs/ja/untypedtree.fsx b/docs/fcs/ja/untypedtree.fsx
new file mode 100644
index 00000000000..f4050109d2c
--- /dev/null
+++ b/docs/fcs/ja/untypedtree.fsx
@@ -0,0 +1,277 @@
+(*** hide ***)
+#I "../../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+コンパイラサービス:型無し構文木の処理
+======================================
+
+このチュートリアルではF#コードに対する型無し抽象構文木
+(untyped abstract syntax tree: untyped AST)
+を取得する方法、および木全体を走査する方法を紹介します。
+この処理を行うことによって、コードフォーマットツールや
+基本的なリファクタリングツール、コードナビゲーションツールなどを作成できます。
+型無し構文木にはコードの構造に関する情報が含まれていますが、
+型情報が含まれていないだけでなく、後で型チェッカーを通すまでは
+解決されないような曖昧さも残されています。
+また、 [エディタサービス](editor.html) として提供されているAPIと
+型無しASTの情報を組み合わせることもできます。
+
+> **注釈:** 以下で使用しているAPIは試験的なもので、将来的に変更される場合があります。
+ つまりFSharp.Compiler.Service.dll には既存のものと重複する機能が多数あるため、
+ 将来的にはもっときちんとした形に変更されます。
+ そのため、これらのサービスを使用するAPIには破壊的変更が加えられる可能性があります。
+
+
+型無しASTの取得
+---------------
+
+
+型無しASTにアクセスするには、 `FSharpChecker` のインスタンスを作成します。
+これは型チェックおよびパース用のコンテキストを表す型で、、
+スタンドアロンのF#スクリプトファイル(たとえばVisual Studioで開いたファイル)、
+あるいは複数ファイルで構成されたロード済みのプロジェクトファイルの
+いずれかと結びつきます。
+このインスタンスを作成すると、型チェックの最初のステップである
+「型無しパース」を実行できます。
+次のフェーズは「型有りパース」で、これは [エディタサービス](editor.html) で
+使用されるものです。
+
+インタラクティブチェッカーを使用するには、
+`FSharp.Compiler.Service.dll` への参照を追加した後、
+`SourceCodeServices` 名前空間をオープンします:
+*)
+#r "FSharp.Compiler.Service.dll"
+open System
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+(**
+
+### 型無しパースの実行
+
+型無しパース処理は(それなりの時間がかかる型チェック処理と比較すると)
+かなり高速なため、同期的に実行できます。
+まず `FSharpChecker` を作成します。
+
+*)
+// インタラクティブチェッカーのインスタンスを作成
+let checker = FSharpChecker.Create()
+(**
+
+ASTを取得するために、ファイル名とソースコードを受け取る関数を用意します
+(ファイル名は位置情報のためだけに使用されるもので、存在しなくても構いません)。
+まず、コンテキストを表す「インタラクティブチェッカーオプション」を
+用意する必要があります。
+単純な処理に対しては、 `GetCheckOptionsFromScriptRoot` を使えば
+スクリプトファイルのコンテキストを推測させることができます。
+そして `UntypedParse` メソッドを呼び出した後、
+`ParseTree` プロパティの値を返します:
+
+*)
+/// 特定の入力に対する型無し構文木を取得する
+let getUntypedTree (file, input) =
+ // 1つのスクリプトファイルから推測される「プロジェクト」用の
+ // コンパイラオプションを取得する
+ let projOptions, errors =
+ checker.GetProjectOptionsFromScript(file, SourceText.ofString input)
+ |> Async.RunSynchronously
+
+ let parsingOptions, _errors = checker.GetParsingOptionsFromProjectOptions(projOptions)
+
+ // コンパイラの第1フェーズを実行する
+ let untypedRes =
+ checker.ParseFile(file, SourceText.ofString input, parsingOptions)
+ |> Async.RunSynchronously
+
+ match untypedRes.ParseTree with
+ | Some tree -> tree
+ | None -> failwith "パース中に何らかの問題が発生しました!"
+
+(**
+`FSharpChecker` の詳細については
+[ APIドキュメント](../reference/microsoft-fsharp-compiler-sourcecodeservices-FSharpChecker.html)
+の他に、F# ソースコードのインラインコメントも参考になるでしょう
+( [`service.fsi` のソースコードを参照](https://github.com/fsharp/fsharp/blob/fsharp_31/src/fsharp/service/service.fsi) )。
+
+ASTの走査
+---------
+
+抽象構文木は(式やパターン、宣言など)それぞれ異なる文法的要素を表現する、
+多数の判別共用体として定義されています。
+ASTを理解するには
+[`ast.fs`内にあるソースコード](https://github.com/fsharp/fsharp/blob/master/src/fsharp/ast.fs#L464)
+の定義を確認する方法が一番よいでしょう。
+
+ASTに関連する要素は以下の名前空間に含まれています:
+*)
+open FSharp.Compiler.SyntaxTree
+(**
+
+ASTを処理する場合、異なる文法的要素に対するパターンマッチを行うような
+相互再帰関数を多数用意することになります。
+サポートすべき要素は非常に多種多様です。
+たとえばトップレベル要素としてはモジュールや名前空間の宣言、
+モジュール内における(letバインディングや型などの)宣言などがあります。
+モジュール内のlet宣言には式が含まれ、さらにこの式に
+パターンが含まれていることもあります。
+
+### パターンと式を走査する
+
+まずは式とパターンを走査する関数から始めます。
+この関数は要素を走査しつつ、要素に関する情報を画面に表示します。
+パターンの場合、入力は `SynPat` 型であり、この型には `Wild` ( `_` パターンを表す)や
+`Named` ( ` という名前` のパターン)、
+`LongIdent` ( `Foo.Bar` 形式の名前)など、多数のケースがあります。
+なお、基本的にパース後のパターンは元のソースコードの見た目よりも複雑になります
+(具体的には `Named` がかなり多数現れます):
+*)
+/// パターンの走査
+/// これは let = あるいは 'match' 式に対する例です
+let rec visitPattern = function
+ | SynPat.Wild(_) ->
+ printfn " .. アンダースコアパターン"
+ | SynPat.Named(pat, name, _, _, _) ->
+ visitPattern pat
+ printfn " .. 名前 '%s' のパターン" name.idText
+ | SynPat.LongIdent(LongIdentWithDots(ident, _), _, _, _, _, _) ->
+ let names = String.concat "." [ for i in ident -> i.idText ]
+ printfn " .. 識別子: %s" names
+ | pat -> printfn " .. その他のパターン: %A" pat
+(**
+この関数は (`bar という名前の (foo, _)` のような、
+ネストされたパターンに対応するために) 再帰関数になっていますが、
+以降で定義するいずれの関数も呼び出しません
+(パターンはその他の文法的な要素を含むことができないからです)。
+
+次の関数は式全体を走査するものです。
+これは処理の大部分が行われる関数で、
+20以上のケースをカバーすることになるでしょう
+( `SynExpr` と入力するとその他のオプションが確認できます)。
+以下のコードでは `if .. then ..` と `let .. = ...` という式を
+処理する方法だけを紹介しています:
+*)
+/// 式を走査する。
+/// 式に2つあるいは3つの部分式が含まれていた場合('else'の分岐がない場合は2つ)、
+/// let式にはパターンおよび2つの部分式が含まれる
+let rec visitExpression = function
+ | SynExpr.IfThenElse(cond, trueBranch, falseBranchOpt, _, _, _, _) ->
+ // すべての部分式を走査
+ printfn "条件部:"
+ visitExpression cond
+ visitExpression trueBranch
+ falseBranchOpt |> Option.iter visitExpression
+
+ | SynExpr.LetOrUse(_, _, bindings, body, _) ->
+ // バインディングを走査
+ // ('let .. = .. and .. = .. in ...' に対しては複数回走査されることがある)
+ printfn "以下のバインディングを含むLetOrUse:"
+ for binding in bindings do
+ let (Binding(access, kind, inlin, mutabl, attrs, xmlDoc,
+ data, pat, retInfo, init, m, sp)) = binding
+ visitPattern pat
+ visitExpression init
+ // 本体の式を走査
+ printfn "本体は以下:"
+ visitExpression body
+ | expr -> printfn " - サポート対象外の式: %A" expr
+(**
+`visitExpression` 関数はモジュール内のすべてのトップレベル宣言を走査するような
+関数から呼ばれることになります。
+今回のチュートリアルでは型やメンバーを無視していますが、
+これらを走査する場合も `visitExpression` を呼び出すことになるでしょう。
+
+### 宣言を走査する
+
+既に説明したように、1つのファイルに対するASTには多数のモジュールや
+名前空間の宣言が(トップレベルノードとして)含まれ、
+モジュール内にも(letバインディングや型の)宣言が、
+名前空間にも(こちらは単に型だけの)宣言が含まれます。
+以下の関数はそれぞれの宣言を走査します。
+ただし今回は型やネストされたモジュール、その他の要素については無視して、
+トップレベルの(値および関数に対する) `let` バインディングだけを対象にしています:
+*)
+/// モジュール内の宣言リストを走査する。
+/// モジュール内のトップレベルに記述できるすべての要素
+/// (letバインディングやネストされたモジュール、型の宣言など)が対象になる。
+let visitDeclarations decls =
+ for declaration in decls do
+ match declaration with
+ | SynModuleDecl.Let(isRec, bindings, range) ->
+ // 宣言としてのletバインディングは
+ // (visitExpressionで処理したような)式としてのletバインディングと
+ // 似ているが、本体を持たない
+ for binding in bindings do
+ let (Binding(access, kind, inlin, mutabl, attrs, xmlDoc,
+ data, pat, retInfo, body, m, sp)) = binding
+ visitPattern pat
+ visitExpression body
+ | _ -> printfn " - サポート対象外の宣言: %A" declaration
+(**
+`visitDeclarations` 関数はモジュールや名前空間の宣言のシーケンスを走査する
+関数から呼ばれることになります。
+このシーケンスはたとえば複数の `namespace Foo` 宣言を含むようなファイルに対応します:
+*)
+/// すべてのモジュールや名前空間の宣言を走査する
+/// (基本的には 'module Foo =' または 'namespace Foo.Bar' というコード)
+/// なおファイル中で明示的に定義されていない場合であっても
+/// 暗黙的にモジュールまたは名前空間の宣言が存在することに注意。
+let visitModulesAndNamespaces modulesOrNss =
+ for moduleOrNs in modulesOrNss do
+ let (SynModuleOrNamespace(lid, isRec, isMod, decls, xml, attrs, _, m)) = moduleOrNs
+ printfn "名前空間またはモジュール: %A" lid
+ visitDeclarations decls
+(**
+以上でASTの要素を(宣言から始まって式やパターンに至るまで)走査するための
+関数がそろったので、サンプル入力からASTを取得した後、
+上記の関数を実行することができるようになりました。
+
+すべてを組み合わせる
+--------------------
+
+既に説明したように、 `getUntypedTree` 関数では `FSharpChecker` を使って
+ASTに対する第1フェーズ(パース)を行ってツリーを返しています。
+この関数にはF#のソースコードとともに、ファイルのパスを指定する必要があります。
+(単に位置情報として利用されるだけなので)
+指定先のパスにファイルが存在している必要はなく、
+UnixとWindowsどちらの形式でも指定できます:
+*)
+// コンパイラサービスへのサンプル入力
+let input = """
+ let foo() =
+ let msg = "Hello world"
+ if true then
+ printfn "%s" msg """
+// Unix形式のファイル名
+let file = "/home/user/Test.fsx"
+
+// サンプルF#コードに対するASTを取得
+let tree = getUntypedTree(file, input)
+(**
+このコードをF# Interactiveで実行した場合、コンソールに `tree;;` と入力すると、
+データ構造に対する文字列表現が表示されることが確認できます。
+ツリーには大量の情報が含まれているため、あまり読みやすいものではありませんが、
+木が動作する様子を想像することはできるでしょう。
+
+`tree` の返値はやはり判別共用体で、2つのケースに分かれます。
+1つはF#のシグネチャファイル( `*.fsi` )を表す `ParsedInput.SigFile` で、
+もう1つは通常のソースコード( `*.fsx` または `*.fs` )を表す
+`ParsedInput.ImplFile` です。
+上記の手順で作成した関数に渡すことができるモジュールや名前空間のシーケンスは
+実装ファイルに含まれています:
+*)
+// 実装ファイルの詳細をチェックする
+match tree with
+| ParsedInput.ImplFile(implFile) ->
+ // 宣言を展開してそれぞれを走査する
+ let (ParsedImplFileInput(fn, script, name, _, _, modules, _)) = implFile
+ visitModulesAndNamespaces modules
+| _ -> failwith "F# インターフェイスファイル (*.fsi) は未サポートです。"
+(**
+まとめ
+------
+このチュートリアルでは型無し抽象構文木に対する基本的な走査方法を紹介しました。
+このトピックは包括的なものであるため、1つの記事ですべてを説明することは不可能です。
+さらに深く理解するためには、型無しASTを活用するツールのよい例として
+[Fantomas project](https://github.com/dungpa/fantomas) を参考にするとよいでしょう。
+実際には今回参照したような情報と、次のチュートリアルで説明する
+[エディタサービス](editor.html) から得られる情報とを
+組み合わせて利用することになるでしょう。
+*)
diff --git a/docs/fcs/project.fsx b/docs/fcs/project.fsx
new file mode 100644
index 00000000000..7988face34e
--- /dev/null
+++ b/docs/fcs/project.fsx
@@ -0,0 +1,309 @@
+(*** hide ***)
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+Compiler Services: Project Analysis
+==================================
+
+This tutorial demonstrates how to can analyze a whole project using services provided by the F# compiler.
+
+> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published.
+
+*)
+
+
+(**
+
+Getting whole-project results
+-----------------------------
+
+As in the [previous tutorial (using untyped AST)](untypedtree.html), we start by referencing
+`FSharp.Compiler.Service.dll`, opening the relevant namespace and creating an instance
+of `InteractiveChecker`:
+
+*)
+// Reference F# compiler API
+#r "FSharp.Compiler.Service.dll"
+
+open System
+open System.Collections.Generic
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+
+// Create an interactive checker instance
+let checker = FSharpChecker.Create()
+
+(**
+Here are our sample inputs:
+*)
+
+module Inputs =
+ open System.IO
+
+ let base1 = Path.GetTempFileName()
+ let fileName1 = Path.ChangeExtension(base1, ".fs")
+ let base2 = Path.GetTempFileName()
+ let fileName2 = Path.ChangeExtension(base2, ".fs")
+ let dllName = Path.ChangeExtension(base2, ".dll")
+ let projFileName = Path.ChangeExtension(base2, ".fsproj")
+ let fileSource1 = """
+module M
+
+type C() =
+ member x.P = 1
+
+let xxx = 3 + 4
+let fff () = xxx + xxx
+ """
+ File.WriteAllText(fileName1, fileSource1)
+
+ let fileSource2 = """
+module N
+
+open M
+
+type D1() =
+ member x.SomeProperty = M.xxx
+
+type D2() =
+ member x.SomeProperty = M.fff() + D1().P
+
+// Generate a warning
+let y2 = match 1 with 1 -> M.xxx
+ """
+ File.WriteAllText(fileName2, fileSource2)
+
+
+(**
+We use `GetProjectOptionsFromCommandLineArgs` to treat two files as a project:
+*)
+
+let projectOptions =
+ let sysLib nm =
+ if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then
+ // file references only valid on Windows
+ System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86) +
+ @"\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\" + nm + ".dll"
+ else
+ let sysDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()
+ let (++) a b = System.IO.Path.Combine(a,b)
+ sysDir ++ nm + ".dll"
+
+ let fsCore4300() =
+ if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then
+ // file references only valid on Windows
+ System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86) +
+ @"\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.0.0\FSharp.Core.dll"
+ else
+ sysLib "FSharp.Core"
+
+ checker.GetProjectOptionsFromCommandLineArgs
+ (Inputs.projFileName,
+ [| yield "--simpleresolution"
+ yield "--noframework"
+ yield "--debug:full"
+ yield "--define:DEBUG"
+ yield "--optimize-"
+ yield "--out:" + Inputs.dllName
+ yield "--doc:test.xml"
+ yield "--warn:3"
+ yield "--fullpaths"
+ yield "--flaterrors"
+ yield "--target:library"
+ yield Inputs.fileName1
+ yield Inputs.fileName2
+ let references =
+ [ sysLib "mscorlib"
+ sysLib "System"
+ sysLib "System.Core"
+ fsCore4300() ]
+ for r in references do
+ yield "-r:" + r |])
+
+(**
+Now check the entire project (using the files saved on disk):
+*)
+
+let wholeProjectResults = checker.ParseAndCheckProject(projectOptions) |> Async.RunSynchronously
+
+(**
+Now look at the errors and warnings:
+*)
+wholeProjectResults .Errors.Length // 1
+wholeProjectResults.Errors.[0].Message.Contains("Incomplete pattern matches on this expression") // yes it does
+
+wholeProjectResults.Errors.[0].StartLineAlternate // 13
+wholeProjectResults.Errors.[0].EndLineAlternate // 13
+wholeProjectResults.Errors.[0].StartColumn // 15
+wholeProjectResults.Errors.[0].EndColumn // 16
+
+(**
+Now look at the inferred signature for the project:
+*)
+[ for x in wholeProjectResults.AssemblySignature.Entities -> x.DisplayName ] // ["N"; "M"]
+[ for x in wholeProjectResults.AssemblySignature.Entities.[0].NestedEntities -> x.DisplayName ] // ["D1"; "D2"]
+[ for x in wholeProjectResults.AssemblySignature.Entities.[1].NestedEntities -> x.DisplayName ] // ["C"]
+[ for x in wholeProjectResults.AssemblySignature.Entities.[0].MembersFunctionsAndValues -> x.DisplayName ] // ["y"; "y2"]
+
+(**
+You can also get all symbols in the project:
+*)
+let rec allSymbolsInEntities (entities: IList) =
+ [ for e in entities do
+ yield (e :> FSharpSymbol)
+ for x in e.MembersFunctionsAndValues do
+ yield (x :> FSharpSymbol)
+ for x in e.UnionCases do
+ yield (x :> FSharpSymbol)
+ for x in e.FSharpFields do
+ yield (x :> FSharpSymbol)
+ yield! allSymbolsInEntities e.NestedEntities ]
+
+let allSymbols = allSymbolsInEntities wholeProjectResults.AssemblySignature.Entities
+(**
+After checking the whole project, you can access the background results for individual files
+in the project. This will be fast and will not involve any additional checking.
+*)
+
+let backgroundParseResults1, backgroundTypedParse1 =
+ checker.GetBackgroundCheckResultsForFileInProject(Inputs.fileName1, projectOptions)
+ |> Async.RunSynchronously
+
+
+(**
+You can now resolve symbols in each file:
+*)
+
+let xSymbolUseOpt =
+ backgroundTypedParse1.GetSymbolUseAtLocation(9,9,"",["xxx"])
+
+let xSymbolUse = xSymbolUseOpt.Value
+
+let xSymbol = xSymbolUse.Symbol
+
+(**
+You can find out more about a symbol by doing type checks on various symbol kinds:
+*)
+
+let xSymbolAsValue =
+ match xSymbol with
+ | :? FSharpMemberOrFunctionOrValue as xSymbolAsVal -> xSymbolAsVal
+ | _ -> failwith "we expected this to be a member, function or value"
+
+
+(**
+For each symbol, you can look up the references to that symbol:
+*)
+let usesOfXSymbol =
+ wholeProjectResults.GetUsesOfSymbol(xSymbol)
+
+(**
+You can iterate all the defined symbols in the inferred signature and find where they are used:
+*)
+let allUsesOfAllSignatureSymbols =
+ [ for s in allSymbols do
+ let uses = wholeProjectResults.GetUsesOfSymbol(s)
+ yield s.ToString(), uses ]
+
+(**
+You can also look at all the symbols uses in the whole project (including uses of symbols with local scope)
+*)
+let allUsesOfAllSymbols =
+ wholeProjectResults.GetAllUsesOfAllSymbols()
+
+(**
+You can also request checks of updated versions of files within the project (note that the other files
+in the project are still read from disk, unless you are using the [FileSystem API](filesystem.html)):
+
+*)
+
+let parseResults1, checkAnswer1 =
+ checker.ParseAndCheckFileInProject(Inputs.fileName1, 0, SourceText.ofString Inputs.fileSource1, projectOptions)
+ |> Async.RunSynchronously
+
+let checkResults1 =
+ match checkAnswer1 with
+ | FSharpCheckFileAnswer.Succeeded x -> x
+ | _ -> failwith "unexpected aborted"
+
+let parseResults2, checkAnswer2 =
+ checker.ParseAndCheckFileInProject(Inputs.fileName2, 0, SourceText.ofString Inputs.fileSource2, projectOptions)
+ |> Async.RunSynchronously
+
+let checkResults2 =
+ match checkAnswer2 with
+ | FSharpCheckFileAnswer.Succeeded x -> x
+ | _ -> failwith "unexpected aborted"
+
+(**
+Again, you can resolve symbols and ask for references:
+*)
+
+let xSymbolUse2Opt =
+ checkResults1.GetSymbolUseAtLocation(9,9,"",["xxx"])
+
+let xSymbolUse2 = xSymbolUse2Opt.Value
+
+let xSymbol2 = xSymbolUse2.Symbol
+
+let usesOfXSymbol2 =
+ wholeProjectResults.GetUsesOfSymbol(xSymbol2)
+
+(**
+Or ask for all the symbols uses in the file (including uses of symbols with local scope)
+*)
+let allUsesOfAllSymbolsInFile1 =
+ checkResults1.GetAllUsesOfAllSymbolsInFile()
+
+(**
+Or ask for all the uses of one symbol in one file:
+*)
+let allUsesOfXSymbolInFile1 =
+ checkResults1.GetUsesOfSymbolInFile(xSymbol2)
+
+let allUsesOfXSymbolInFile2 =
+ checkResults2.GetUsesOfSymbolInFile(xSymbol2)
+
+(**
+
+Analyzing multiple projects
+-----------------------------
+
+If you have multiple F# projects to analyze which include references from some projects to others,
+then the simplest way to do this is to build the projects and specify the cross-project references using
+a `-r:path-to-output-of-project.dll` argument in the ProjectOptions. However, this requires the build
+of each project to succeed, producing the DLL file on disk which can be referred to.
+
+In some situations, e.g. in an IDE, you may wish to allow references to other F# projects prior to successful compilation to
+a DLL. To do this, fill in the ProjectReferences entry in ProjectOptions, which recursively specifies the project
+options for dependent projects. Each project reference still needs a corresponding `-r:path-to-output-of-project.dll`
+command line argument in ProjectOptions, along with an entry in ProjectReferences.
+The first element of each tuple in the ProjectReferences entry should be the DLL name, i.e. `path-to-output-of-project.dll`.
+This should be the same as the text used in the `-r` project reference.
+
+When a project reference is used, the analysis will make use of the results of incremental
+analysis of the referenced F# project from source files, without requiring the compilation of these files to DLLs.
+
+To efficiently analyze a set of F# projects which include cross-references, you should populate the ProjectReferences
+correctly and then analyze each project in turn.
+
+*)
+
+(**
+
+> **NOTE:** Project references are disabled if the assembly being referred to contains type provider components -
+ specifying the project reference will have no effect beyond forcing the analysis of the project, and the DLL will
+ still be required on disk.
+
+*)
+
+(**
+Summary
+-------
+
+As you have seen, the `ParseAndCheckProject` lets you access results of project-wide analysis
+such as symbol references. To learn more about working with symbols, see [Symbols](symbols.html).
+
+Using the FSharpChecker component in multi-project, incremental and interactive editing situations may involve
+knowledge of the [FSharpChecker operations queue](queue.html) and the [FSharpChecker caches](caches.html).
+
+*)
diff --git a/fcs/docsrc/content/queue.fsx b/docs/fcs/queue.fsx
similarity index 96%
rename from fcs/docsrc/content/queue.fsx
rename to docs/fcs/queue.fsx
index ccc7ccabbff..88a5af258ec 100644
--- a/fcs/docsrc/content/queue.fsx
+++ b/docs/fcs/queue.fsx
@@ -1,5 +1,5 @@
(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
(**
Compiler Services: Notes on the FSharpChecker operations queue
=================================================
@@ -36,7 +36,7 @@ These use cross-threaded access to the TAST data produced by other FSharpChecker
Some tools throw a lot of interactive work at the FSharpChecker operations queue.
If you are writing such a component, consider running your project against a debug build
of FSharp.Compiler.Service.dll to see the Trace.WriteInformation messages indicating the length of the
-operations queuea and the time to process requests.
+operations queue and the time to process requests.
For those writing interactive editors which use FCS, you
should be cautious about operations that request a check of the entire project.
diff --git a/fcs/docsrc/content/react.fsx b/docs/fcs/react.fsx
similarity index 97%
rename from fcs/docsrc/content/react.fsx
rename to docs/fcs/react.fsx
index ef5ccbf4952..07c9195e0b5 100644
--- a/fcs/docsrc/content/react.fsx
+++ b/docs/fcs/react.fsx
@@ -1,5 +1,5 @@
(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
(**
Compiler Services: Reacting to Changes
============================================
@@ -67,7 +67,7 @@ If your host happens to be Visual Studio, then this is one technique you can use
...
- // Unadvise file changes...
+ // Unadvised file changes...
Com.ThrowOnFailure0(vsFileWatch.UnadviseFileChange(cookie))
diff --git a/docs/fcs/symbols.fsx b/docs/fcs/symbols.fsx
new file mode 100644
index 00000000000..16607beb122
--- /dev/null
+++ b/docs/fcs/symbols.fsx
@@ -0,0 +1,224 @@
+(*** hide ***)
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+Compiler Services: Working with symbols
+============================================
+
+This tutorial demonstrates how to work with symbols provided by the F# compiler. See also [project wide analysis](project.html)
+for information on symbol references.
+
+> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published.
+
+As usual we start by referencing `FSharp.Compiler.Service.dll`, opening the relevant namespace and creating an instance
+of `FSharpChecker`:
+
+*)
+// Reference F# compiler API
+#r "FSharp.Compiler.Service.dll"
+
+open System
+open System.IO
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+
+// Create an interactive checker instance
+let checker = FSharpChecker.Create()
+
+(**
+
+We now perform type checking on the specified input:
+
+*)
+
+let parseAndTypeCheckSingleFile (file, input) =
+ // Get context representing a stand-alone (script) file
+ let projOptions, errors =
+ checker.GetProjectOptionsFromScript(file, input)
+ |> Async.RunSynchronously
+
+ let parseFileResults, checkFileResults =
+ checker.ParseAndCheckFileInProject(file, 0, input, projOptions)
+ |> Async.RunSynchronously
+
+ // Wait until type checking succeeds (or 100 attempts)
+ match checkFileResults with
+ | FSharpCheckFileAnswer.Succeeded(res) -> parseFileResults, res
+ | res -> failwithf "Parsing did not finish... (%A)" res
+
+let file = "/home/user/Test.fsx"
+
+(**
+## Getting resolved signature information about the file
+
+After type checking a file, you can access the inferred signature of a project up to and including the
+checking of the given file through the `PartialAssemblySignature` property of the `TypeCheckResults`.
+
+The full signature information is available for modules, types, attributes, members, values, functions,
+union cases, record types, units of measure and other F# language constructs.
+
+The typed expression trees are also available, see [typed tree tutorial](typedtree.html).
+
+*)
+
+let input2 =
+ """
+[]
+let foo(x, y) =
+ let msg = String.Concat("Hello"," ","world")
+ if true then
+ printfn "x = %d, y = %d" x y
+ printfn "%s" msg
+
+type C() =
+ member x.P = 1
+ """
+let parseFileResults, checkFileResults =
+ parseAndTypeCheckSingleFile(file, SourceText.ofString input2)
+
+(**
+Now get the partial assembly signature for the code:
+*)
+let partialAssemblySignature = checkFileResults.PartialAssemblySignature
+
+partialAssemblySignature.Entities.Count = 1 // one entity
+
+
+(**
+Now get the entity that corresponds to the module containing the code:
+*)
+let moduleEntity = partialAssemblySignature.Entities.[0]
+
+moduleEntity.DisplayName = "Test"
+
+(**
+Now get the entity that corresponds to the type definition in the code:
+*)
+let classEntity = moduleEntity.NestedEntities.[0]
+
+(**
+Now get the value that corresponds to the function defined in the code:
+*)
+let fnVal = moduleEntity.MembersFunctionsAndValues.[0]
+
+(**
+Now look around at the properties describing the function value. All of the following evaluate to `true`:
+*)
+fnVal.Attributes.Count = 1
+fnVal.CurriedParameterGroups.Count // 1
+fnVal.CurriedParameterGroups.[0].Count // 2
+fnVal.CurriedParameterGroups.[0].[0].Name // "x"
+fnVal.CurriedParameterGroups.[0].[1].Name // "y"
+fnVal.DeclarationLocation.StartLine // 3
+fnVal.DisplayName // "foo"
+fnVal.DeclaringEntity.Value.DisplayName // "Test"
+fnVal.DeclaringEntity.Value.DeclarationLocation.StartLine // 1
+fnVal.GenericParameters.Count // 0
+fnVal.InlineAnnotation // FSharpInlineAnnotation.OptionalInline
+fnVal.IsActivePattern // false
+fnVal.IsCompilerGenerated // false
+fnVal.IsDispatchSlot // false
+fnVal.IsExtensionMember // false
+fnVal.IsPropertyGetterMethod // false
+fnVal.IsImplicitConstructor // false
+fnVal.IsInstanceMember // false
+fnVal.IsMember // false
+fnVal.IsModuleValueOrMember // true
+fnVal.IsMutable // false
+fnVal.IsPropertySetterMethod // false
+fnVal.IsTypeFunction // false
+
+(**
+Now look at the type of the function if used as a first class value. (Aside: the `CurriedParameterGroups` property contains
+more information like the names of the arguments.)
+*)
+fnVal.FullType // int * int -> unit
+fnVal.FullType.IsFunctionType // int * int -> unit
+fnVal.FullType.GenericArguments.[0] // int * int
+fnVal.FullType.GenericArguments.[0].IsTupleType // int * int
+let argTy1 = fnVal.FullType.GenericArguments.[0].GenericArguments.[0]
+
+argTy1.TypeDefinition.DisplayName // int
+
+(**
+OK, so we got an object representation of the type `int * int -> unit`, and we have seen the first 'int'. We can find out more about the
+type 'int' as follows, determining that it is a named type, which is an F# type abbreviation, `type int = int32`:
+*)
+
+argTy1.HasTypeDefinition
+argTy1.TypeDefinition.IsFSharpAbbreviation // "int"
+
+(**
+We can now look at the right-hand-side of the type abbreviation, which is the type `int32`:
+*)
+
+let argTy1b = argTy1.TypeDefinition.AbbreviatedType
+argTy1b.TypeDefinition.Namespace // Some "Microsoft.FSharp.Core"
+argTy1b.TypeDefinition.CompiledName // "int32"
+
+(**
+Again we can now look through the type abbreviation `type int32 = System.Int32` to get the
+full information about the type:
+*)
+let argTy1c = argTy1b.TypeDefinition.AbbreviatedType
+argTy1c.TypeDefinition.Namespace // Some "SystemCore"
+argTy1c.TypeDefinition.CompiledName // "Int32"
+
+(**
+The type checking results for a file also contain information extracted from the project (or script) options
+used in the compilation, called the `ProjectContext`:
+*)
+let projectContext = checkFileResults.ProjectContext
+
+for assembly in projectContext.GetReferencedAssemblies() do
+ match assembly.FileName with
+ | None -> printfn "compilation referenced an assembly without a file"
+ | Some s -> printfn "compilation references assembly '%s'" s
+
+
+(**
+**Notes:**
+
+ - If incomplete code is present, some or all of the attributes may not be quite as expected.
+ - If some assembly references are missing (which is actually very, very common), then 'IsUnresolved' may
+ be true on values, members and/or entities related to external assemblies. You should be sure to make your
+ code robust against IsUnresolved exceptions.
+
+*)
+
+(**
+
+## Getting symbolic information about whole projects
+
+To check whole projects, create a checker, then call `parseAndCheckScript`. In this case, we just check
+the project for a single script. By specifying a different "projOptions" you can create
+a specification of a larger project.
+*)
+let parseAndCheckScript (file, input) =
+ let projOptions, errors =
+ checker.GetProjectOptionsFromScript(file, input)
+ |> Async.RunSynchronously
+
+ checker.ParseAndCheckProject(projOptions) |> Async.RunSynchronously
+
+(**
+Now do it for a particular input:
+*)
+
+let tmpFile = Path.ChangeExtension(System.IO.Path.GetTempFileName() , "fs")
+File.WriteAllText(tmpFile, input2)
+
+let projectResults = parseAndCheckScript(tmpFile, SourceText.ofString input2)
+
+
+(**
+Now look at the results:
+*)
+
+let assemblySig = projectResults.AssemblySignature
+
+assemblySig.Entities.Count = 1 // one entity
+assemblySig.Entities.[0].Namespace // one entity
+assemblySig.Entities.[0].DisplayName // "Tmp28D0"
+assemblySig.Entities.[0].MembersFunctionsAndValues.Count // 1
+assemblySig.Entities.[0].MembersFunctionsAndValues.[0].DisplayName // "foo"
+
diff --git a/docs/fcs/tokenizer.fsx b/docs/fcs/tokenizer.fsx
new file mode 100644
index 00000000000..b3dd97b6b6c
--- /dev/null
+++ b/docs/fcs/tokenizer.fsx
@@ -0,0 +1,132 @@
+(*** hide ***)
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+Compiler Services: Using the F# tokenizer
+=========================================
+
+This tutorial demonstrates how to call the F# language tokenizer. Given F#
+source code, the tokenizer generates a list of source code lines that contain
+information about tokens on each line. For each token, you can get the type
+of the token, exact location as well as color kind of the token (keyword,
+identifier, number, operator, etc.).
+
+> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published
+
+
+Creating the tokenizer
+---------------------
+
+To use the tokenizer, reference `FSharp.Compiler.Service.dll` and open the
+`SourceCodeServices` namespace:
+*)
+#r "FSharp.Compiler.Service.dll"
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+(**
+Now you can create an instance of `FSharpSourceTokenizer`. The class takes two
+arguments - the first is the list of defined symbols and the second is the
+file name of the source code. The defined symbols are required because the
+tokenizer handles `#if` directives. The file name is required only to specify
+locations of the source code (and it does not have to exist):
+*)
+let sourceTok = FSharpSourceTokenizer([], Some "C:\\test.fsx")
+(**
+Using the `sourceTok` object, we can now (repeatedly) tokenize lines of
+F# source code.
+
+Tokenizing F# code
+------------------
+
+The tokenizer operates on individual lines rather than on the entire source
+file. After getting a token, the tokenizer also returns new state (as `int64` value).
+This can be used to tokenize F# code more efficiently. When source code changes,
+you do not need to re-tokenize the entire file - only the parts that have changed.
+
+### Tokenizing single line
+
+To tokenize a single line, we create a `FSharpLineTokenizer` by calling `CreateLineTokenizer`
+on the `FSharpSourceTokenizer` object that we created earlier:
+*)
+let tokenizer = sourceTok.CreateLineTokenizer("let answer=42")
+(**
+Now, we can write a simple recursive function that calls `ScanToken` on the `tokenizer`
+until it returns `None` (indicating the end of line). When the function succeeds, it
+returns `FSharpTokenInfo` object with all the interesting details:
+*)
+/// Tokenize a single line of F# code
+let rec tokenizeLine (tokenizer:FSharpLineTokenizer) state =
+ match tokenizer.ScanToken(state) with
+ | Some tok, state ->
+ // Print token name
+ printf "%s " tok.TokenName
+ // Tokenize the rest, in the new state
+ tokenizeLine tokenizer state
+ | None, state -> state
+(**
+The function returns the new state, which is needed if you need to tokenize multiple lines
+and an earlier line ends with a multi-line comment. As an initial state, we can use `0L`:
+*)
+tokenizeLine tokenizer FSharpTokenizerLexState.Initial
+(**
+The result is a sequence of tokens with names LET, WHITESPACE, IDENT, EQUALS and INT32.
+There is a number of interesting properties on `FSharpTokenInfo` including:
+
+ - `CharClass` and `ColorClass` return information about the token category that
+ can be used for colorizing F# code.
+ - `LeftColumn` and `RightColumn` return the location of the token inside the line.
+ - `TokenName` is the name of the token (as defined in the F# lexer)
+
+Note that the tokenizer is stateful - if you want to tokenize single line multiple times,
+you need to call `CreateLineTokenizer` again.
+
+### Tokenizing sample code
+
+To run the tokenizer on a longer sample code or an entire file, you need to read the
+sample input as a collection of `string` values:
+*)
+let lines = """
+ // Hello world
+ let hello() =
+ printfn "Hello world!" """.Split('\r','\n')
+(**
+To tokenize multi-line input, we again need a recursive function that keeps the current
+state. The following function takes the lines as a list of strings (together with line number
+and the current state). We create a new tokenizer for each line and call `tokenizeLine`
+using the state from the *end* of the previous line:
+*)
+/// Print token names for multiple lines of code
+let rec tokenizeLines state count lines =
+ match lines with
+ | line::lines ->
+ // Create tokenizer & tokenize single line
+ printfn "\nLine %d" count
+ let tokenizer = sourceTok.CreateLineTokenizer(line)
+ let state = tokenizeLine tokenizer state
+ // Tokenize the rest using new state
+ tokenizeLines state (count+1) lines
+ | [] -> ()
+(**
+The function simply calls `tokenizeLine` (defined earlier) to print the names of all
+the tokens on each line. We can call it on the previous input with `0L` as the initial
+state and `1` as the number of the first line:
+*)
+lines
+|> List.ofSeq
+|> tokenizeLines FSharpTokenizerLexState.Initial 1
+(**
+Ignoring some unimportant details (like whitespace at the beginning of each line and
+the first line which is just whitespace), the code generates the following output:
+
+ [lang=text]
+ Line 1
+ LINE_COMMENT LINE_COMMENT (...) LINE_COMMENT
+ Line 2
+ LET WHITESPACE IDENT LPAREN RPAREN WHITESPACE EQUALS
+ Line 3
+ IDENT WHITESPACE STRING_TEXT (...) STRING_TEXT STRING
+
+It is worth noting that the tokenizer yields multiple `LINE_COMMENT` tokens and multiple
+`STRING_TEXT` tokens for each single comment or string (roughly, one for each word), so
+if you want to get the entire text of a comment/string, you need to concatenate the
+tokens.
+*)
\ No newline at end of file
diff --git a/fcs/docsrc/content/typedtree.fsx b/docs/fcs/typedtree.fsx
similarity index 98%
rename from fcs/docsrc/content/typedtree.fsx
rename to docs/fcs/typedtree.fsx
index 43bb55ba730..f5fbf1d7ab9 100644
--- a/fcs/docsrc/content/typedtree.fsx
+++ b/docs/fcs/typedtree.fsx
@@ -1,5 +1,5 @@
(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
(**
Compiler Services: Processing typed expression tree
=================================================
@@ -26,6 +26,7 @@ To use the interactive checker, reference `FSharp.Compiler.Service.dll` and open
open System
open System.IO
open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
(**
### Checking code
@@ -42,7 +43,7 @@ let parseAndCheckSingleFile (input) =
File.WriteAllText(file, input)
// Get context representing a stand-alone (script) file
let projOptions, _errors =
- checker.GetProjectOptionsFromScript(file, input)
+ checker.GetProjectOptionsFromScript(file, SourceText.ofString input)
|> Async.RunSynchronously
checker.ParseAndCheckProject(projOptions)
diff --git a/docs/fcs/untypedtree.fsx b/docs/fcs/untypedtree.fsx
new file mode 100644
index 00000000000..8ba9a0b4eba
--- /dev/null
+++ b/docs/fcs/untypedtree.fsx
@@ -0,0 +1,246 @@
+(*** hide ***)
+#I "../../artifacts/bin/FSharp.Compiler.Service/Debug/netstandard2.0"
+(**
+Compiler Services: Processing untyped syntax tree
+=================================================
+
+This tutorial demonstrates how to get the untyped abstract syntax tree (AST)
+for F# code and how to walk over the tree. This can be used for creating tools
+such as code formatter, basic refactoring or code navigation tools. The untyped
+syntax tree contains information about the code structure, but does not contain
+types and there are some ambiguities that are resolved only later by the type
+checker. You can also combine the untyped AST information with the API available
+from [editor services](editor.html).
+
+> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published
+
+
+Getting the untyped AST
+-----------------------
+
+To access the untyped AST, you need to create an instance of `FSharpChecker`.
+This type represents a context for type checking and parsing and corresponds either
+to a stand-alone F# script file (e.g. opened in Visual Studio) or to a loaded project
+file with multiple files. Once you have an instance of `FSharpChecker`, you can
+use it to perform "untyped parse" which is the first step of type-checking. The
+second phase is "typed parse" and is used by [editor services](editor.html).
+
+To use the interactive checker, reference `FSharp.Compiler.Service.dll` and open the
+`SourceCodeServices` namespace:
+*)
+#r "FSharp.Compiler.Service.dll"
+open System
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Text
+(**
+
+### Performing untyped parse
+
+The untyped parse operation is very fast (compared to type checking, which can
+take notable amount of time) and so we can perform it synchronously. First, we
+need to create `FSharpChecker` - the constructor takes an argument that
+can be used to notify the checker about file changes (which we ignore).
+
+*)
+// Create an interactive checker instance
+let checker = FSharpChecker.Create()
+(**
+
+To get the AST, we define a function that takes file name and the source code
+(the file is only used for location information and does not have to exist).
+We first need to get "interactive checker options" which represents the context.
+For simple tasks, you can use `GetProjectOptionsFromScriptRoot` which infers
+the context for a script file. Then we use the `ParseFile` method and
+return the `ParseTree` property:
+
+*)
+/// Get untyped tree for a specified input
+let getUntypedTree (file, input) =
+ // Get compiler options for the 'project' implied by a single script file
+ let projOptions, errors =
+ checker.GetProjectOptionsFromScript(file, input)
+ |> Async.RunSynchronously
+
+ let parsingOptions, _errors = checker.GetParsingOptionsFromProjectOptions(projOptions)
+
+ // Run the first phase (untyped parsing) of the compiler
+ let parseFileResults =
+ checker.ParseFile(file, input, parsingOptions)
+ |> Async.RunSynchronously
+
+ match parseFileResults.ParseTree with
+ | Some tree -> tree
+ | None -> failwith "Something went wrong during parsing!"
+
+(**
+
+Walking over the AST
+--------------------
+
+The abstract syntax tree is defined as a number of discriminated unions that represent
+different syntactical elements (such as expressions, patterns, declarations etc.). The best
+way to understand the AST is to look at the definitions in [`ast.fs` in the source
+code](https://github.com/fsharp/fsharp/blob/master/src/fsharp/ast.fs#L464).
+
+The relevant parts are in the following namespace:
+*)
+open FSharp.Compiler.SyntaxTree
+(**
+
+When processing the AST, you will typically write a number of mutually recursive functions
+that pattern match on the different syntactical elements. There is a number of elements
+that need to be supported - the top-level element is module or namespace declaration,
+containing declarations inside a module (let bindings, types etc.). A let declaration inside
+a module then contains expression, which can contain patterns.
+
+### Walking over patterns and expressions
+
+We start by looking at functions that walk over expressions and patterns - as we walk,
+we print information about the visited elements. For patterns, the input is of type
+`SynPat` and has a number of cases including `Wild` (for `_` pattern), `Named` (for
+` as name`) and `LongIdent` (for a `Foo.Bar` name). Note that the parsed pattern
+is occasionally more complex than what is in the source code (in particular, `Named` is
+used more often):
+*)
+/// Walk over a pattern - this is for example used in
+/// let = or in the 'match' expression
+let rec visitPattern = function
+ | SynPat.Wild(_) ->
+ printfn " .. underscore pattern"
+ | SynPat.Named(pat, name, _, _, _) ->
+ visitPattern pat
+ printfn " .. named as '%s'" name.idText
+ | SynPat.LongIdent(LongIdentWithDots(ident, _), _, _, _, _, _) ->
+ let names = String.concat "." [ for i in ident -> i.idText ]
+ printfn " .. identifier: %s" names
+ | pat -> printfn " .. other pattern: %A" pat
+(**
+The function is recursive (for nested patterns such as `(foo, _) as bar`), but it does not
+call any of the functions defined later (because patterns cannot contain other syntactical
+elements).
+
+The next function iterates over expressions - this is where most of the work would be and
+there are around 20 cases to cover (type `SynExpr.` and you'll get completion with other
+options). In the following, we only show how to handle `if .. then ..` and `let .. = ...`:
+*)
+/// Walk over an expression - if expression contains two or three
+/// sub-expressions (two if the 'else' branch is missing), let expression
+/// contains pattern and two sub-expressions
+let rec visitExpression e =
+ match e with
+ | SynExpr.IfThenElse(cond, trueBranch, falseBranchOpt, _, _, _, _) ->
+ // Visit all sub-expressions
+ printfn "Conditional:"
+ visitExpression cond
+ visitExpression trueBranch
+ falseBranchOpt |> Option.iter visitExpression
+
+ | SynExpr.LetOrUse(_, _, bindings, body, _) ->
+ // Visit bindings (there may be multiple
+ // for 'let .. = .. and .. = .. in ...'
+ printfn "LetOrUse with the following bindings:"
+ for binding in bindings do
+ let (Binding(access, kind, inlin, mutabl, attrs, xmlDoc,
+ data, pat, retInfo, init, m, sp)) = binding
+ visitPattern pat
+ visitExpression init
+ // Visit the body expression
+ printfn "And the following body:"
+ visitExpression body
+ | expr -> printfn " - not supported expression: %A" expr
+(**
+The `visitExpression` function will be called from a function that visits all top-level
+declarations inside a module. In this tutorial, we ignore types and members, but that would
+be another source of calls to `visitExpression`.
+
+### Walking over declarations
+
+As mentioned earlier, the AST of a file contains a number of module or namespace declarations
+(top-level node) that contain declarations inside a module (let bindings or types) or inside
+a namespace (just types). The following functions walks over declarations - we ignore types,
+nested modules and all other elements and look only at top-level `let` bindings (values and
+functions):
+*)
+/// Walk over a list of declarations in a module. This is anything
+/// that you can write as a top-level inside module (let bindings,
+/// nested modules, type declarations etc.)
+let visitDeclarations decls =
+ for declaration in decls do
+ match declaration with
+ | SynModuleDecl.Let(isRec, bindings, range) ->
+ // Let binding as a declaration is similar to let binding
+ // as an expression (in visitExpression), but has no body
+ for binding in bindings do
+ let (Binding(access, kind, inlin, mutabl, attrs, xmlDoc,
+ data, pat, retInfo, body, m, sp)) = binding
+ visitPattern pat
+ visitExpression body
+ | _ -> printfn " - not supported declaration: %A" declaration
+(**
+The `visitDeclarations` function will be called from a function that walks over a
+sequence of module or namespace declarations. This corresponds, for example, to a file
+with multiple `namespace Foo` declarations:
+*)
+/// Walk over all module or namespace declarations
+/// (basically 'module Foo =' or 'namespace Foo.Bar')
+/// Note that there is one implicitly, even if the file
+/// does not explicitly define it..
+let visitModulesAndNamespaces modulesOrNss =
+ for moduleOrNs in modulesOrNss do
+ let (SynModuleOrNamespace(lid, isRec, isMod, decls, xml, attrs, _, m)) = moduleOrNs
+ printfn "Namespace or module: %A" lid
+ visitDeclarations decls
+(**
+Now that we have functions that walk over the elements of the AST (starting from declaration,
+down to expressions and patterns), we can get AST of a sample input and run the above function.
+
+Putting things together
+-----------------------
+
+As already discussed, the `getUntypedTree` function uses `FSharpChecker` to run the first
+phase (parsing) on the AST and get back the tree. The function requires F# source code together
+with location of the file. The location does not have to exist (it is used only for location
+information) and it can be in both Unix and Windows formats:
+*)
+// Sample input for the compiler service
+let input =
+ """
+ let foo() =
+ let msg = "Hello world"
+ if true then
+ printfn "%s" msg
+ """
+
+// File name in Unix format
+let file = "/home/user/Test.fsx"
+
+// Get the AST of sample F# code
+let tree = getUntypedTree(file, SourceText.ofString input)
+(**
+When you run the code in F# interactive, you can enter `tree;;` in the interactive console and
+see pretty printed representation of the data structure - the tree contains a lot of information,
+so this is not particularly readable, but it gives you good idea about how the tree looks.
+
+The returned `tree` value is again a discriminated union that can be two different cases - one case
+is `ParsedInput.SigFile` which represents F# signature file (`*.fsi`) and the other one is
+`ParsedInput.ImplFile` representing regular source code (`*.fsx` or `*.fs`). The implementation
+file contains a sequence of modules or namespaces that we can pass to the function implemented
+in the previous step:
+*)
+// Extract implementation file details
+match tree with
+| ParsedInput.ImplFile(implFile) ->
+ // Extract declarations and walk over them
+ let (ParsedImplFileInput(fn, script, name, _, _, modules, _)) = implFile
+ visitModulesAndNamespaces modules
+| _ -> failwith "F# Interface file (*.fsi) not supported."
+(**
+Summary
+-------
+In this tutorial, we looked at basic of working with the untyped abstract syntax tree. This is a
+comprehensive topic, so it is not possible to explain everything in a single article. The
+[Fantomas project](https://github.com/dungpa/fantomas) is a good example of tool based on the untyped
+AST that can help you understand more. In practice, it is also useful to combine the information here
+with some information you can obtain from the [editor services](editor.html) discussed in the next
+tutorial.
+*)
diff --git a/fcs/docsrc/files/content/fcs.css b/docs/files/content/fcs.css
similarity index 100%
rename from fcs/docsrc/files/content/fcs.css
rename to docs/files/content/fcs.css
diff --git a/fcs/docsrc/files/content/style.ja.css b/docs/files/content/style.ja.css
similarity index 100%
rename from fcs/docsrc/files/content/style.ja.css
rename to docs/files/content/style.ja.css
diff --git a/fcs/docsrc/files/images/en.png b/docs/files/images/en.png
similarity index 100%
rename from fcs/docsrc/files/images/en.png
rename to docs/files/images/en.png
diff --git a/fcs/docsrc/files/images/ja.png b/docs/files/images/ja.png
similarity index 100%
rename from fcs/docsrc/files/images/ja.png
rename to docs/files/images/ja.png
diff --git a/fcs/docsrc/files/images/logo.png b/docs/files/images/logo.png
similarity index 100%
rename from fcs/docsrc/files/images/logo.png
rename to docs/files/images/logo.png
diff --git a/docs/fsharp-core-notes.md b/docs/fsharp-core-notes.md
new file mode 100644
index 00000000000..e98354bd181
--- /dev/null
+++ b/docs/fsharp-core-notes.md
@@ -0,0 +1,158 @@
+---
+layout: default
+title: Notes on FSharp.Core
+subtitle: This technical guide discusses the FSharp.Core library.
+---
+
+# Notes and Guidance on FSharp.Core
+{:.no_toc}
+
+This technical guide discusses the FSharp.Core library. Please help improve this guide by editing it and submitting a pull-request.
+
+Much of the guidance below applies to any .NET library respecting binary compatibility.
+
+### FSharp.Core is binary compatible
+
+FSharp.Core is binary compatible across versions of the F# language. For example, FSharp.Core `5.0.0.0` (F# 5.0) is binary compatible with
+`4.7.0.0` (F# 4.7), `4.6.0.0` (F# 3.6), `4.4.0.0` (F# 4.0) , `4.4.1.0` (F# 4.1), , `4.4.3.0` (F# 4.1+) and so on.
+
+Likewise, FSharp.Core is binary compatible from "netstandard" profiles to actual runtime implementations.
+For example, FSharp.Core for `netstandard2.0` is binary compatible with the runtime implementation assembly `4.7.0.0` and so on.
+
+Binary compatibility means that a component built for X can instead bind to Y at runtime.
+It doesn't mean that Y behaves 100% the same as X (some bug fixes may have been made, and Y may have more functionality than X).
+
+### Application v. Library v. Script
+{:.no_toc}
+
+Each project is either an *application* or a *library*.
+
+* Examples of application are `.exe` project or a `.dll` project that is a test project, addin, website, or an app.
+
+* Libraries are just ordinary `.dll` components (excluding those above which are applications).
+
+* Scripts are not projects, just `.fsx` files, possibly referring to other files using `#load` and Libraries using `#r`
+
+### Do *not* bundle FSharp.Core with a library
+
+Do _not_ include a copy of FSharp.Core with your library or package. If you do, you will create havoc for users of
+your library.
+
+The decision about which `FSharp.Core` a library binds to is up to the application hosting of the library.
+The library and/or library package can place constraints on this, but it doesn't decide it.
+
+Especially, do _not_ include FSharp.Core in the ``lib`` folder of a NuGet package.
+
+### Always deploy FSharp.Core as part of a compiled application
+
+For applications, FSharp.Core is normally part of the application itself (so-called "xcopy deploy" of FSharp.Core).
+
+For modern templates, this is the default. For older templates, you may need to use ``true`` in your project file. In Visual Studio this is equivalent to setting the `CopyLocal` property to `true` properties for the `FSharp.Core` reference.
+
+FSharp.Core.dll will normally appear in the `bin` output folder for your application. For example:
+
+```
+ Directory of ...\ConsoleApplication3\bin\Debug\netcoreapp3.1
+
+ 18/04/2020 13:20 5,632 ConsoleApplication3.exe
+ 14/10/2020 12:12 1,400,472 FSharp.Core.dll
+```
+
+### Always reference FSharp.Core via the NuGet package.
+
+FSharp.Core is now always referenced via [the NuGet package](http://www.nuget.org/packages/FSharp.Core).
+
+### Make your FSharp.Core references explicit
+
+Templates for F# libraries use an **implicit** FSharp.Core package reference where the .NET SDK chooses one. Consider
+using an **explicit** reference, especially when creating libraries.
+
+To select a particular FSharp.Core use `Update`:
+
+
+
+In C# projects use:
+
+
+
+If you make your FSharp.Core dependency explicit, you will have to explicitly upgrade your FSharp.Core reference in order to use
+new F# language or library features should those features depend on a particular minimal FSharp.Core version.
+
+### Libraries should target lower versions of FSharp.Core
+
+F# ecosystem libraries should generally target the *earliest, most portable* profile of FSharp.Core feasible, within reason.
+
+If your library is part of an ecosystem, it can be helpful to target the _earliest, most widespread language version_
+and the _earliest_ and _most supported_ profiles of the .NET Framework feasible.
+
+The version you choose should be based on the minimum F# language version you want to support. The minimum FSharp.Core version for each language version is listed below:
+
+|Minimum F# language version|Minimum FSharp.Core version|
+|------------------------------|------------------------------|
+|F# 4.1|4.3.4|
+|F# 4.5|4.5.2|
+|F# 4.6|4.6.2|
+|F# 4.7|4.7.2|
+|F# 5.0|5.0.0|
+
+A good choice for libraries is to target `netstandard2.0` and FSharp.Core 4.7.2.
+
+
+
+For "libraries" that are effectively part of an application, you can just target
+the latest language version and the framework you're using in your application.
+
+### Applications should target higher versions of FSharp.Core
+
+F# applications should generally use the *highest* language version and the most *platform-specific* version of FSharp.Core.
+
+Generally, when writing an application, you want to use the highest version of FSharp.Core available for the platform
+you are targeting.
+
+If your application in being developed by people using multiple versions of F# tooling (common
+in open source working) you may need to target a lower version of the language and a correspondingly earlier version
+of FSharp.Core.
+
+### The FSharp.Core used by a script depends on the tool processing the script
+
+If you run a script with `dotnet fsi` then the tool will decide which FSharp.Core is used, and which implementation assemblies are used.
+
+When editing a script, the editing tools will decide which FSharp.Core is referenced.
+
+### FSharp.Core and static linking
+{:.no_toc}
+
+The ILMerge tool and the F# compiler both allow static linking of assemblies including static linking of FSharp.Core.
+This can be useful to build a single standalone file for a tool.
+
+However, these options must be used with caution.
+
+* Only use this option for applications, not libraries. If it's not a .EXE (or a library that is effectively an application) then don't even try using this option.
+
+Searching on stackoverflow reveals further guidance on this topic.
+
+### FSharp.Core in components using FSharp.Compiler.Service
+{:.no_toc}
+
+If your application of component uses FSharp.Compiler.Service,
+see [this guide](http://fsharp.github.io/FSharp.Compiler.Service/corelib.html). This scenario is more complicated
+because FSharp.Core is used both to run your script or application, and is referenced during compilation.
+
+Likewise, if you have a script or library using FSharp.Formatting, then beware that is using FSharp.Compiler.Service.
+For scripts that is normally OK because they are processed using F# Interactive, and the default FSharp.Core is used.
+If you have an application using FSharp.Formatting as a component then see the guide linked above.
+
+### FSharp.Core and new language features
+{:.no_toc}
+
+New versions of FSharp.Core must generally be consumable by previous generations of F# compiler tooling. There is nothing stopping
+older tooling from adding a reference to the new nuget package.
+
+This sometimes limits the new language features that can be used in FSharp.Core or requires careful coding in the serializing/deserializing of
+F# metadata stored in the FSharp.Core.dll binary as resources.
+
+## Reference: FSharp.Core version and NuGet package numbers
+
+See [the F# version information RFC](https://github.com/fsharp/fslang-design/blob/master/tooling/FST-1004-versioning-plan.md).
+
+
diff --git a/fcs/docsrc/tools/generate.fsx b/docs/tools/generate.fsx
similarity index 88%
rename from fcs/docsrc/tools/generate.fsx
rename to docs/tools/generate.fsx
index 617a154efb3..09fa803a2f5 100644
--- a/fcs/docsrc/tools/generate.fsx
+++ b/docs/tools/generate.fsx
@@ -3,6 +3,9 @@
// (the generated documentation is stored in the 'docs' directory)
// --------------------------------------------------------------------------------------
+#r "paket: groupref generate //"
+#load "./.fake/generate.fsx/intellisense.fsx"
+
// Binaries that have XML documentation (in a corresponding generated XML file)
let referenceBinaries = [ "FSharp.Compiler.Service.dll" ]
// Web site location for the generated documentation
@@ -20,14 +23,12 @@ let info =
// For typical project, no changes are needed below
// --------------------------------------------------------------------------------------
-#load "../../packages/FSharp.Formatting/FSharp.Formatting.fsx"
-#I "../../packages/FAKE/tools"
-#r "../../packages/FAKE/tools/FakeLib.dll"
open Fake
open System.IO
-open Fake.FileHelper
+open Fake.IO.FileSystemOperators
+open Fake.IO
+open Fake.Core
open FSharp.Literate
-open FSharp.MetadataFormat
let root = "."
@@ -48,19 +49,20 @@ let layoutRoots =
// Copy static files and CSS + JS from F# Formatting
let copyFiles () =
- CopyRecursive files output true |> Log "Copying file: "
- ensureDirectory (output @@ "content")
- CopyRecursive (formatting @@ "styles") (output @@ "content") true
- |> Log "Copying styles and scripts: "
+ Shell.copyRecursive files output true
+ |> Trace.tracefn "Copying file: %A"
+ Directory.ensure (output @@ "content")
+ Shell.copyRecursive (formatting @@ "styles") (output @@ "content") true
+ |> Trace.tracefn "Copying styles and scripts: %A"
let clr = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()
let fsfmt = __SOURCE_DIRECTORY__ @@ ".." @@ ".." @@ @"packages" @@ "FSharp.Formatting" @@ "lib" @@ "net40"
// Build API reference from XML comments
let buildReference () =
- CleanDir (output @@ "reference")
+ Shell.cleanDir (output @@ "reference")
for lib in referenceBinaries do
- MetadataFormat.Generate
+ RazorMetadataFormat.Generate
( bin @@ lib, output @@ "reference", layoutRoots,
parameters = ("root", root)::info,
sourceRepo = "https://github.com/fsharp/FSharp.Compiler.Service/tree/master/src",
@@ -87,7 +89,7 @@ let buildReference () =
let buildDocumentation () =
for dir in [content] do
let sub = if dir.Length > content.Length then dir.Substring(content.Length + 1) else "."
- Literate.ProcessDirectory
+ RazorLiterate.ProcessDirectory
( dir, docTemplate, output @@ sub, replacements = ("root", root)::info,
layoutRoots = layoutRoots, generateAnchors = true, processRecursive=false )
diff --git a/fcs/docsrc/tools/generate.ja.fsx b/docs/tools/generate.ja.fsx
similarity index 100%
rename from fcs/docsrc/tools/generate.ja.fsx
rename to docs/tools/generate.ja.fsx
diff --git a/fcs/docsrc/tools/templates/ja/template.cshtml b/docs/tools/templates/ja/template.cshtml
similarity index 100%
rename from fcs/docsrc/tools/templates/ja/template.cshtml
rename to docs/tools/templates/ja/template.cshtml
diff --git a/fcs/docsrc/tools/templates/template.cshtml b/docs/tools/templates/template.cshtml
similarity index 100%
rename from fcs/docsrc/tools/templates/template.cshtml
rename to docs/tools/templates/template.cshtml
diff --git a/eng/Build.ps1 b/eng/Build.ps1
index adbe1a2eb4a..429ad1d580c 100644
--- a/eng/Build.ps1
+++ b/eng/Build.ps1
@@ -37,6 +37,7 @@ param (
[string]$bootstrapConfiguration = "Proto",
[string]$bootstrapTfm = "net472",
[switch][Alias('bl')]$binaryLog,
+ [switch][Alias('nobl')]$excludeCIBinaryLog,
[switch]$ci,
[switch]$official,
[switch]$procdump,
@@ -50,6 +51,7 @@ param (
[switch]$testCompiler,
[switch]$testFSharpCore,
[switch]$testFSharpQA,
+ [switch]$testScripting,
[switch]$testVs,
[switch]$testAll,
[string]$officialSkipTests = "false",
@@ -59,6 +61,8 @@ param (
Set-StrictMode -version 2.0
$ErrorActionPreference = "Stop"
+$BuildCategory = ""
+$BuildMessage = ""
function Print-Usage() {
Write-Host "Common settings:"
@@ -66,6 +70,7 @@ function Print-Usage() {
Write-Host " -verbosity Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]"
Write-Host " -deployExtensions Deploy built vsixes"
Write-Host " -binaryLog Create MSBuild binary log (short: -bl)"
+ Write-Host " -excludeCIBinaryLog When running on CI, allow no binary log (short: -nobl)"
Write-Host ""
Write-Host "Actions:"
Write-Host " -restore Restore packages (short: -r)"
@@ -86,6 +91,7 @@ function Print-Usage() {
Write-Host " -testCoreClr Run tests against CoreCLR"
Write-Host " -testFSharpCore Run FSharpCore unit tests"
Write-Host " -testFSharpQA Run F# Cambridge tests"
+ Write-Host " -testScripting Run Scripting tests"
Write-Host " -testVs Run F# editor unit tests"
Write-Host " -officialSkipTests Set to 'true' to skip running tests"
Write-Host ""
@@ -148,11 +154,11 @@ function Process-Arguments() {
function Update-Arguments() {
if ($script:noVisualStudio) {
- $script:bootstrapTfm = "netcoreapp2.1"
+ $script:bootstrapTfm = "netcoreapp3.1"
$script:msbuildEngine = "dotnet"
}
- if ($bootstrapTfm -eq "netcoreapp2.1") {
+ if ($bootstrapTfm -eq "netcoreapp3.1") {
if (-Not (Test-Path "$ArtifactsDir\Bootstrap\fsc\fsc.runtimeconfig.json")) {
$script:bootstrap = $True
}
@@ -169,12 +175,17 @@ function BuildSolution() {
Write-Host "$($solution):"
+ if ($binaryLog -and $excludeCIBinaryLog) {
+ Write-Host "Invalid argument -binarylog(-bl) and -excludeCIBinaryLog(-nobl) cannot be set at the same time"
+ ExitWithExitCode 1
+ }
$bl = if ($binaryLog) { "/bl:" + (Join-Path $LogDir "Build.binlog") } else { "" }
+
$projects = Join-Path $RepoRoot $solution
$officialBuildId = if ($official) { $env:BUILD_BUILDNUMBER } else { "" }
$toolsetBuildProj = InitializeToolset
$quietRestore = !$ci
- $testTargetFrameworks = if ($testCoreClr) { "netcoreapp2.1" } else { "" }
+ $testTargetFrameworks = if ($testCoreClr) { "netcoreapp3.1" } else { "" }
# Do not set the property to true explicitly, since that would override value projects might set.
$suppressExtensionDeployment = if (!$deployExtensions) { "/p:DeployExtension=false" } else { "" }
@@ -216,7 +227,7 @@ function UpdatePath() {
TestAndAddToPath $subdir
# add windows SDK dir for ildasm.exe
- foreach ($child in Get-ChildItem "${env:ProgramFiles(x86)}\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.?.? Tools") {
+ foreach ($child in Get-ChildItem "${env:ProgramFiles(x86)}\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.* Tools") {
$subdir = $child
}
TestAndAddToPath $subdir
@@ -252,11 +263,15 @@ function TestUsingNUnit([string] $testProject, [string] $targetFramework) {
$args += " --no-build"
}
+ if ($env:RunningAsPullRequest -ne "true") {
+ $args += " --filter TestCategory!=PullRequest"
+ }
+
Exec-Console $dotnetExe $args
}
function BuildCompiler() {
- if ($bootstrapTfm -eq "netcoreapp2.1") {
+ if ($bootstrapTfm -eq "netcoreapp3.1") {
$dotnetPath = InitializeDotNetCli
$dotnetExe = Join-Path $dotnetPath "dotnet.exe"
$fscProject = "$RepoRoot\src\fsharp\fsc\fsc.fsproj"
@@ -265,10 +280,18 @@ function BuildCompiler() {
$argNoRestore = if ($norestore) { " --no-restore" } else { "" }
$argNoIncremental = if ($rebuild) { " --no-incremental" } else { "" }
- $args = "build $fscProject -c $configuration -v $verbosity -f netcoreapp2.1" + $argNoRestore + $argNoIncremental
+ if ($binaryLog) {
+ $logFilePath = Join-Path $LogDir "fscBootstrapLog.binlog"
+ $args += " /bl:$logFilePath"
+ }
+ $args = "build $fscProject -c $configuration -v $verbosity -f netcoreapp3.1" + $argNoRestore + $argNoIncremental
Exec-Console $dotnetExe $args
- $args = "build $fsiProject -c $configuration -v $verbosity -f netcoreapp2.1" + $argNoRestore + $argNoIncremental
+ if ($binaryLog) {
+ $logFilePath = Join-Path $LogDir "fsiBootstrapLog.binlog"
+ $args += " /bl:$logFilePath"
+ }
+ $args = "build $fsiProject -c $configuration -v $verbosity -f netcoreapp3.1" + $argNoRestore + $argNoIncremental
Exec-Console $dotnetExe $args
}
}
@@ -278,6 +301,100 @@ function Prepare-TempDir() {
Copy-Item (Join-Path $RepoRoot "tests\Resources\Directory.Build.targets") $TempDir
}
+function DownloadDotnetFrameworkSdk() {
+ $dlTempPath = [System.IO.Path]::GetTempPath()
+ $dlRandomFile = [System.IO.Path]::GetRandomFileName()
+ $net48Dir = Join-Path $dlTempPath $dlRandomFile
+ Create-Directory $net48Dir
+
+ $net48Exe = Join-Path $net48Dir "ndp48-devpack-enu.exe"
+ $dlLogFilePath = Join-Path $LogDir "dotnet48.install.log"
+ Invoke-WebRequest "https://go.microsoft.com/fwlink/?linkid=2088517" -OutFile $net48Exe
+
+ Write-Host "Exec-Console $net48Exe /install /quiet /norestart /log $dlLogFilePath"
+ Exec-Console $net48Exe "/install /quiet /norestart /log $dlLogFilePath"
+}
+
+function Test-IsAdmin {
+ ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
+}
+
+function TryDownloadDotnetFrameworkSdk() {
+ # If we are not running as admin user, don't bother grabbing ndp sdk -- since we don't need sn.exe
+ $isAdmin = Test-IsAdmin
+ Write-Host "TryDownloadDotnetFrameworkSdk -- Test-IsAdmin = '$isAdmin'"
+ if ($isAdmin -eq $true)
+ {
+ # Get program files(x86) location
+ if (${env:ProgramFiles(x86)} -eq $null) {
+ $programFiles = $env:ProgramFiles
+ }
+ else {
+ $programFiles = ${env:ProgramFiles(x86)}
+ }
+
+ # Get windowsSDK location for x86
+ $windowsSDK_ExecutablePath_x86 = $env:WindowsSDK_ExecutablePath_x86
+ $newWindowsSDK_ExecutablePath_x86 = Join-Path "$programFiles" "Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools"
+
+ if ($windowsSDK_ExecutablePath_x86 -eq $null) {
+ $snPathX86 = Join-Path $newWindowsSDK_ExecutablePath_x86 "sn.exe"
+ }
+ else {
+ $snPathX86 = Join-Path $windowsSDK_ExecutablePath_x86 "sn.exe"
+ $snPathX86Exists = Test-Path $snPathX86 -PathType Leaf
+ if ($snPathX86Exists -ne $true) {
+ $windowsSDK_ExecutablePath_x86 = null
+ $snPathX86 = Join-Path $newWindowsSDK_ExecutablePath_x86 "sn.exe"
+ }
+ }
+
+ $windowsSDK_ExecutablePath_x64 = $env:WindowsSDK_ExecutablePath_x64
+ $newWindowsSDK_ExecutablePath_x64 = Join-Path "$programFiles" "Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64"
+
+ if ($windowsSDK_ExecutablePath_x64 -eq $null) {
+ $snPathX64 = Join-Path $newWindowsSDK_ExecutablePath_x64 "sn.exe"
+ }
+ else {
+ $snPathX64 = Join-Path $windowsSDK_ExecutablePath_x64 "sn.exe"
+ $snPathX64Exists = Test-Path $snPathX64 -PathType Leaf
+ if ($snPathX64Exists -ne $true) {
+ $windowsSDK_ExecutablePath_x86 = null
+ $snPathX64 = Join-Path $newWindowsSDK_ExecutablePath_x64 "sn.exe"
+ }
+ }
+
+ $snPathX86Exists = Test-Path $snPathX86 -PathType Leaf
+ Write-Host "pre-dl snPathX86Exists : $snPathX86Exists - '$snPathX86'"
+ if ($snPathX86Exists -ne $true) {
+ DownloadDotnetFrameworkSdk
+ }
+
+ $snPathX86Exists = Test-Path $snPathX86 -PathType Leaf
+ if ($snPathX86Exists -eq $true) {
+ if ($windowsSDK_ExecutablePath_x86 -ne $newWindowsSDK_ExecutablePath_x86) {
+ $windowsSDK_ExecutablePath_x86 = $newWindowsSDK_ExecutablePath_x86
+ # x86 environment variable
+ Write-Host "set WindowsSDK_ExecutablePath_x86=$WindowsSDK_ExecutablePath_x86"
+ [System.Environment]::SetEnvironmentVariable("WindowsSDK_ExecutablePath_x86","$newWindowsSDK_ExecutablePath_x86",[System.EnvironmentVariableTarget]::Machine)
+ $env:WindowsSDK_ExecutablePath_x86 = $newWindowsSDK_ExecutablePath_x86
+ }
+ }
+
+ # Also update environment variable for x64
+ $snPathX64Exists = Test-Path $snPathX64 -PathType Leaf
+ if ($snPathX64Exists -eq $true) {
+ if ($windowsSDK_ExecutablePath_x64 -ne $newWindowsSDK_ExecutablePath_x64) {
+ $windowsSDK_ExecutablePath_x64 = $newWindowsSDK_ExecutablePath_x64
+ # x64 environment variable
+ Write-Host "set WindowsSDK_ExecutablePath_x64=$WindowsSDK_ExecutablePath_x64"
+ [System.Environment]::SetEnvironmentVariable("WindowsSDK_ExecutablePath_x64","$newWindowsSDK_ExecutablePath_x64",[System.EnvironmentVariableTarget]::Machine)
+ $env:WindowsSDK_ExecutablePath_x64 = $newWindowsSDK_ExecutablePath_x64
+ }
+ }
+ }
+}
+
function EnablePreviewSdks() {
if (Test-Path variable:global:_MSBuildExe) {
return
@@ -298,6 +415,9 @@ function EnablePreviewSdks() {
}
try {
+ $script:BuildCategory = "Build"
+ $script:BuildMessage = "Failure preparing build"
+
Process-Arguments
. (Join-Path $PSScriptRoot "build-utils.ps1")
@@ -306,20 +426,23 @@ try {
Push-Location $RepoRoot
+ Get-ChildItem ENV: | Sort-Object Name
+ Write-Host ""
+
if ($ci) {
Prepare-TempDir
EnablePreviewSdks
-
- # enable us to build netcoreapp2.1 binaries
- $global:_DotNetInstallDir = Join-Path $RepoRoot ".dotnet"
- InstallDotNetSdk $global:_DotNetInstallDir $GlobalJson.tools.dotnet
- InstallDotNetSdk $global:_DotNetInstallDir "2.1.503"
}
+ $buildTool = InitializeBuildTool
+ $toolsetBuildProj = InitializeToolset
+ TryDownloadDotnetFrameworkSdk
if ($bootstrap) {
+ $script:BuildMessage = "Failure building bootstrap compiler"
$bootstrapDir = Make-BootstrapBuild
}
+ $script:BuildMessage = "Failure building product"
if ($restore -or $build -or $rebuild -or $pack -or $sign -or $publish) {
if ($noVisualStudio) {
BuildCompiler
@@ -332,20 +455,24 @@ try {
VerifyAssemblyVersionsAndSymbols
}
+ $script:BuildCategory = "Test"
+ $script:BuildMessage = "Failure running tests"
$desktopTargetFramework = "net472"
- $coreclrTargetFramework = "netcoreapp2.1"
+ $coreclrTargetFramework = "netcoreapp3.1"
if ($testDesktop -and -not $noVisualStudio) {
+ TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $desktopTargetFramework
TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.UnitTests\FSharp.Compiler.UnitTests.fsproj" -targetFramework $desktopTargetFramework
- TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.LanguageServer.UnitTests\FSharp.Compiler.LanguageServer.UnitTests.fsproj" -targetFramework $desktopTargetFramework
+ TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.Private.Scripting.UnitTests\FSharp.Compiler.Private.Scripting.UnitTests.fsproj" -targetFramework $desktopTargetFramework
TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Build.UnitTests\FSharp.Build.UnitTests.fsproj" -targetFramework $desktopTargetFramework
TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Core.UnitTests\FSharp.Core.UnitTests.fsproj" -targetFramework $desktopTargetFramework
TestUsingNUnit -testProject "$RepoRoot\tests\fsharp\FSharpSuite.Tests.fsproj" -targetFramework $desktopTargetFramework
}
if ($testCoreClr) {
+ TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $coreclrTargetFramework
TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.UnitTests\FSharp.Compiler.UnitTests.fsproj" -targetFramework $coreclrTargetFramework
- TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.LanguageServer.UnitTests\FSharp.Compiler.LanguageServer.UnitTests.fsproj" -targetFramework $coreclrTargetFramework
+ TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.Private.Scripting.UnitTests\FSharp.Compiler.Private.Scripting.UnitTests.fsproj" -targetFramework $coreclrTargetFramework
TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Build.UnitTests\FSharp.Build.UnitTests.fsproj" -targetFramework $coreclrTargetFramework
TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Core.UnitTests\FSharp.Core.UnitTests.fsproj" -targetFramework $coreclrTargetFramework
TestUsingNUnit -testProject "$RepoRoot\tests\fsharp\FSharpSuite.Tests.fsproj" -targetFramework $coreclrTargetFramework
@@ -353,18 +480,21 @@ try {
if ($testFSharpQA -and -not $noVisualStudio) {
Push-Location "$RepoRoot\tests\fsharpqa\source"
+ $nugetPackages = Get-PackagesDir
$resultsRoot = "$ArtifactsDir\TestResults\$configuration"
$resultsLog = "test-net40-fsharpqa-results.log"
$errorLog = "test-net40-fsharpqa-errors.log"
$failLog = "test-net40-fsharpqa-errors"
- $perlExe = "$env:USERPROFILE\.nuget\packages\StrawberryPerl64\5.22.2.1\Tools\perl\bin\perl.exe"
+ $perlPackageRoot = "$nugetPackages\StrawberryPerl\5.28.0.1";
+ $perlExe = "$perlPackageRoot\bin\perl.exe"
Create-Directory $resultsRoot
UpdatePath
$env:HOSTED_COMPILER = 1
- $env:CSC_PIPE = "$env:USERPROFILE\.nuget\packages\Microsoft.Net.Compilers\2.7.0\tools\csc.exe"
+ $env:CSC_PIPE = "$nugetPackages\Microsoft.Net.Compilers\2.7.0\tools\csc.exe"
$env:FSCOREDLLPATH = "$ArtifactsDir\bin\fsc\$configuration\net472\FSharp.Core.dll"
$env:LINK_EXE = "$RepoRoot\tests\fsharpqa\testenv\bin\link\link.exe"
$env:OSARCH = $env:PROCESSOR_ARCHITECTURE
+ $env:PERL5LIB = "$perlPackageRoot\vendor\lib"
Exec-Console $perlExe """$RepoRoot\tests\fsharpqa\testenv\bin\runall.pl"" -resultsroot ""$resultsRoot"" -results $resultsLog -log $errorLog -fail $failLog -cleanup:no -procs:$env:NUMBER_OF_PROCESSORS"
Pop-Location
}
@@ -378,8 +508,10 @@ try {
if ($testCompiler) {
if (-not $noVisualStudio) {
+ TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $desktopTargetFramework
TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.UnitTests\FSharp.Compiler.UnitTests.fsproj" -targetFramework $desktopTargetFramework
}
+ TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.ComponentTests\FSharp.Compiler.ComponentTests.fsproj" -targetFramework $coreclrTargetFramework
TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.UnitTests\FSharp.Compiler.UnitTests.fsproj" -targetFramework $coreclrTargetFramework
}
@@ -390,6 +522,13 @@ try {
TestUsingNUnit -testProject "$RepoRoot\tests\fsharp\FSharpSuite.Tests.fsproj" -targetFramework $coreclrTargetFramework
}
+ if ($testScripting) {
+ if (-not $noVisualStudio) {
+ TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.Private.Scripting.UnitTests\FSharp.Compiler.Private.Scripting.UnitTests.fsproj" -targetFramework $desktopTargetFramework
+ }
+ TestUsingNUnit -testProject "$RepoRoot\tests\FSharp.Compiler.Private.Scripting.UnitTests\FSharp.Compiler.Private.Scripting.UnitTests.fsproj" -targetFramework $coreclrTargetFramework
+ }
+
if ($testVs -and -not $noVisualStudio) {
TestUsingNUnit -testProject "$RepoRoot\vsintegration\tests\GetTypesVS.UnitTests\GetTypesVS.UnitTests.fsproj" -targetFramework $desktopTargetFramework
TestUsingNUnit -testProject "$RepoRoot\vsintegration\tests\UnitTests\VisualFSharp.UnitTests.fsproj" -targetFramework $desktopTargetFramework
@@ -401,6 +540,7 @@ catch {
Write-Host $_
Write-Host $_.Exception
Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category $script:BuildCategory -Message $script:BuildMessage
ExitWithExitCode 1
}
finally {
diff --git a/eng/DumpPackageRoot/DumpPackageRoot.csproj b/eng/DumpPackageRoot/DumpPackageRoot.csproj
new file mode 100644
index 00000000000..c3b2cedf8f6
--- /dev/null
+++ b/eng/DumpPackageRoot/DumpPackageRoot.csproj
@@ -0,0 +1,22 @@
+
+
+
+
+
+ netcoreapp3.1
+
+
+
+
+
+
+
+
+ $(ArtifactsDir)NugetPackageRootContents
+ $(PackageRootArtifactDirectory)/package_contents.txt
+
+
+
+
+
diff --git a/eng/MockBuild.ps1 b/eng/MockBuild.ps1
new file mode 100644
index 00000000000..e8000edb45f
--- /dev/null
+++ b/eng/MockBuild.ps1
@@ -0,0 +1,15 @@
+Set-StrictMode -version 2.0
+$ErrorActionPreference = "Stop"
+
+try {
+ $fakeBuildId = (Get-Date -Format "yyyyMMdd") + ".0"
+ $visualStudioDropName = "Products/mock/dotnet-fsharp/branch/$fakeBuildId"
+ & "$PSScriptRoot\Build.ps1" -build -restore -ci -bootstrap -binaryLog -pack -configuration Release /p:OfficialBuildId=$fakeBuildId /p:VisualStudioDropName=$visualStudioDropName
+}
+catch {
+ Write-Host $_
+ Write-Host $_.Exception
+ Write-Host $_.ScriptStackTrace
+ Write-Host "##[error](NETCORE_ENGINEERING_TELEMETRY=Build) Error doing mock official build."
+ exit 1
+}
diff --git a/eng/Publishing.props b/eng/Publishing.props
new file mode 100644
index 00000000000..18483e92a08
--- /dev/null
+++ b/eng/Publishing.props
@@ -0,0 +1,5 @@
+
+
+ 3
+
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 92b380533f7..4c478cc4500 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -3,9 +3,9 @@
-
+
https://github.com/dotnet/arcade
- def377f94747dac91482aad67b33a1c011ffc770
+ 4c8515c18ebe0071c32fed467ee3890fbd488898
diff --git a/eng/Versions.props b/eng/Versions.props
index 948f10cf498..8eab85eeae5 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -4,82 +4,91 @@
false
true
-
-
-
-
+ true
+ true
+ true
+ true
beta
- 4.7
- $(FSLanguageVersion)
- $(FSCoreMajorVersion).1
- $(FSCoreMajorVersion).0
- $(FSCoreVersionPrefix).0
+
+ 5
+ 0
+ 2
+ 0
+
+ $(FSMajorVersion).$(FSMinorVersion)
+ $(FSMajorVersion)-$(FSMinorVersion)
+
+ $(FSMajorVersion).$(FSMinorVersion)
+ $(FSMajorVersion).$(FSMinorVersion).$(FSBuildVersion)
+ $(FSMajorVersion)-$(FSMinorVersion)-$(FSBuildVersion)
+ $(FSMajorVersion).$(FSMinorVersion).$(FSBuildVersion)
+ $(FSMajorVersion).$(FSMinorVersion).0.0
+
+ 39
+ 0
+ 3
+ $(FSRevisionVersion)
+ $(FCSMajorVersion).$(FCSMinorVersion).$(FCSBuildVersion)
+ $(FCSMajorVersion)$(FCSMinorVersion)$(FCSBuildVersion)
- 4.7.0
+ 5.0.0
$(FSCorePackageVersion)-$(PreReleaseVersionLabel).*
-
-
- 10.6
- $(FSPackageMajorVersion).0
- $(FSPackageVersion)
- $(FSPackageVersion).0
+ 11
+ 3
+ $(FSBuildVersion)
+ $(FSRevisionVersion)
+ $(FSToolsMajorVersion).$(FSToolsMinorVersion).$(FSToolsBuildVersion)
+ $(FSToolsMajorVersion)-$(FSToolsMinorVersion)-$(FSToolsBuildVersion)
+ $(FSToolsMajorVersion).$(FSToolsMinorVersion).$(FSToolsBuildVersion).$(FSToolsRevisionVersion)
16
- 3
+ 9
$(VSMajorVersion).0
$(VSMajorVersion).$(VSMinorVersion).0
$(VSAssemblyVersionPrefix).0
-
+
+ $(FSCoreVersionPrefix)
+ $(FSCoreVersion)
+
+
$(FSCoreVersionPrefix)
- $(FSCorePackageVersion)
$(FSProductVersionPrefix)
$(VSAssemblyVersionPrefix)
- $(VersionPrefix).0
+ $(FSharpCompilerServicePackageVersion)
+ $(VersionPrefix).0
$(RestoreSources);
- https://www.myget.org/F/fsharp-daily/api/v3/index.json;
- https://dotnet.myget.org/F/roslyn-master-nightly/api/v3/index.json;
- https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
- https://dotnet.myget.org/F/dotnet-buildtools/api/v3/index.json;
- https://dotnet.myget.org/F/roslyn-tools/api/v3/index.json;
https://api.nuget.org/v3/index.json;
- https://dotnet.myget.org/F/roslyn/api/v3/index.json;
- https://dotnet.myget.org/F/symreader-converter/api/v3/index.json;
- https://dotnet.myget.org/F/interactive-window/api/v3/index.json;
- https://myget.org/F/vs-devcore/api/v3/index.json;
- https://myget.org/F/vs-editor/api/v3/index.json;
https://pkgs.dev.azure.com/azure-public/vside/_packaging/vssdk/nuget/v3/index.json;
https://pkgs.dev.azure.com/azure-public/vside/_packaging/vs-impl/nuget/v3/index.json;
- https://myget.org/F/roslyn_concord/api/v3/index.json;
-
-
- $([System.IO.File]::ReadAllText('$(MSBuildThisFileDirectory)..\RoslynPackageVersion.txt').Trim())
+
- 4.3.0
- 1.5.0
+ 4.5.1
+ 5.0.0
4.3.0
+ 4.3.0
4.0.0
4.3.0
4.3.0
4.3.0
4.3.0
4.3.0
- 4.5.2
+ 4.5.4
4.3.0
4.3.0
4.3.0
- 1.6.0
+ 5.0.0
4.3.0
1.5.0
4.3.0
@@ -90,73 +99,81 @@
4.3.0
4.3.0
4.3.0
+ 4.11.1
4.3.0
4.3.0
4.5.0
+ 3.8.0-5.20570.14
$(RoslynVersion)
$(RoslynVersion)
$(RoslynVersion)
$(RoslynVersion)
$(RoslynVersion)
$(RoslynVersion)
- 2.0.17
+ 2.0.28
$(RoslynVersion)
- 16.0.461
+ 16.6
$(MicrosoftBuildOverallPackagesVersion)
$(MicrosoftBuildOverallPackagesVersion)
$(MicrosoftBuildOverallPackagesVersion)
$(MicrosoftBuildOverallPackagesVersion)
-
- 8.0.1
+
+ 16.8.39
+ $(VisualStudioEditorPackagesVersion)
+ $(VisualStudioEditorPackagesVersion)
+ $(VisualStudioEditorPackagesVersion)
+ $(VisualStudioEditorPackagesVersion)
+ $(VisualStudioEditorPackagesVersion)
+ $(VisualStudioEditorPackagesVersion)
+ $(VisualStudioEditorPackagesVersion)
+ $(VisualStudioEditorPackagesVersion)
+ $(VisualStudioEditorPackagesVersion)
+ $(VisualStudioEditorPackagesVersion)
+
+ 16.7.30329.88
+ $(VisualStudioLanguageAndShellVersion)
+ $(VisualStudioLanguageAndShellVersion)
+ $(VisualStudioLanguageAndShellVersion)
+ $(VisualStudioLanguageAndShellVersion)
+
+ 16.7.30328.74
+ $(VisualStudioLanguageAndShellInteropVersion)
+ $(VisualStudioLanguageAndShellInteropVersion)
+ $(VisualStudioLanguageAndShellInteropVersion)
+ $(VisualStudioLanguageAndShellInteropVersion)
+ $(VisualStudioLanguageAndShellInteropVersion)
+ $(VisualStudioLanguageAndShellInteropVersion)
+ $(VisualStudioLanguageAndShellInteropVersion)
+ $(VisualStudioLanguageAndShellInteropVersion)
+ $(VisualStudioLanguageAndShellInteropVersion)
+ $(VisualStudioLanguageAndShellInteropVersion)
+ $(VisualStudioLanguageAndShellInteropVersion)
+ $(VisualStudioLanguageAndShellInteropVersion)
+ $(VisualStudioLanguageAndShellInteropVersion)
+
+ 16.8.30
+ 16.6.255
14.0.25420
- 16.1.89
- 16.1.89
1.1.4322
- 16.1.89
- 16.1.89
16.0.28226-alpha
- 16.1.28916.169
- 16.1.28917.181
- 16.1.3121
- 16.1.89
- 16.1.89
- 16.1.89
+ 16.7.30329.63
8.0.50728
- 7.10.6071
- 16.1.28917.181
- 16.1.89
8.0.50728
16.0.201-pre-g7d366164d0
2.3.6152103
14.3.25407
- 16.1.28917.181
- 16.1.28917.181
- 16.1.28917.181
10.0.30319
11.0.50727
15.0.25123-Dev15Preview
- 7.10.6072
- 8.0.50728
- 9.0.30730
- 10.0.30320
- 11.0.61031
- 12.0.30111
- 16.0.0
- 16.1.89
- 16.1.89
- 7.10.6071
- 8.0.50728
- 10.0.30320
- 12.0.30112
- 16.1.89
- 16.1.89
- 16.0.102
- 16.1.28917.181
- 15.3.58
+ 16.0.1
+ 16.0.28924.11111
+ 16.8.55
+ 16.10.31225.38
+ 16.8.33
9.0.30729
- 16.0.2264
+ 16.5.2044
12.0.4
7.0.4
8.0.4
@@ -170,20 +187,22 @@
3.0.0-alpha4
4.3.0.0
1.0.30
- 8.0.0-alpha
+ 8.0.0
2.7.0
- 3.0.0-preview-27318-01
- 3.0.0-preview-27318-01
- 15.8.0
- 1.0.0
+ 3.1.0
+ 5.0.0-preview.7.20364.11
+ 5.0.0-preview.7.20364.11
+ 16.6.1
4.3.0
- 9.0.1
+ 12.0.2
3.11.0
3.11.2
3.11.0
- 2.1.36
+ 2.1.41
1.0.0-beta2-dev3
- 5.22.2.1
- 2.0.187
+ 5.28.0.1
+ 2.6.113
+ 2.4.1
+ 5.10.3
diff --git a/eng/build-utils.ps1 b/eng/build-utils.ps1
index 772de110ca2..c601896faf1 100644
--- a/eng/build-utils.ps1
+++ b/eng/build-utils.ps1
@@ -237,16 +237,38 @@ function Make-BootstrapBuild() {
Create-Directory $dir
# prepare FsLex and Fsyacc and AssemblyCheck
- Run-MSBuild "$RepoRoot\src\buildtools\buildtools.proj" "/restore /t:Publish" -logFileName "BuildTools" -configuration $bootstrapConfiguration
- Copy-Item "$ArtifactsDir\bin\fslex\$bootstrapConfiguration\netcoreapp2.1\publish" -Destination "$dir\fslex" -Force -Recurse
- Copy-Item "$ArtifactsDir\bin\fsyacc\$bootstrapConfiguration\netcoreapp2.1\publish" -Destination "$dir\fsyacc" -Force -Recurse
- Copy-Item "$ArtifactsDir\bin\AssemblyCheck\$bootstrapConfiguration\netcoreapp2.1\publish" -Destination "$dir\AssemblyCheck" -Force -Recurse
+ $dotnetPath = InitializeDotNetCli
+ $dotnetExe = Join-Path $dotnetPath "dotnet.exe"
+ $buildToolsProject = "`"$RepoRoot\src\buildtools\buildtools.proj`""
+
+ $argNoRestore = if ($norestore) { " --no-restore" } else { "" }
+ $argNoIncremental = if ($rebuild) { " --no-incremental" } else { "" }
+
+ $args = "build $buildToolsProject -c $bootstrapConfiguration -v $verbosity -f netcoreapp3.1" + $argNoRestore + $argNoIncremental
+ if ($binaryLog) {
+ $logFilePath = Join-Path $LogDir "toolsBootstrapLog.binlog"
+ $args += " /bl:$logFilePath"
+ }
+ Exec-Console $dotnetExe $args
+
+ Copy-Item "$ArtifactsDir\bin\fslex\$bootstrapConfiguration\netcoreapp3.1" -Destination "$dir\fslex" -Force -Recurse
+ Copy-Item "$ArtifactsDir\bin\fsyacc\$bootstrapConfiguration\netcoreapp3.1" -Destination "$dir\fsyacc" -Force -Recurse
+ Copy-Item "$ArtifactsDir\bin\AssemblyCheck\$bootstrapConfiguration\netcoreapp3.1" -Destination "$dir\AssemblyCheck" -Force -Recurse
# prepare compiler
- $projectPath = "$RepoRoot\proto.proj"
- Run-MSBuild $projectPath "/restore /t:Publish /p:TargetFramework=$bootstrapTfm;ProtoTargetFramework=$bootstrapTfm" -logFileName "Bootstrap" -configuration $bootstrapConfiguration
- Copy-Item "$ArtifactsDir\bin\fsc\$bootstrapConfiguration\$bootstrapTfm\publish" -Destination "$dir\fsc" -Force -Recurse
- Copy-Item "$ArtifactsDir\bin\fsi\$bootstrapConfiguration\$bootstrapTfm\publish" -Destination "$dir\fsi" -Force -Recurse
+ $protoProject = "`"$RepoRoot\proto.proj`""
+ $args = "build $protoProject -c $bootstrapConfiguration -v $verbosity -f $bootstrapTfm" + $argNoRestore + $argNoIncremental
+ if ($binaryLog) {
+ $logFilePath = Join-Path $LogDir "protoBootstrapLog.binlog"
+ $args += " /bl:$logFilePath"
+ }
+ Exec-Console $dotnetExe $args
+
+ Copy-Item "$ArtifactsDir\bin\fsc\$bootstrapConfiguration\$bootstrapTfm" -Destination "$dir\fsc" -Force -Recurse
+ Copy-Item "$ArtifactsDir\bin\fsi\$bootstrapConfiguration\$bootstrapTfm" -Destination "$dir\fsi" -Force -Recurse
return $dir
}
+
+
+
diff --git a/eng/build.sh b/eng/build.sh
index 7f6a88128c6..e741ff85495 100755
--- a/eng/build.sh
+++ b/eng/build.sh
@@ -30,6 +30,7 @@ usage()
echo " --docker Run in a docker container if applicable"
echo " --skipAnalyzers Do not run analyzers during build operations"
echo " --prepareMachine Prepare machine for CI run, clean up processes after build"
+ echo " --sourceBuild Simulate building for source-build"
echo ""
echo "Command line arguments starting with '/p:' are passed through to MSBuild."
}
@@ -60,11 +61,15 @@ force_bootstrap=false
ci=false
skip_analyzers=false
prepare_machine=false
+source_build=false
properties=""
docker=false
args=""
+BuildCategory=""
+BuildMessage=""
+
if [[ $# = 0 ]]
then
usage
@@ -126,8 +131,9 @@ while [[ $# > 0 ]]; do
;;
--docker)
docker=true
- shift
- continue
+ ;;
+ --sourcebuild)
+ source_build=true
;;
/p:*)
properties="$properties $1"
@@ -146,8 +152,11 @@ done
. "$scriptroot/common/tools.sh"
function TestUsingNUnit() {
+ BuildCategory="Test"
+ BuildMessage="Error running tests"
testproject=""
targetframework=""
+ notestfilter=0
while [[ $# > 0 ]]; do
opt="$(echo "$1" | awk '{print tolower($0)}')"
case "$opt" in
@@ -159,6 +168,10 @@ function TestUsingNUnit() {
targetframework=$2
shift
;;
+ --notestfilter)
+ notestfilter=1
+ shift
+ ;;
*)
echo "Invalid argument: $1"
exit 1
@@ -172,31 +185,34 @@ function TestUsingNUnit() {
exit 1
fi
+ filterArgs=""
+ if [[ "${RunningAsPullRequest:-}" != "true" && $notestfilter == 0 ]]; then
+ filterArgs=" --filter TestCategory!=PullRequest"
+ fi
+
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 \"nunit;LogFilePath=$testlogpath\""
- "$DOTNET_INSTALL_DIR/dotnet" $args || {
- local exit_code=$?
- echo "dotnet test failed (exit code '$exit_code')." >&2
- ExitWithExitCode $exit_code
- }
+ args="test \"$testproject\" --no-restore --no-build -c $configuration -f $targetframework --test-adapter-path . --logger \"nunit;LogFilePath=$testlogpath\"$filterArgs"
+ "$DOTNET_INSTALL_DIR/dotnet" $args || exit $?
}
function BuildSolution {
+ BuildCategory="Build"
+ BuildMessage="Error preparing build"
local solution="FSharp.sln"
echo "$solution:"
InitializeToolset
local toolset_build_proj=$_InitializeToolset
-
+
local bl=""
if [[ "$binary_log" = true ]]; then
bl="/bl:\"$log_dir/Build.binlog\""
fi
-
- local projects="$repo_root/$solution"
-
+
+ local projects="$repo_root/$solution"
+
# https://github.com/dotnet/roslyn/issues/23736
local enable_analyzers=!$skip_analyzers
UNAME="$(uname)"
@@ -225,25 +241,27 @@ function BuildSolution {
rm -fr $bootstrap_dir
fi
if [ ! -f "$bootstrap_dir/fslex.dll" ]; then
+ BuildMessage="Error building tools"
MSBuild "$repo_root/src/buildtools/buildtools.proj" \
/restore \
- /p:Configuration=$bootstrap_config \
- /t:Publish
+ /p:Configuration=$bootstrap_config
mkdir -p "$bootstrap_dir"
- cp -pr $artifacts_dir/bin/fslex/$bootstrap_config/netcoreapp2.1/publish $bootstrap_dir/fslex
- cp -pr $artifacts_dir/bin/fsyacc/$bootstrap_config/netcoreapp2.1/publish $bootstrap_dir/fsyacc
+ cp -pr $artifacts_dir/bin/fslex/$bootstrap_config/netcoreapp3.1 $bootstrap_dir/fslex
+ cp -pr $artifacts_dir/bin/fsyacc/$bootstrap_config/netcoreapp3.1 $bootstrap_dir/fsyacc
fi
if [ ! -f "$bootstrap_dir/fsc.exe" ]; then
+ BuildMessage="Error building bootstrap"
MSBuild "$repo_root/proto.proj" \
/restore \
/p:Configuration=$bootstrap_config \
- /t:Publish
- cp -pr $artifacts_dir/bin/fsc/$bootstrap_config/netcoreapp2.1/publish $bootstrap_dir/fsc
+
+ cp -pr $artifacts_dir/bin/fsc/$bootstrap_config/netcoreapp3.1 $bootstrap_dir/fsc
fi
# do real build
+ BuildMessage="Error building solution"
MSBuild $toolset_build_proj \
$bl \
/v:$verbosity \
@@ -259,23 +277,33 @@ function BuildSolution {
/p:ContinuousIntegrationBuild=$ci \
/p:QuietRestore=$quiet_restore \
/p:QuietRestoreBinaryLog="$binary_log" \
+ /p:DotNetBuildFromSource=$source_build \
$properties
}
-InitializeDotNetCli $restore
+function TrapAndReportError {
+ local exit_code=$?
+ if [[ ! $exit_code == 0 ]]; then
+ Write-PipelineTelemetryError -category $BuildCategory "$BuildMessage (exit code '$exit_code')."
+ ExitWithExitCode $exit_code
+ fi
+}
-# enable us to build netcoreapp2.1 binaries
-InstallDotNetSdk $_InitializeDotNetCli 2.1.503
+# allow early termination to report the appropriate build failure reason
+trap TrapAndReportError EXIT
+
+InitializeDotNetCli $restore
BuildSolution
if [[ "$test_core_clr" == true ]]; then
- coreclrtestframework=netcoreapp2.1
+ coreclrtestframework=netcoreapp3.1
+ TestUsingNUnit --testproject "$repo_root/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj" --targetframework $coreclrtestframework --notestfilter
+ TestUsingNUnit --testproject "$repo_root/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj" --targetframework $coreclrtestframework --notestfilter
TestUsingNUnit --testproject "$repo_root/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj" --targetframework $coreclrtestframework
- TestUsingNUnit --testproject "$repo_root/tests/FSharp.Compiler.LanguageServer.UnitTests/FSharp.Compiler.LanguageServer.UnitTests.fsproj" --targetframework $coreclrtestframework
+ TestUsingNUnit --testproject "$repo_root/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharp.Compiler.Private.Scripting.UnitTests.fsproj" --targetframework $coreclrtestframework
TestUsingNUnit --testproject "$repo_root/tests/FSharp.Build.UnitTests/FSharp.Build.UnitTests.fsproj" --targetframework $coreclrtestframework
TestUsingNUnit --testproject "$repo_root/tests/FSharp.Core.UnitTests/FSharp.Core.UnitTests.fsproj" --targetframework $coreclrtestframework
fi
ExitWithExitCode 0
-
diff --git a/eng/common/CheckSymbols.ps1 b/eng/common/CheckSymbols.ps1
deleted file mode 100644
index b8d84607b89..00000000000
--- a/eng/common/CheckSymbols.ps1
+++ /dev/null
@@ -1,158 +0,0 @@
-param(
- [Parameter(Mandatory=$true)][string] $InputPath, # Full path to directory where NuGet packages to be checked are stored
- [Parameter(Mandatory=$true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation
- [Parameter(Mandatory=$true)][string] $SymbolToolPath # Full path to directory where dotnet symbol-tool was installed
-)
-
-Add-Type -AssemblyName System.IO.Compression.FileSystem
-
-function FirstMatchingSymbolDescriptionOrDefault {
- param(
- [string] $FullPath, # Full path to the module that has to be checked
- [string] $TargetServerParam, # Parameter to pass to `Symbol Tool` indicating the server to lookup for symbols
- [string] $SymbolsPath
- )
-
- $FileName = [System.IO.Path]::GetFileName($FullPath)
- $Extension = [System.IO.Path]::GetExtension($FullPath)
-
- # Those below are potential symbol files that the `dotnet symbol` might
- # return. Which one will be returned depend on the type of file we are
- # checking and which type of file was uploaded.
-
- # The file itself is returned
- $SymbolPath = $SymbolsPath + "\" + $FileName
-
- # PDB file for the module
- $PdbPath = $SymbolPath.Replace($Extension, ".pdb")
-
- # PDB file for R2R module (created by crossgen)
- $NGenPdb = $SymbolPath.Replace($Extension, ".ni.pdb")
-
- # DBG file for a .so library
- $SODbg = $SymbolPath.Replace($Extension, ".so.dbg")
-
- # DWARF file for a .dylib
- $DylibDwarf = $SymbolPath.Replace($Extension, ".dylib.dwarf")
-
- .\dotnet-symbol.exe --symbols --modules --windows-pdbs $TargetServerParam $FullPath -o $SymbolsPath | Out-Null
-
- if (Test-Path $PdbPath) {
- return "PDB"
- }
- elseif (Test-Path $NGenPdb) {
- return "NGen PDB"
- }
- elseif (Test-Path $SODbg) {
- return "DBG for SO"
- }
- elseif (Test-Path $DylibDwarf) {
- return "Dwarf for Dylib"
- }
- elseif (Test-Path $SymbolPath) {
- return "Module"
- }
- else {
- return $null
- }
-}
-
-function CountMissingSymbols {
- param(
- [string] $PackagePath # Path to a NuGet package
- )
-
- # Ensure input file exist
- if (!(Test-Path $PackagePath)) {
- throw "Input file does not exist: $PackagePath"
- }
-
- # Extensions for which we'll look for symbols
- $RelevantExtensions = @(".dll", ".exe", ".so", ".dylib")
-
- # How many files are missing symbol information
- $MissingSymbols = 0
-
- $PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)
- $PackageGuid = New-Guid
- $ExtractPath = Join-Path -Path $ExtractPath -ChildPath $PackageGuid
- $SymbolsPath = Join-Path -Path $ExtractPath -ChildPath "Symbols"
-
- [System.IO.Compression.ZipFile]::ExtractToDirectory($PackagePath, $ExtractPath)
-
- # Makes easier to reference `symbol tool`
- Push-Location $SymbolToolPath
-
- Get-ChildItem -Recurse $ExtractPath |
- Where-Object {$RelevantExtensions -contains $_.Extension} |
- ForEach-Object {
- if ($_.FullName -Match "\\ref\\") {
- Write-Host "`t Ignoring reference assembly file" $_.FullName
- return
- }
-
- $SymbolsOnMSDL = FirstMatchingSymbolDescriptionOrDefault $_.FullName "--microsoft-symbol-server" $SymbolsPath
- $SymbolsOnSymWeb = FirstMatchingSymbolDescriptionOrDefault $_.FullName "--internal-server" $SymbolsPath
-
- Write-Host -NoNewLine "`t Checking file" $_.FullName "... "
-
- if ($SymbolsOnMSDL -ne $null -and $SymbolsOnSymWeb -ne $null) {
- Write-Host "Symbols found on MSDL (" $SymbolsOnMSDL ") and SymWeb (" $SymbolsOnSymWeb ")"
- }
- else {
- $MissingSymbols++
-
- if ($SymbolsOnMSDL -eq $null -and $SymbolsOnSymWeb -eq $null) {
- Write-Host "No symbols found on MSDL or SymWeb!"
- }
- else {
- if ($SymbolsOnMSDL -eq $null) {
- Write-Host "No symbols found on MSDL!"
- }
- else {
- Write-Host "No symbols found on SymWeb!"
- }
- }
- }
- }
-
- Pop-Location
-
- return $MissingSymbols
-}
-
-function CheckSymbolsAvailable {
- if (Test-Path $ExtractPath) {
- Remove-Item $ExtractPath -Force -Recurse -ErrorAction SilentlyContinue
- }
-
- Get-ChildItem "$InputPath\*.nupkg" |
- ForEach-Object {
- $FileName = $_.Name
-
- # These packages from Arcade-Services include some native libraries that
- # our current symbol uploader can't handle. Below is a workaround until
- # we get issue: https://github.com/dotnet/arcade/issues/2457 sorted.
- if ($FileName -Match "Microsoft\.DotNet\.Darc\.") {
- Write-Host "Ignoring Arcade-services file: $FileName"
- Write-Host
- return
- }
- elseif ($FileName -Match "Microsoft\.DotNet\.Maestro\.Tasks\.") {
- Write-Host "Ignoring Arcade-services file: $FileName"
- Write-Host
- return
- }
-
- Write-Host "Validating $FileName "
- $Status = CountMissingSymbols "$InputPath\$FileName"
-
- if ($Status -ne 0) {
- Write-Error "Missing symbols for $Status modules in the package $FileName"
- }
-
- Write-Host
- }
-}
-
-CheckSymbolsAvailable
diff --git a/eng/common/PublishToPackageFeed.proj b/eng/common/PublishToPackageFeed.proj
deleted file mode 100644
index a1b1333723e..00000000000
--- a/eng/common/PublishToPackageFeed.proj
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-
-
-
- netcoreapp2.1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json
- https://dotnetfeed.blob.core.windows.net/arcade-validation/index.json
- https://dotnetfeed.blob.core.windows.net/aspnet-aspnetcore/index.json
- https://dotnetfeed.blob.core.windows.net/aspnet-aspnetcore-tooling/index.json
- https://dotnetfeed.blob.core.windows.net/aspnet-entityframeworkcore/index.json
- https://dotnetfeed.blob.core.windows.net/aspnet-extensions/index.json
- https://dotnetfeed.blob.core.windows.net/dotnet-coreclr/index.json
- https://dotnetfeed.blob.core.windows.net/dotnet-sdk/index.json
- https://dotnetfeed.blob.core.windows.net/dotnet-tools-internal/index.json
- https://dotnetfeed.blob.core.windows.net/dotnet-toolset/index.json
- https://dotnetfeed.blob.core.windows.net/dotnet-windowsdesktop/index.json
- https://dotnetfeed.blob.core.windows.net/nuget-nugetclient/index.json
- https://dotnetfeed.blob.core.windows.net/aspnet-entityframework6/index.json
- https://dotnetfeed.blob.core.windows.net/aspnet-blazor/index.json
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/eng/common/PublishToSymbolServers.proj b/eng/common/PublishToSymbolServers.proj
deleted file mode 100644
index 5d55e312b01..00000000000
--- a/eng/common/PublishToSymbolServers.proj
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
-
-
- netcoreapp2.1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 3650
- true
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/eng/common/SetupNugetSources.ps1 b/eng/common/SetupNugetSources.ps1
new file mode 100644
index 00000000000..a0b5fc37f43
--- /dev/null
+++ b/eng/common/SetupNugetSources.ps1
@@ -0,0 +1,161 @@
+# This file is a temporary workaround for internal builds to be able to restore from private AzDO feeds.
+# This file should be removed as part of this issue: https://github.com/dotnet/arcade/issues/4080
+#
+# What the script does is iterate over all package sources in the pointed NuGet.config and add a credential entry
+# under for each Maestro managed private feed. Two additional credential
+# entries are also added for the two private static internal feeds: dotnet3-internal and dotnet3-internal-transport.
+#
+# This script needs to be called in every job that will restore packages and which the base repo has
+# private AzDO feeds in the NuGet.config.
+#
+# See example YAML call for this script below. Note the use of the variable `$(dn-bot-dnceng-artifact-feeds-rw)`
+# from the AzureDevOps-Artifact-Feeds-Pats variable group.
+#
+# Any disabledPackageSources entries which start with "darc-int" will be re-enabled as part of this script executing
+#
+# - task: PowerShell@2
+# displayName: Setup Private Feeds Credentials
+# condition: eq(variables['Agent.OS'], 'Windows_NT')
+# inputs:
+# filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1
+# arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token
+# env:
+# Token: $(dn-bot-dnceng-artifact-feeds-rw)
+
+[CmdletBinding()]
+param (
+ [Parameter(Mandatory = $true)][string]$ConfigFile,
+ [Parameter(Mandatory = $true)][string]$Password
+)
+
+$ErrorActionPreference = "Stop"
+Set-StrictMode -Version 2.0
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+
+. $PSScriptRoot\tools.ps1
+
+# Add source entry to PackageSources
+function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Username, $Password) {
+ $packageSource = $sources.SelectSingleNode("add[@key='$SourceName']")
+
+ if ($packageSource -eq $null)
+ {
+ $packageSource = $doc.CreateElement("add")
+ $packageSource.SetAttribute("key", $SourceName)
+ $packageSource.SetAttribute("value", $SourceEndPoint)
+ $sources.AppendChild($packageSource) | Out-Null
+ }
+ else {
+ Write-Host "Package source $SourceName already present."
+ }
+
+ AddCredential -Creds $creds -Source $SourceName -Username $Username -Password $Password
+}
+
+# Add a credential node for the specified source
+function AddCredential($creds, $source, $username, $password) {
+ # Looks for credential configuration for the given SourceName. Create it if none is found.
+ $sourceElement = $creds.SelectSingleNode($Source)
+ if ($sourceElement -eq $null)
+ {
+ $sourceElement = $doc.CreateElement($Source)
+ $creds.AppendChild($sourceElement) | Out-Null
+ }
+
+ # Add the node to the credential if none is found.
+ $usernameElement = $sourceElement.SelectSingleNode("add[@key='Username']")
+ if ($usernameElement -eq $null)
+ {
+ $usernameElement = $doc.CreateElement("add")
+ $usernameElement.SetAttribute("key", "Username")
+ $sourceElement.AppendChild($usernameElement) | Out-Null
+ }
+ $usernameElement.SetAttribute("value", $Username)
+
+ # Add the to the credential if none is found.
+ # Add it as a clear text because there is no support for encrypted ones in non-windows .Net SDKs.
+ # -> https://github.com/NuGet/Home/issues/5526
+ $passwordElement = $sourceElement.SelectSingleNode("add[@key='ClearTextPassword']")
+ if ($passwordElement -eq $null)
+ {
+ $passwordElement = $doc.CreateElement("add")
+ $passwordElement.SetAttribute("key", "ClearTextPassword")
+ $sourceElement.AppendChild($passwordElement) | Out-Null
+ }
+ $passwordElement.SetAttribute("value", $Password)
+}
+
+function InsertMaestroPrivateFeedCredentials($Sources, $Creds, $Username, $Password) {
+ $maestroPrivateSources = $Sources.SelectNodes("add[contains(@key,'darc-int')]")
+
+ Write-Host "Inserting credentials for $($maestroPrivateSources.Count) Maestro's private feeds."
+
+ ForEach ($PackageSource in $maestroPrivateSources) {
+ Write-Host "`tInserting credential for Maestro's feed:" $PackageSource.Key
+ AddCredential -Creds $creds -Source $PackageSource.Key -Username $Username -Password $Password
+ }
+}
+
+function EnablePrivatePackageSources($DisabledPackageSources) {
+ $maestroPrivateSources = $DisabledPackageSources.SelectNodes("add[contains(@key,'darc-int')]")
+ ForEach ($DisabledPackageSource in $maestroPrivateSources) {
+ Write-Host "`tEnsuring private source '$($DisabledPackageSource.key)' is enabled by deleting it from disabledPackageSource"
+ # Due to https://github.com/NuGet/Home/issues/10291, we must actually remove the disabled entries
+ $DisabledPackageSources.RemoveChild($DisabledPackageSource)
+ }
+}
+
+if (!(Test-Path $ConfigFile -PathType Leaf)) {
+ Write-PipelineTelemetryError -Category 'Build' -Message "Eng/common/SetupNugetSources.ps1 returned a non-zero exit code. Couldn't find the NuGet config file: $ConfigFile"
+ ExitWithExitCode 1
+}
+
+if (!$Password) {
+ Write-PipelineTelemetryError -Category 'Build' -Message 'Eng/common/SetupNugetSources.ps1 returned a non-zero exit code. Please supply a valid PAT'
+ ExitWithExitCode 1
+}
+
+# Load NuGet.config
+$doc = New-Object System.Xml.XmlDocument
+$filename = (Get-Item $ConfigFile).FullName
+$doc.Load($filename)
+
+# Get reference to or create one if none exist already
+$sources = $doc.DocumentElement.SelectSingleNode("packageSources")
+if ($sources -eq $null) {
+ $sources = $doc.CreateElement("packageSources")
+ $doc.DocumentElement.AppendChild($sources) | Out-Null
+}
+
+# Looks for a node. Create it if none is found.
+$creds = $doc.DocumentElement.SelectSingleNode("packageSourceCredentials")
+if ($creds -eq $null) {
+ $creds = $doc.CreateElement("packageSourceCredentials")
+ $doc.DocumentElement.AppendChild($creds) | Out-Null
+}
+
+# Check for disabledPackageSources; we'll enable any darc-int ones we find there
+$disabledSources = $doc.DocumentElement.SelectSingleNode("disabledPackageSources")
+if ($disabledSources -ne $null) {
+ Write-Host "Checking for any darc-int disabled package sources in the disabledPackageSources node"
+ EnablePrivatePackageSources -DisabledPackageSources $disabledSources
+}
+
+$userName = "dn-bot"
+
+# Insert credential nodes for Maestro's private feeds
+InsertMaestroPrivateFeedCredentials -Sources $sources -Creds $creds -Username $userName -Password $Password
+
+$dotnet31Source = $sources.SelectSingleNode("add[@key='dotnet3.1']")
+if ($dotnet31Source -ne $null) {
+ AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password
+ AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password
+}
+
+$dotnet5Source = $sources.SelectSingleNode("add[@key='dotnet5']")
+if ($dotnet5Source -ne $null) {
+ AddPackageSource -Sources $sources -SourceName "dotnet5-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password
+ AddPackageSource -Sources $sources -SourceName "dotnet5-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password
+}
+
+$doc.Save($filename)
diff --git a/eng/common/SetupNugetSources.sh b/eng/common/SetupNugetSources.sh
new file mode 100644
index 00000000000..2734601c13c
--- /dev/null
+++ b/eng/common/SetupNugetSources.sh
@@ -0,0 +1,167 @@
+#!/usr/bin/env bash
+
+# This file is a temporary workaround for internal builds to be able to restore from private AzDO feeds.
+# This file should be removed as part of this issue: https://github.com/dotnet/arcade/issues/4080
+#
+# What the script does is iterate over all package sources in the pointed NuGet.config and add a credential entry
+# under for each Maestro's managed private feed. Two additional credential
+# entries are also added for the two private static internal feeds: dotnet3-internal and dotnet3-internal-transport.
+#
+# This script needs to be called in every job that will restore packages and which the base repo has
+# private AzDO feeds in the NuGet.config.
+#
+# See example YAML call for this script below. Note the use of the variable `$(dn-bot-dnceng-artifact-feeds-rw)`
+# from the AzureDevOps-Artifact-Feeds-Pats variable group.
+#
+# Any disabledPackageSources entries which start with "darc-int" will be re-enabled as part of this script executing.
+#
+# - task: Bash@3
+# displayName: Setup Private Feeds Credentials
+# inputs:
+# filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh
+# arguments: $(Build.SourcesDirectory)/NuGet.config $Token
+# condition: ne(variables['Agent.OS'], 'Windows_NT')
+# env:
+# Token: $(dn-bot-dnceng-artifact-feeds-rw)
+
+ConfigFile=$1
+CredToken=$2
+NL='\n'
+TB=' '
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $source until the file is no longer a symlink
+while [[ -h "$source" ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+. "$scriptroot/tools.sh"
+
+if [ ! -f "$ConfigFile" ]; then
+ Write-PipelineTelemetryError -Category 'Build' "Error: Eng/common/SetupNugetSources.sh returned a non-zero exit code. Couldn't find the NuGet config file: $ConfigFile"
+ ExitWithExitCode 1
+fi
+
+if [ -z "$CredToken" ]; then
+ Write-PipelineTelemetryError -category 'Build' "Error: Eng/common/SetupNugetSources.sh returned a non-zero exit code. Please supply a valid PAT"
+ ExitWithExitCode 1
+fi
+
+if [[ `uname -s` == "Darwin" ]]; then
+ NL=$'\\\n'
+ TB=''
+fi
+
+# Ensure there is a ... section.
+grep -i "" $ConfigFile
+if [ "$?" != "0" ]; then
+ echo "Adding ... section."
+ ConfigNodeHeader=""
+ PackageSourcesTemplate="${TB}${NL}${TB}"
+
+ sed -i.bak "s|$ConfigNodeHeader|$ConfigNodeHeader${NL}$PackageSourcesTemplate|" $ConfigFile
+fi
+
+# Ensure there is a ... section.
+grep -i "" $ConfigFile
+if [ "$?" != "0" ]; then
+ echo "Adding ... section."
+
+ PackageSourcesNodeFooter=""
+ PackageSourceCredentialsTemplate="${TB}${NL}${TB}"
+
+ sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourcesNodeFooter${NL}$PackageSourceCredentialsTemplate|" $ConfigFile
+fi
+
+PackageSources=()
+
+# Ensure dotnet3.1-internal and dotnet3.1-internal-transport are in the packageSources if the public dotnet3.1 feeds are present
+grep -i ""
+
+ sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
+ fi
+ PackageSources+=('dotnet3.1-internal')
+
+ grep -i "" $ConfigFile
+ if [ "$?" != "0" ]; then
+ echo "Adding dotnet3.1-internal-transport to the packageSources."
+ PackageSourcesNodeFooter=""
+ PackageSourceTemplate="${TB}"
+
+ sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
+ fi
+ PackageSources+=('dotnet3.1-internal-transport')
+fi
+
+# Ensure dotnet5-internal and dotnet5-internal-transport are in the packageSources if the public dotnet5 feeds are present
+grep -i ""
+
+ sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
+ fi
+ PackageSources+=('dotnet5-internal')
+
+ grep -i "" $ConfigFile
+ if [ "$?" != "0" ]; then
+ echo "Adding dotnet5-internal-transport to the packageSources."
+ PackageSourcesNodeFooter=""
+ PackageSourceTemplate="${TB}"
+
+ sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
+ fi
+ PackageSources+=('dotnet5-internal-transport')
+fi
+
+# I want things split line by line
+PrevIFS=$IFS
+IFS=$'\n'
+PackageSources+="$IFS"
+PackageSources+=$(grep -oh '"darc-int-[^"]*"' $ConfigFile | tr -d '"')
+IFS=$PrevIFS
+
+for FeedName in ${PackageSources[@]} ; do
+ # Check if there is no existing credential for this FeedName
+ grep -i "<$FeedName>" $ConfigFile
+ if [ "$?" != "0" ]; then
+ echo "Adding credentials for $FeedName."
+
+ PackageSourceCredentialsNodeFooter=""
+ NewCredential="${TB}${TB}<$FeedName>${NL}${NL}${NL}$FeedName>"
+
+ sed -i.bak "s|$PackageSourceCredentialsNodeFooter|$NewCredential${NL}$PackageSourceCredentialsNodeFooter|" $ConfigFile
+ fi
+done
+
+# Re-enable any entries in disabledPackageSources where the feed name contains darc-int
+grep -i "" $ConfigFile
+if [ "$?" == "0" ]; then
+ DisabledDarcIntSources=()
+ echo "Re-enabling any disabled \"darc-int\" package sources in $ConfigFile"
+ DisabledDarcIntSources+=$(grep -oh '"darc-int-[^"]*" value="true"' $ConfigFile | tr -d '"')
+ for DisabledSourceName in ${DisabledDarcIntSources[@]} ; do
+ if [[ $DisabledSourceName == darc-int* ]]
+ then
+ OldDisableValue=""
+ NewDisableValue=""
+ sed -i.bak "s|$OldDisableValue|$NewDisableValue|" $ConfigFile
+ echo "Neutralized disablePackageSources entry for '$DisabledSourceName'"
+ fi
+ done
+fi
diff --git a/eng/common/SigningValidation.proj b/eng/common/SigningValidation.proj
deleted file mode 100644
index 3d0ac80af3f..00000000000
--- a/eng/common/SigningValidation.proj
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-
-
-
- netcoreapp2.1
-
-
-
-
-
-
-
- $(NuGetPackageRoot)Microsoft.DotNet.SignCheck\$(SignCheckVersion)\tools\Microsoft.DotNet.SignCheck.exe
-
- $(PackageBasePath)
- signcheck.log
- signcheck.errors.log
- signcheck.exclusions.txt
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/eng/common/SourceLinkValidation.ps1 b/eng/common/SourceLinkValidation.ps1
deleted file mode 100644
index cb2d28cb99e..00000000000
--- a/eng/common/SourceLinkValidation.ps1
+++ /dev/null
@@ -1,184 +0,0 @@
-param(
- [Parameter(Mandatory=$true)][string] $InputPath, # Full path to directory where Symbols.NuGet packages to be checked are stored
- [Parameter(Mandatory=$true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation
- [Parameter(Mandatory=$true)][string] $SourceLinkToolPath, # Full path to directory where dotnet SourceLink CLI was installed
- [Parameter(Mandatory=$true)][string] $GHRepoName, # GitHub name of the repo including the Org. E.g., dotnet/arcade
- [Parameter(Mandatory=$true)][string] $GHCommit # GitHub commit SHA used to build the packages
-)
-
-# Cache/HashMap (File -> Exist flag) used to consult whether a file exist
-# in the repository at a specific commit point. This is populated by inserting
-# all files present in the repo at a specific commit point.
-$global:RepoFiles = @{}
-
-$ValidatePackage = {
- param(
- [string] $PackagePath # Full path to a Symbols.NuGet package
- )
-
- # Ensure input file exist
- if (!(Test-Path $PackagePath)) {
- throw "Input file does not exist: $PackagePath"
- }
-
- # Extensions for which we'll look for SourceLink information
- # For now we'll only care about Portable & Embedded PDBs
- $RelevantExtensions = @(".dll", ".exe", ".pdb")
-
- Write-Host -NoNewLine "Validating" ([System.IO.Path]::GetFileName($PackagePath)) "... "
-
- $PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)
- $ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageId
- $FailedFiles = 0
-
- Add-Type -AssemblyName System.IO.Compression.FileSystem
-
- [System.IO.Directory]::CreateDirectory($ExtractPath);
-
- $zip = [System.IO.Compression.ZipFile]::OpenRead($PackagePath)
-
- $zip.Entries |
- Where-Object {$RelevantExtensions -contains [System.IO.Path]::GetExtension($_.Name)} |
- ForEach-Object {
- $FileName = $_.FullName
- $Extension = [System.IO.Path]::GetExtension($_.Name)
- $FakeName = -Join((New-Guid), $Extension)
- $TargetFile = Join-Path -Path $ExtractPath -ChildPath $FakeName
-
- # We ignore resource DLLs
- if ($FileName.EndsWith(".resources.dll")) {
- return
- }
-
- [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile, $true)
-
- $ValidateFile = {
- param(
- [string] $FullPath, # Full path to the module that has to be checked
- [string] $RealPath,
- [ref] $FailedFiles
- )
-
- # Makes easier to reference `sourcelink cli`
- Push-Location $using:SourceLinkToolPath
-
- $SourceLinkInfos = .\sourcelink.exe print-urls $FullPath | Out-String
-
- if ($LASTEXITCODE -eq 0 -and -not ([string]::IsNullOrEmpty($SourceLinkInfos))) {
- $NumFailedLinks = 0
-
- # We only care about Http addresses
- $Matches = (Select-String '(http[s]?)(:\/\/)([^\s,]+)' -Input $SourceLinkInfos -AllMatches).Matches
-
- if ($Matches.Count -ne 0) {
- $Matches.Value |
- ForEach-Object {
- $Link = $_
- $CommitUrl = -Join("https://raw.githubusercontent.com/", $using:GHRepoName, "/", $using:GHCommit, "/")
- $FilePath = $Link.Replace($CommitUrl, "")
- $Status = 200
- $Cache = $using:RepoFiles
-
- if ( !($Cache.ContainsKey($FilePath)) ) {
- try {
- $Uri = $Link -as [System.URI]
-
- # Only GitHub links are valid
- if ($Uri.AbsoluteURI -ne $null -and $Uri.Host -match "github") {
- $Status = (Invoke-WebRequest -Uri $Link -UseBasicParsing -Method HEAD -TimeoutSec 5).StatusCode
- }
- else {
- $Status = 0
- }
- }
- catch {
- $Status = 0
- }
- }
-
- if ($Status -ne 200) {
- if ($NumFailedLinks -eq 0) {
- if ($FailedFiles.Value -eq 0) {
- Write-Host
- }
-
- Write-Host "`tFile $RealPath has broken links:"
- }
-
- Write-Host "`t`tFailed to retrieve $Link"
-
- $NumFailedLinks++
- }
- }
- }
-
- if ($NumFailedLinks -ne 0) {
- $FailedFiles.value++
- $global:LASTEXITCODE = 1
- }
- }
-
- Pop-Location
- }
-
- &$ValidateFile $TargetFile $FileName ([ref]$FailedFiles)
- }
-
- $zip.Dispose()
-
- if ($FailedFiles -eq 0) {
- Write-Host "Passed."
- }
-}
-
-function ValidateSourceLinkLinks {
- if (!($GHRepoName -Match "^[^\s\/]+/[^\s\/]+$")) {
- Write-Host "GHRepoName should be in the format /"
- $global:LASTEXITCODE = 1
- return
- }
-
- if (!($GHCommit -Match "^[0-9a-fA-F]{40}$")) {
- Write-Host "GHCommit should be a 40 chars hexadecimal string"
- $global:LASTEXITCODE = 1
- return
- }
-
- $RepoTreeURL = -Join("https://api.github.com/repos/", $GHRepoName, "/git/trees/", $GHCommit, "?recursive=1")
- $CodeExtensions = @(".cs", ".vb", ".fs", ".fsi", ".fsx", ".fsscript")
-
- try {
- # Retrieve the list of files in the repo at that particular commit point and store them in the RepoFiles hash
- $Data = Invoke-WebRequest $RepoTreeURL | ConvertFrom-Json | Select-Object -ExpandProperty tree
-
- foreach ($file in $Data) {
- $Extension = [System.IO.Path]::GetExtension($file.path)
-
- if ($CodeExtensions.Contains($Extension)) {
- $RepoFiles[$file.path] = 1
- }
- }
- }
- catch {
- Write-Host "Problems downloading the list of files from the repo. Url used: $RepoTreeURL"
- $global:LASTEXITCODE = 1
- return
- }
-
- if (Test-Path $ExtractPath) {
- Remove-Item $ExtractPath -Force -Recurse -ErrorAction SilentlyContinue
- }
-
- # Process each NuGet package in parallel
- $Jobs = @()
- Get-ChildItem "$InputPath\*.symbols.nupkg" |
- ForEach-Object {
- $Jobs += Start-Job -ScriptBlock $ValidatePackage -ArgumentList $_.FullName
- }
-
- foreach ($Job in $Jobs) {
- Wait-Job -Id $Job.Id | Receive-Job
- }
-}
-
-Measure-Command { ValidateSourceLinkLinks }
diff --git a/eng/common/build.ps1 b/eng/common/build.ps1
index feb58d14191..94a91c0817e 100644
--- a/eng/common/build.ps1
+++ b/eng/common/build.ps1
@@ -18,56 +18,67 @@ Param(
[switch] $sign,
[switch] $pack,
[switch] $publish,
+ [switch] $clean,
[switch][Alias('bl')]$binaryLog,
+ [switch][Alias('nobl')]$excludeCIBinarylog,
[switch] $ci,
[switch] $prepareMachine,
+ [string] $runtimeSourceFeed = '',
+ [string] $runtimeSourceFeedKey = '',
[switch] $help,
[Parameter(ValueFromRemainingArguments=$true)][String[]]$properties
)
-. $PSScriptRoot\tools.ps1
-
+# Unset 'Platform' environment variable to avoid unwanted collision in InstallDotNetCore.targets file
+# some computer has this env var defined (e.g. Some HP)
+if($env:Platform) {
+ $env:Platform=""
+}
function Print-Usage() {
- Write-Host "Common settings:"
- Write-Host " -configuration Build configuration: 'Debug' or 'Release' (short: -c)"
- Write-Host " -platform Platform configuration: 'x86', 'x64' or any valid Platform value to pass to msbuild"
- Write-Host " -verbosity Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic] (short: -v)"
- Write-Host " -binaryLog Output binary log (short: -bl)"
- Write-Host " -help Print help and exit"
- Write-Host ""
-
- Write-Host "Actions:"
- Write-Host " -restore Restore dependencies (short: -r)"
- Write-Host " -build Build solution (short: -b)"
- Write-Host " -rebuild Rebuild solution"
- Write-Host " -deploy Deploy built VSIXes"
- Write-Host " -deployDeps Deploy dependencies (e.g. VSIXes for integration tests)"
- Write-Host " -test Run all unit tests in the solution (short: -t)"
- Write-Host " -integrationTest Run all integration tests in the solution"
- Write-Host " -performanceTest Run all performance tests in the solution"
- Write-Host " -pack Package build outputs into NuGet packages and Willow components"
- Write-Host " -sign Sign build outputs"
- Write-Host " -publish Publish artifacts (e.g. symbols)"
- Write-Host ""
-
- Write-Host "Advanced settings:"
- Write-Host " -projects Semi-colon delimited list of sln/proj's to build. Globbing is supported (*.sln)"
- Write-Host " -ci Set when running on CI server"
- Write-Host " -prepareMachine Prepare machine for CI run, clean up processes after build"
- Write-Host " -warnAsError Sets warnaserror msbuild parameter ('true' or 'false')"
- Write-Host " -msbuildEngine Msbuild engine to use to run build ('dotnet', 'vs', or unspecified)."
- Write-Host ""
-
- Write-Host "Command line arguments not listed above are passed thru to msbuild."
- Write-Host "The above arguments can be shortened as much as to be unambiguous (e.g. -co for configuration, -t for test, etc.)."
+ Write-Host "Common settings:"
+ Write-Host " -configuration Build configuration: 'Debug' or 'Release' (short: -c)"
+ Write-Host " -platform Platform configuration: 'x86', 'x64' or any valid Platform value to pass to msbuild"
+ Write-Host " -verbosity Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic] (short: -v)"
+ Write-Host " -binaryLog Output binary log (short: -bl)"
+ Write-Host " -help Print help and exit"
+ Write-Host ""
+
+ Write-Host "Actions:"
+ Write-Host " -restore Restore dependencies (short: -r)"
+ Write-Host " -build Build solution (short: -b)"
+ Write-Host " -rebuild Rebuild solution"
+ Write-Host " -deploy Deploy built VSIXes"
+ Write-Host " -deployDeps Deploy dependencies (e.g. VSIXes for integration tests)"
+ Write-Host " -test Run all unit tests in the solution (short: -t)"
+ Write-Host " -integrationTest Run all integration tests in the solution"
+ Write-Host " -performanceTest Run all performance tests in the solution"
+ Write-Host " -pack Package build outputs into NuGet packages and Willow components"
+ Write-Host " -sign Sign build outputs"
+ Write-Host " -publish Publish artifacts (e.g. symbols)"
+ Write-Host " -clean Clean the solution"
+ Write-Host ""
+
+ Write-Host "Advanced settings:"
+ Write-Host " -projects Semi-colon delimited list of sln/proj's to build. Globbing is supported (*.sln)"
+ Write-Host " -ci Set when running on CI server"
+ Write-Host " -excludeCIBinarylog Don't output binary log (short: -nobl)"
+ Write-Host " -prepareMachine Prepare machine for CI run, clean up processes after build"
+ Write-Host " -warnAsError Sets warnaserror msbuild parameter ('true' or 'false')"
+ Write-Host " -msbuildEngine Msbuild engine to use to run build ('dotnet', 'vs', or unspecified)."
+ Write-Host ""
+
+ Write-Host "Command line arguments not listed above are passed thru to msbuild."
+ Write-Host "The above arguments can be shortened as much as to be unambiguous (e.g. -co for configuration, -t for test, etc.)."
}
+. $PSScriptRoot\tools.ps1
+
function InitializeCustomToolset {
if (-not $restore) {
return
}
- $script = Join-Path $EngRoot "restore-toolset.ps1"
+ $script = Join-Path $EngRoot 'restore-toolset.ps1'
if (Test-Path $script) {
. $script
@@ -78,13 +89,17 @@ function Build {
$toolsetBuildProj = InitializeToolset
InitializeCustomToolset
- $bl = if ($binaryLog) { "/bl:" + (Join-Path $LogDir "Build.binlog") } else { "" }
- $platformArg = if ($platform) { "/p:Platform=$platform" } else { "" }
+ $bl = if ($binaryLog) { '/bl:' + (Join-Path $LogDir 'Build.binlog') } else { '' }
+ $platformArg = if ($platform) { "/p:Platform=$platform" } else { '' }
if ($projects) {
# Re-assign properties to a new variable because PowerShell doesn't let us append properties directly for unclear reasons.
# Explicitly set the type as string[] because otherwise PowerShell would make this char[] if $properties is empty.
[string[]] $msbuildArgs = $properties
+
+ # Resolve relative project paths into full paths
+ $projects = ($projects.Split(';').ForEach({Resolve-Path $_}) -join ';')
+
$msbuildArgs += "/p:Projects=$projects"
$properties = $msbuildArgs
}
@@ -109,24 +124,27 @@ function Build {
}
try {
- if ($help -or (($null -ne $properties) -and ($properties.Contains("/help") -or $properties.Contains("/?")))) {
+ if ($clean) {
+ if (Test-Path $ArtifactsDir) {
+ Remove-Item -Recurse -Force $ArtifactsDir
+ Write-Host 'Artifacts directory deleted.'
+ }
+ exit 0
+ }
+
+ if ($help -or (($null -ne $properties) -and ($properties.Contains('/help') -or $properties.Contains('/?')))) {
Print-Usage
exit 0
}
if ($ci) {
- $binaryLog = $true
+ if (-not $excludeCIBinarylog) {
+ $binaryLog = $true
+ }
$nodeReuse = $false
}
- # Import custom tools configuration, if present in the repo.
- # Note: Import in global scope so that the script set top-level variables without qualification.
- $configureToolsetScript = Join-Path $EngRoot "configure-toolset.ps1"
- if (Test-Path $configureToolsetScript) {
- . $configureToolsetScript
- }
-
- if (($restore) -and ($null -eq $env:DisableNativeToolsetInstalls)) {
+ if ($restore) {
InitializeNativeTools
}
@@ -134,7 +152,7 @@ try {
}
catch {
Write-Host $_.ScriptStackTrace
- Write-PipelineTelemetryError -Category "InitializeToolset" -Message $_
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_
ExitWithExitCode 1
}
diff --git a/eng/common/build.sh b/eng/common/build.sh
index 6236fc4d38c..252b63604e6 100755
--- a/eng/common/build.sh
+++ b/eng/common/build.sh
@@ -26,11 +26,13 @@ usage()
echo " --pack Package build outputs into NuGet packages and Willow components"
echo " --sign Sign build outputs"
echo " --publish Publish artifacts (e.g. symbols)"
+ echo " --clean Clean the solution"
echo ""
echo "Advanced settings:"
echo " --projects Project or solution file(s) to build"
echo " --ci Set when running on CI server"
+ echo " --excludeCIBinarylog Don't output binary log (short: -nobl)"
echo " --prepareMachine Prepare machine for CI run, clean up processes after build"
echo " --nodeReuse Sets nodereuse msbuild parameter ('true' or 'false')"
echo " --warnAsError Sets warnaserror msbuild parameter ('true' or 'false')"
@@ -62,19 +64,22 @@ publish=false
sign=false
public=false
ci=false
+clean=false
warn_as_error=true
node_reuse=true
binary_log=false
+exclude_ci_binary_log=false
pipelines_log=false
projects=''
configuration='Debug'
prepare_machine=false
verbosity='minimal'
+runtime_source_feed=''
+runtime_source_feed_key=''
properties=''
-
while [[ $# > 0 ]]; do
opt="$(echo "${1/#--/-}" | awk '{print tolower($0)}')"
case "$opt" in
@@ -82,6 +87,9 @@ while [[ $# > 0 ]]; do
usage
exit 0
;;
+ -clean)
+ clean=true
+ ;;
-configuration|-c)
configuration=$2
shift
@@ -93,6 +101,9 @@ while [[ $# > 0 ]]; do
-binarylog|-bl)
binary_log=true
;;
+ -excludeCIBinarylog|-nobl)
+ exclude_ci_binary_log=true
+ ;;
-pipelineslog|-pl)
pipelines_log=true
;;
@@ -141,6 +152,14 @@ while [[ $# > 0 ]]; do
node_reuse=$2
shift
;;
+ -runtimesourcefeed)
+ runtime_source_feed=$2
+ shift
+ ;;
+ -runtimesourcefeedkey)
+ runtime_source_feed_key=$2
+ shift
+ ;;
*)
properties="$properties $1"
;;
@@ -151,8 +170,10 @@ done
if [[ "$ci" == true ]]; then
pipelines_log=true
- binary_log=true
node_reuse=false
+ if [[ "$exclude_ci_binary_log" == false ]]; then
+ binary_log=true
+ fi
fi
. "$scriptroot/tools.sh"
@@ -196,20 +217,15 @@ function Build {
ExitWithExitCode 0
}
-# Import custom tools configuration, if present in the repo.
-configure_toolset_script="$eng_root/configure-toolset.sh"
-if [[ -a "$configure_toolset_script" ]]; then
- . "$configure_toolset_script"
-fi
-
-# TODO: https://github.com/dotnet/arcade/issues/1468
-# Temporary workaround to avoid breaking change.
-# Remove once repos are updated.
-if [[ -n "${useInstalledDotNetCli:-}" ]]; then
- use_installed_dotnet_cli="$useInstalledDotNetCli"
+if [[ "$clean" == true ]]; then
+ if [ -d "$artifacts_dir" ]; then
+ rm -rf $artifacts_dir
+ echo "Artifacts directory deleted."
+ fi
+ exit 0
fi
-if [[ "$restore" == true && -z ${DisableNativeToolsetInstalls:-} ]]; then
+if [[ "$restore" == true ]]; then
InitializeNativeTools
fi
diff --git a/eng/common/cross/android/arm/toolchain.cmake b/eng/common/cross/android/arm/toolchain.cmake
deleted file mode 100644
index a7e1c73501b..00000000000
--- a/eng/common/cross/android/arm/toolchain.cmake
+++ /dev/null
@@ -1,41 +0,0 @@
-set(CROSS_NDK_TOOLCHAIN $ENV{ROOTFS_DIR}/../)
-set(CROSS_ROOTFS ${CROSS_NDK_TOOLCHAIN}/sysroot)
-set(CLR_CMAKE_PLATFORM_ANDROID "Android")
-
-set(CMAKE_SYSTEM_NAME Linux)
-set(CMAKE_SYSTEM_VERSION 1)
-set(CMAKE_SYSTEM_PROCESSOR arm)
-
-## Specify the toolchain
-set(TOOLCHAIN "arm-linux-androideabi")
-set(CMAKE_PREFIX_PATH ${CROSS_NDK_TOOLCHAIN})
-set(TOOLCHAIN_PREFIX ${TOOLCHAIN}-)
-
-find_program(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}clang)
-find_program(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}clang++)
-find_program(CMAKE_ASM_COMPILER ${TOOLCHAIN_PREFIX}clang)
-find_program(CMAKE_AR ${TOOLCHAIN_PREFIX}ar)
-find_program(CMAKE_LD ${TOOLCHAIN_PREFIX}ar)
-find_program(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy)
-find_program(CMAKE_OBJDUMP ${TOOLCHAIN_PREFIX}objdump)
-
-add_compile_options(--sysroot=${CROSS_ROOTFS})
-add_compile_options(-fPIE)
-add_compile_options(-mfloat-abi=soft)
-include_directories(SYSTEM ${CROSS_NDK_TOOLCHAIN}/include/c++/4.9.x/)
-include_directories(SYSTEM ${CROSS_NDK_TOOLCHAIN}/include/c++/4.9.x/arm-linux-androideabi/)
-
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -B ${CROSS_ROOTFS}/usr/lib/gcc/${TOOLCHAIN}")
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/lib/${TOOLCHAIN}")
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} --sysroot=${CROSS_ROOTFS}")
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -fPIE -pie")
-
-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE)
-set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE)
-set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE)
-
-set(CMAKE_FIND_ROOT_PATH "${CROSS_ROOTFS}")
-set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
-set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
-set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
diff --git a/eng/common/cross/android/arm64/toolchain.cmake b/eng/common/cross/android/arm64/toolchain.cmake
deleted file mode 100644
index 29415899c1c..00000000000
--- a/eng/common/cross/android/arm64/toolchain.cmake
+++ /dev/null
@@ -1,42 +0,0 @@
-set(CROSS_NDK_TOOLCHAIN $ENV{ROOTFS_DIR}/../)
-set(CROSS_ROOTFS ${CROSS_NDK_TOOLCHAIN}/sysroot)
-set(CLR_CMAKE_PLATFORM_ANDROID "Android")
-
-set(CMAKE_SYSTEM_NAME Linux)
-set(CMAKE_SYSTEM_VERSION 1)
-set(CMAKE_SYSTEM_PROCESSOR aarch64)
-
-## Specify the toolchain
-set(TOOLCHAIN "aarch64-linux-android")
-set(CMAKE_PREFIX_PATH ${CROSS_NDK_TOOLCHAIN})
-set(TOOLCHAIN_PREFIX ${TOOLCHAIN}-)
-
-find_program(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}clang)
-find_program(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}clang++)
-find_program(CMAKE_ASM_COMPILER ${TOOLCHAIN_PREFIX}clang)
-find_program(CMAKE_AR ${TOOLCHAIN_PREFIX}ar)
-find_program(CMAKE_LD ${TOOLCHAIN_PREFIX}ar)
-find_program(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy)
-find_program(CMAKE_OBJDUMP ${TOOLCHAIN_PREFIX}objdump)
-
-add_compile_options(--sysroot=${CROSS_ROOTFS})
-add_compile_options(-fPIE)
-
-## Needed for Android or bionic specific conditionals
-add_compile_options(-D__ANDROID__)
-add_compile_options(-D__BIONIC__)
-
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -B ${CROSS_ROOTFS}/usr/lib/gcc/${TOOLCHAIN}")
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -L${CROSS_ROOTFS}/lib/${TOOLCHAIN}")
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} --sysroot=${CROSS_ROOTFS}")
-set(CROSS_LINK_FLAGS "${CROSS_LINK_FLAGS} -fPIE -pie")
-
-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE)
-set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE)
-set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${CROSS_LINK_FLAGS}" CACHE STRING "" FORCE)
-
-set(CMAKE_FIND_ROOT_PATH "${CROSS_ROOTFS}")
-set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
-set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
-set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
diff --git a/eng/common/cross/arm64/tizen-build-rootfs.sh b/eng/common/cross/arm64/tizen-build-rootfs.sh
new file mode 100644
index 00000000000..13bfddb5e2a
--- /dev/null
+++ b/eng/common/cross/arm64/tizen-build-rootfs.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+set -e
+
+__CrossDir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+__TIZEN_CROSSDIR="$__CrossDir/tizen"
+
+if [[ -z "$ROOTFS_DIR" ]]; then
+ echo "ROOTFS_DIR is not defined."
+ exit 1;
+fi
+
+TIZEN_TMP_DIR=$ROOTFS_DIR/tizen_tmp
+mkdir -p $TIZEN_TMP_DIR
+
+# Download files
+echo ">>Start downloading files"
+VERBOSE=1 $__CrossDir/tizen-fetch.sh $TIZEN_TMP_DIR
+echo "<>Start constructing Tizen rootfs"
+TIZEN_RPM_FILES=`ls $TIZEN_TMP_DIR/*.rpm`
+cd $ROOTFS_DIR
+for f in $TIZEN_RPM_FILES; do
+ rpm2cpio $f | cpio -idm --quiet
+done
+echo "<>Start configuring Tizen rootfs"
+ln -sfn asm-arm64 ./usr/include/asm
+patch -p1 < $__TIZEN_CROSSDIR/tizen.patch
+echo "</dev/null; then
+ VERBOSE=0
+fi
+
+Log()
+{
+ if [ $VERBOSE -ge $1 ]; then
+ echo ${@:2}
+ fi
+}
+
+Inform()
+{
+ Log 1 -e "\x1B[0;34m$@\x1B[m"
+}
+
+Debug()
+{
+ Log 2 -e "\x1B[0;32m$@\x1B[m"
+}
+
+Error()
+{
+ >&2 Log 0 -e "\x1B[0;31m$@\x1B[m"
+}
+
+Fetch()
+{
+ URL=$1
+ FILE=$2
+ PROGRESS=$3
+ if [ $VERBOSE -ge 1 ] && [ $PROGRESS ]; then
+ CURL_OPT="--progress-bar"
+ else
+ CURL_OPT="--silent"
+ fi
+ curl $CURL_OPT $URL > $FILE
+}
+
+hash curl 2> /dev/null || { Error "Require 'curl' Aborting."; exit 1; }
+hash xmllint 2> /dev/null || { Error "Require 'xmllint' Aborting."; exit 1; }
+hash sha256sum 2> /dev/null || { Error "Require 'sha256sum' Aborting."; exit 1; }
+
+TMPDIR=$1
+if [ ! -d $TMPDIR ]; then
+ TMPDIR=./tizen_tmp
+ Debug "Create temporary directory : $TMPDIR"
+ mkdir -p $TMPDIR
+fi
+
+TIZEN_URL=http://download.tizen.org/snapshots/tizen/
+BUILD_XML=build.xml
+REPOMD_XML=repomd.xml
+PRIMARY_XML=primary.xml
+TARGET_URL="http://__not_initialized"
+
+Xpath_get()
+{
+ XPATH_RESULT=''
+ XPATH=$1
+ XML_FILE=$2
+ RESULT=$(xmllint --xpath $XPATH $XML_FILE)
+ if [[ -z ${RESULT// } ]]; then
+ Error "Can not find target from $XML_FILE"
+ Debug "Xpath = $XPATH"
+ exit 1
+ fi
+ XPATH_RESULT=$RESULT
+}
+
+fetch_tizen_pkgs_init()
+{
+ TARGET=$1
+ PROFILE=$2
+ Debug "Initialize TARGET=$TARGET, PROFILE=$PROFILE"
+
+ TMP_PKG_DIR=$TMPDIR/tizen_${PROFILE}_pkgs
+ if [ -d $TMP_PKG_DIR ]; then rm -rf $TMP_PKG_DIR; fi
+ mkdir -p $TMP_PKG_DIR
+
+ PKG_URL=$TIZEN_URL/$PROFILE/latest
+
+ BUILD_XML_URL=$PKG_URL/$BUILD_XML
+ TMP_BUILD=$TMP_PKG_DIR/$BUILD_XML
+ TMP_REPOMD=$TMP_PKG_DIR/$REPOMD_XML
+ TMP_PRIMARY=$TMP_PKG_DIR/$PRIMARY_XML
+ TMP_PRIMARYGZ=${TMP_PRIMARY}.gz
+
+ Fetch $BUILD_XML_URL $TMP_BUILD
+
+ Debug "fetch $BUILD_XML_URL to $TMP_BUILD"
+
+ TARGET_XPATH="//build/buildtargets/buildtarget[@name=\"$TARGET\"]/repo[@type=\"binary\"]/text()"
+ Xpath_get $TARGET_XPATH $TMP_BUILD
+ TARGET_PATH=$XPATH_RESULT
+ TARGET_URL=$PKG_URL/$TARGET_PATH
+
+ REPOMD_URL=$TARGET_URL/repodata/repomd.xml
+ PRIMARY_XPATH='string(//*[local-name()="data"][@type="primary"]/*[local-name()="location"]/@href)'
+
+ Fetch $REPOMD_URL $TMP_REPOMD
+
+ Debug "fetch $REPOMD_URL to $TMP_REPOMD"
+
+ Xpath_get $PRIMARY_XPATH $TMP_REPOMD
+ PRIMARY_XML_PATH=$XPATH_RESULT
+ PRIMARY_URL=$TARGET_URL/$PRIMARY_XML_PATH
+
+ Fetch $PRIMARY_URL $TMP_PRIMARYGZ
+
+ Debug "fetch $PRIMARY_URL to $TMP_PRIMARYGZ"
+
+ gunzip $TMP_PRIMARYGZ
+
+ Debug "unzip $TMP_PRIMARYGZ to $TMP_PRIMARY"
+}
+
+fetch_tizen_pkgs()
+{
+ ARCH=$1
+ PACKAGE_XPATH_TPL='string(//*[local-name()="metadata"]/*[local-name()="package"][*[local-name()="name"][text()="_PKG_"]][*[local-name()="arch"][text()="_ARCH_"]]/*[local-name()="location"]/@href)'
+
+ PACKAGE_CHECKSUM_XPATH_TPL='string(//*[local-name()="metadata"]/*[local-name()="package"][*[local-name()="name"][text()="_PKG_"]][*[local-name()="arch"][text()="_ARCH_"]]/*[local-name()="checksum"]/text())'
+
+ for pkg in ${@:2}
+ do
+ Inform "Fetching... $pkg"
+ XPATH=${PACKAGE_XPATH_TPL/_PKG_/$pkg}
+ XPATH=${XPATH/_ARCH_/$ARCH}
+ Xpath_get $XPATH $TMP_PRIMARY
+ PKG_PATH=$XPATH_RESULT
+
+ XPATH=${PACKAGE_CHECKSUM_XPATH_TPL/_PKG_/$pkg}
+ XPATH=${XPATH/_ARCH_/$ARCH}
+ Xpath_get $XPATH $TMP_PRIMARY
+ CHECKSUM=$XPATH_RESULT
+
+ PKG_URL=$TARGET_URL/$PKG_PATH
+ PKG_FILE=$(basename $PKG_PATH)
+ PKG_PATH=$TMPDIR/$PKG_FILE
+
+ Debug "Download $PKG_URL to $PKG_PATH"
+ Fetch $PKG_URL $PKG_PATH true
+
+ echo "$CHECKSUM $PKG_PATH" | sha256sum -c - > /dev/null
+ if [ $? -ne 0 ]; then
+ Error "Fail to fetch $PKG_URL to $PKG_PATH"
+ Debug "Checksum = $CHECKSUM"
+ exit 1
+ fi
+ done
+}
+
+Inform "Initialize arm base"
+fetch_tizen_pkgs_init standard base
+Inform "fetch common packages"
+fetch_tizen_pkgs aarch64 gcc glibc glibc-devel libicu libicu-devel libatomic linux-glibc-devel
+Inform "fetch coreclr packages"
+fetch_tizen_pkgs aarch64 lldb lldb-devel libgcc libstdc++ libstdc++-devel libunwind libunwind-devel lttng-ust-devel lttng-ust userspace-rcu-devel userspace-rcu
+Inform "fetch corefx packages"
+fetch_tizen_pkgs aarch64 libcom_err libcom_err-devel zlib zlib-devel libopenssl11 libopenssl1.1-devel krb5 krb5-devel
+
+Inform "Initialize standard unified"
+fetch_tizen_pkgs_init standard unified
+Inform "fetch corefx packages"
+fetch_tizen_pkgs aarch64 gssdp gssdp-devel tizen-release
+
diff --git a/eng/common/cross/arm64/tizen/tizen.patch b/eng/common/cross/arm64/tizen/tizen.patch
new file mode 100644
index 00000000000..af7c8be0590
--- /dev/null
+++ b/eng/common/cross/arm64/tizen/tizen.patch
@@ -0,0 +1,9 @@
+diff -u -r a/usr/lib/libc.so b/usr/lib/libc.so
+--- a/usr/lib64/libc.so 2016-12-30 23:00:08.284951863 +0900
++++ b/usr/lib64/libc.so 2016-12-30 23:00:32.140951815 +0900
+@@ -2,4 +2,4 @@
+ Use the shared library, but some functions are only in
+ the static library, so try that secondarily. */
+ OUTPUT_FORMAT(elf64-littleaarch64)
+-GROUP ( /lib64/libc.so.6 /usr/lib64/libc_nonshared.a AS_NEEDED ( /lib/ld-linux-aarch64.so.1 ) )
++GROUP ( libc.so.6 libc_nonshared.a AS_NEEDED ( ld-linux-aarch64.so.1 ) )
diff --git a/eng/common/cross/armel/armel.jessie.patch b/eng/common/cross/armel/armel.jessie.patch
new file mode 100644
index 00000000000..2d261561935
--- /dev/null
+++ b/eng/common/cross/armel/armel.jessie.patch
@@ -0,0 +1,43 @@
+diff -u -r a/usr/include/urcu/uatomic/generic.h b/usr/include/urcu/uatomic/generic.h
+--- a/usr/include/urcu/uatomic/generic.h 2014-10-22 15:00:58.000000000 -0700
++++ b/usr/include/urcu/uatomic/generic.h 2020-10-30 21:38:28.550000000 -0700
+@@ -69,10 +69,10 @@
+ #endif
+ #ifdef UATOMIC_HAS_ATOMIC_SHORT
+ case 2:
+- return __sync_val_compare_and_swap_2(addr, old, _new);
++ return __sync_val_compare_and_swap_2((uint16_t*) addr, old, _new);
+ #endif
+ case 4:
+- return __sync_val_compare_and_swap_4(addr, old, _new);
++ return __sync_val_compare_and_swap_4((uint32_t*) addr, old, _new);
+ #if (CAA_BITS_PER_LONG == 64)
+ case 8:
+ return __sync_val_compare_and_swap_8(addr, old, _new);
+@@ -109,7 +109,7 @@
+ return;
+ #endif
+ case 4:
+- __sync_and_and_fetch_4(addr, val);
++ __sync_and_and_fetch_4((uint32_t*) addr, val);
+ return;
+ #if (CAA_BITS_PER_LONG == 64)
+ case 8:
+@@ -148,7 +148,7 @@
+ return;
+ #endif
+ case 4:
+- __sync_or_and_fetch_4(addr, val);
++ __sync_or_and_fetch_4((uint32_t*) addr, val);
+ return;
+ #if (CAA_BITS_PER_LONG == 64)
+ case 8:
+@@ -187,7 +187,7 @@
+ return __sync_add_and_fetch_2(addr, val);
+ #endif
+ case 4:
+- return __sync_add_and_fetch_4(addr, val);
++ return __sync_add_and_fetch_4((uint32_t*) addr, val);
+ #if (CAA_BITS_PER_LONG == 64)
+ case 8:
+ return __sync_add_and_fetch_8(addr, val);
diff --git a/eng/common/cross/armel/tizen-build-rootfs.sh b/eng/common/cross/armel/tizen-build-rootfs.sh
index 87c48e78fbb..9a4438af61c 100755
--- a/eng/common/cross/armel/tizen-build-rootfs.sh
+++ b/eng/common/cross/armel/tizen-build-rootfs.sh
@@ -9,13 +9,6 @@ if [[ -z "$ROOTFS_DIR" ]]; then
exit 1;
fi
-# Clean-up (TODO-Cleanup: We may already delete $ROOTFS_DIR at ./cross/build-rootfs.sh.)
-# hk0110
-if [ -d "$ROOTFS_DIR" ]; then
- umount $ROOTFS_DIR/*
- rm -rf $ROOTFS_DIR
-fi
-
TIZEN_TMP_DIR=$ROOTFS_DIR/tizen_tmp
mkdir -p $TIZEN_TMP_DIR
@@ -37,8 +30,6 @@ rm -rf $TIZEN_TMP_DIR
# Configure Tizen rootfs
echo ">>Start configuring Tizen rootfs"
-rm ./usr/lib/libunwind.so
-ln -s libunwind.so.8 ./usr/lib/libunwind.so
ln -sfn asm-arm ./usr/include/asm
patch -p1 < $__TIZEN_CROSSDIR/tizen.patch
echo "< $__ToolchainDir/sysroot/android_platform
-echo Now run:
-echo CONFIG_DIR=\`realpath cross/android/$__BuildArch\` ROOTFS_DIR=\`realpath $__ToolchainDir/sysroot\` ./build.sh cross $__BuildArch skipgenerateversion skipnuget cmakeargs -DENABLE_LLDBPLUGIN=0
+for path in $(wget -qO- http://termux.net/dists/stable/main/binary-$__AndroidArch/Packages |\
+ grep -A15 "Package: \(${__AndroidPackages// /\\|}\)" | grep -v "static\|tool" | grep Filename); do
+ if [[ "$path" != "Filename:" ]]; then
+ echo "Working on: $path"
+ wget -qO- http://termux.net/$path | dpkg -x - "$__TmpDir"
+ fi
+done
+
+cp -R "$__TmpDir/data/data/com.termux/files/usr/"* "$__ToolchainDir/sysroot/usr/"
+
+# Generate platform file for build.sh script to assign to __DistroRid
+echo "Generating platform file..."
+echo "RID=android.${__ApiLevel}-${__BuildArch}" > $__ToolchainDir/sysroot/android_platform
+
+echo "Now to build coreclr, libraries and installers; run:"
+echo ROOTFS_DIR=\$\(realpath $__ToolchainDir/sysroot\) ./build.sh --cross --arch $__BuildArch \
+ --subsetCategory coreclr
+echo ROOTFS_DIR=\$\(realpath $__ToolchainDir/sysroot\) ./build.sh --cross --arch $__BuildArch \
+ --subsetCategory libraries
+echo ROOTFS_DIR=\$\(realpath $__ToolchainDir/sysroot\) ./build.sh --cross --arch $__BuildArch \
+ --subsetCategory installer
diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh
index d7d5d7d5f44..6d59e181c8f 100755
--- a/eng/common/cross/build-rootfs.sh
+++ b/eng/common/cross/build-rootfs.sh
@@ -1,19 +1,26 @@
#!/usr/bin/env bash
+set -e
+
usage()
{
- echo "Usage: $0 [BuildArch] [LinuxCodeName] [lldbx.y] [--skipunmount] --rootfsdir ]"
+ echo "Usage: $0 [BuildArch] [CodeName] [lldbx.y] [--skipunmount] --rootfsdir ]"
echo "BuildArch can be: arm(default), armel, arm64, x86"
- echo "LinuxCodeName - optional, Code name for Linux, can be: trusty, xenial(default), zesty, bionic, alpine. If BuildArch is armel, LinuxCodeName is jessie(default) or tizen."
- echo "lldbx.y - optional, LLDB version, can be: lldb3.9(default), lldb4.0, lldb5.0, lldb6.0 no-lldb. Ignored for alpine"
+ echo "CodeName - optional, Code name for Linux, can be: trusty, xenial(default), zesty, bionic, alpine. If BuildArch is armel, LinuxCodeName is jessie(default) or tizen."
+ echo " for FreeBSD can be: freebsd11 or freebsd12."
+ echo " for illumos can be: illumos."
+ echo "lldbx.y - optional, LLDB version, can be: lldb3.9(default), lldb4.0, lldb5.0, lldb6.0 no-lldb. Ignored for alpine and FReeBSD"
echo "--skipunmount - optional, will skip the unmount of rootfs folder."
+ echo "--use-mirror - optional, use mirror URL to fetch resources, when available."
exit 1
}
-__LinuxCodeName=xenial
+__CodeName=xenial
__CrossDir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
__InitialDir=$PWD
__BuildArch=arm
+__AlpineArch=armv7
+__QEMUArch=arm
__UbuntuArch=armhf
__UbuntuRepo="http://ports.ubuntu.com/"
__LLDB_Package="liblldb-3.9-dev"
@@ -25,8 +32,10 @@ __UbuntuPackages="build-essential"
__AlpinePackages="alpine-base"
__AlpinePackages+=" build-base"
__AlpinePackages+=" linux-headers"
-__AlpinePackages+=" lldb-dev"
-__AlpinePackages+=" llvm-dev"
+__AlpinePackagesEdgeCommunity=" lldb-dev"
+__AlpinePackagesEdgeMain=" llvm10-libs"
+__AlpinePackagesEdgeMain+=" python3"
+__AlpinePackagesEdgeMain+=" libedit"
# symlinks fixer
__UbuntuPackages+=" symlinks"
@@ -52,6 +61,21 @@ __AlpinePackages+=" krb5-dev"
__AlpinePackages+=" openssl-dev"
__AlpinePackages+=" zlib-dev"
+__FreeBSDBase="12.1-RELEASE"
+__FreeBSDPkg="1.12.0"
+__FreeBSDPackages="libunwind"
+__FreeBSDPackages+=" icu"
+__FreeBSDPackages+=" libinotify"
+__FreeBSDPackages+=" lttng-ust"
+__FreeBSDPackages+=" krb5"
+
+__IllumosPackages="icu-64.2nb2"
+__IllumosPackages+=" mit-krb5-1.16.2nb4"
+__IllumosPackages+=" openssl-1.1.1e"
+__IllumosPackages+=" zlib-1.2.11"
+
+__UseMirror=0
+
__UnprocessedBuildArgs=
while :; do
if [ $# -le 0 ]; then
@@ -67,7 +91,7 @@ while :; do
arm)
__BuildArch=arm
__UbuntuArch=armhf
- __AlpineArch=armhf
+ __AlpineArch=armv7
__QEMUArch=arm
;;
arm64)
@@ -80,7 +104,14 @@ while :; do
__BuildArch=armel
__UbuntuArch=armel
__UbuntuRepo="http://ftp.debian.org/debian/"
- __LinuxCodeName=jessie
+ __CodeName=jessie
+ ;;
+ s390x)
+ __BuildArch=s390x
+ __UbuntuArch=s390x
+ __UbuntuRepo="http://ports.ubuntu.com/ubuntu-ports/"
+ __UbuntuPackages=$(echo ${__UbuntuPackages} | sed 's/ libunwind8-dev//')
+ unset __LLDB_Package
;;
x86)
__BuildArch=x86
@@ -109,53 +140,66 @@ while :; do
unset __LLDB_Package
;;
trusty) # Ubuntu 14.04
- if [ "$__LinuxCodeName" != "jessie" ]; then
- __LinuxCodeName=trusty
+ if [ "$__CodeName" != "jessie" ]; then
+ __CodeName=trusty
fi
;;
xenial) # Ubuntu 16.04
- if [ "$__LinuxCodeName" != "jessie" ]; then
- __LinuxCodeName=xenial
+ if [ "$__CodeName" != "jessie" ]; then
+ __CodeName=xenial
fi
;;
zesty) # Ubuntu 17.04
- if [ "$__LinuxCodeName" != "jessie" ]; then
- __LinuxCodeName=zesty
+ if [ "$__CodeName" != "jessie" ]; then
+ __CodeName=zesty
fi
;;
bionic) # Ubuntu 18.04
- if [ "$__LinuxCodeName" != "jessie" ]; then
- __LinuxCodeName=bionic
+ if [ "$__CodeName" != "jessie" ]; then
+ __CodeName=bionic
fi
;;
jessie) # Debian 8
- __LinuxCodeName=jessie
+ __CodeName=jessie
__UbuntuRepo="http://ftp.debian.org/debian/"
;;
stretch) # Debian 9
- __LinuxCodeName=stretch
+ __CodeName=stretch
__UbuntuRepo="http://ftp.debian.org/debian/"
__LLDB_Package="liblldb-6.0-dev"
;;
buster) # Debian 10
- __LinuxCodeName=buster
+ __CodeName=buster
__UbuntuRepo="http://ftp.debian.org/debian/"
__LLDB_Package="liblldb-6.0-dev"
;;
tizen)
- if [ "$__BuildArch" != "armel" ]; then
- echo "Tizen is available only for armel."
+ if [ "$__BuildArch" != "armel" ] && [ "$__BuildArch" != "arm64" ]; then
+ echo "Tizen is available only for armel and arm64."
usage;
exit 1;
fi
- __LinuxCodeName=
+ __CodeName=
__UbuntuRepo=
__Tizen=tizen
;;
alpine)
- __LinuxCodeName=alpine
+ __CodeName=alpine
__UbuntuRepo=
;;
+ freebsd11)
+ __FreeBSDBase="11.3-RELEASE"
+ ;&
+ freebsd12)
+ __CodeName=freebsd
+ __BuildArch=x64
+ __SkipUnmount=1
+ ;;
+ illumos)
+ __CodeName=illumos
+ __BuildArch=x64
+ __SkipUnmount=1
+ ;;
--skipunmount)
__SkipUnmount=1
;;
@@ -163,6 +207,9 @@ while :; do
shift
__RootfsDir=$1
;;
+ --use-mirror)
+ __UseMirror=1
+ ;;
*)
__UnprocessedBuildArgs="$__UnprocessedBuildArgs $1"
;;
@@ -186,46 +233,128 @@ fi
if [ -d "$__RootfsDir" ]; then
if [ $__SkipUnmount == 0 ]; then
- umount $__RootfsDir/*
+ umount $__RootfsDir/* || true
fi
rm -rf $__RootfsDir
fi
-if [[ "$__LinuxCodeName" == "alpine" ]]; then
+mkdir -p $__RootfsDir
+__RootfsDir="$( cd "$__RootfsDir" && pwd )"
+
+if [[ "$__CodeName" == "alpine" ]]; then
__ApkToolsVersion=2.9.1
- __AlpineVersion=3.7
+ __AlpineVersion=3.9
__ApkToolsDir=$(mktemp -d)
wget https://github.com/alpinelinux/apk-tools/releases/download/v$__ApkToolsVersion/apk-tools-$__ApkToolsVersion-x86_64-linux.tar.gz -P $__ApkToolsDir
tar -xf $__ApkToolsDir/apk-tools-$__ApkToolsVersion-x86_64-linux.tar.gz -C $__ApkToolsDir
mkdir -p $__RootfsDir/usr/bin
cp -v /usr/bin/qemu-$__QEMUArch-static $__RootfsDir/usr/bin
+
$__ApkToolsDir/apk-tools-$__ApkToolsVersion/apk \
-X http://dl-cdn.alpinelinux.org/alpine/v$__AlpineVersion/main \
-X http://dl-cdn.alpinelinux.org/alpine/v$__AlpineVersion/community \
- -X http://dl-cdn.alpinelinux.org/alpine/edge/testing \
- -X http://dl-cdn.alpinelinux.org/alpine/edge/main \
-U --allow-untrusted --root $__RootfsDir --arch $__AlpineArch --initdb \
add $__AlpinePackages
+
+ $__ApkToolsDir/apk-tools-$__ApkToolsVersion/apk \
+ -X http://dl-cdn.alpinelinux.org/alpine/edge/main \
+ -U --allow-untrusted --root $__RootfsDir --arch $__AlpineArch --initdb \
+ add $__AlpinePackagesEdgeMain
+
+ $__ApkToolsDir/apk-tools-$__ApkToolsVersion/apk \
+ -X http://dl-cdn.alpinelinux.org/alpine/edge/community \
+ -U --allow-untrusted --root $__RootfsDir --arch $__AlpineArch --initdb \
+ add $__AlpinePackagesEdgeCommunity
+
rm -r $__ApkToolsDir
-elif [[ -n $__LinuxCodeName ]]; then
- qemu-debootstrap --arch $__UbuntuArch $__LinuxCodeName $__RootfsDir $__UbuntuRepo
- cp $__CrossDir/$__BuildArch/sources.list.$__LinuxCodeName $__RootfsDir/etc/apt/sources.list
+elif [[ "$__CodeName" == "freebsd" ]]; then
+ mkdir -p $__RootfsDir/usr/local/etc
+ wget -O - https://download.freebsd.org/ftp/releases/amd64/${__FreeBSDBase}/base.txz | tar -C $__RootfsDir -Jxf - ./lib ./usr/lib ./usr/libdata ./usr/include ./usr/share/keys ./etc ./bin/freebsd-version
+ # For now, ask for 11 ABI even on 12. This can be revisited later.
+ echo "ABI = \"FreeBSD:11:amd64\"; FINGERPRINTS = \"${__RootfsDir}/usr/share/keys\"; REPOS_DIR = [\"${__RootfsDir}/etc/pkg\"]; REPO_AUTOUPDATE = NO; RUN_SCRIPTS = NO;" > ${__RootfsDir}/usr/local/etc/pkg.conf
+ echo "FreeBSD: { url: "pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly", mirror_type: \"srv\", signature_type: \"fingerprints\", fingerprints: \"${__RootfsDir}/usr/share/keys/pkg\", enabled: yes }" > ${__RootfsDir}/etc/pkg/FreeBSD.conf
+ mkdir -p $__RootfsDir/tmp
+ # get and build package manager
+ wget -O - https://github.com/freebsd/pkg/archive/${__FreeBSDPkg}.tar.gz | tar -C $__RootfsDir/tmp -zxf -
+ cd $__RootfsDir/tmp/pkg-${__FreeBSDPkg}
+ # needed for install to succeed
+ mkdir -p $__RootfsDir/host/etc
+ ./autogen.sh && ./configure --prefix=$__RootfsDir/host && make && make install
+ rm -rf $__RootfsDir/tmp/pkg-${__FreeBSDPkg}
+ # install packages we need.
+ INSTALL_AS_USER=$(whoami) $__RootfsDir/host/sbin/pkg -r $__RootfsDir -C $__RootfsDir/usr/local/etc/pkg.conf update
+ INSTALL_AS_USER=$(whoami) $__RootfsDir/host/sbin/pkg -r $__RootfsDir -C $__RootfsDir/usr/local/etc/pkg.conf install --yes $__FreeBSDPackages
+elif [[ "$__CodeName" == "illumos" ]]; then
+ mkdir "$__RootfsDir/tmp"
+ pushd "$__RootfsDir/tmp"
+ JOBS="$(getconf _NPROCESSORS_ONLN)"
+ echo "Downloading sysroot."
+ wget -O - https://github.com/illumos/sysroot/releases/download/20181213-de6af22ae73b-v1/illumos-sysroot-i386-20181213-de6af22ae73b-v1.tar.gz | tar -C "$__RootfsDir" -xzf -
+ echo "Building binutils. Please wait.."
+ wget -O - https://ftp.gnu.org/gnu/binutils/binutils-2.33.1.tar.bz2 | tar -xjf -
+ mkdir build-binutils && cd build-binutils
+ ../binutils-2.33.1/configure --prefix="$__RootfsDir" --target="x86_64-sun-solaris2.10" --program-prefix="x86_64-illumos-" --with-sysroot="$__RootfsDir"
+ make -j "$JOBS" && make install && cd ..
+ echo "Building gcc. Please wait.."
+ wget -O - https://ftp.gnu.org/gnu/gcc/gcc-8.4.0/gcc-8.4.0.tar.xz | tar -xJf -
+ CFLAGS="-fPIC"
+ CXXFLAGS="-fPIC"
+ CXXFLAGS_FOR_TARGET="-fPIC"
+ CFLAGS_FOR_TARGET="-fPIC"
+ export CFLAGS CXXFLAGS CXXFLAGS_FOR_TARGET CFLAGS_FOR_TARGET
+ mkdir build-gcc && cd build-gcc
+ ../gcc-8.4.0/configure --prefix="$__RootfsDir" --target="x86_64-sun-solaris2.10" --program-prefix="x86_64-illumos-" --with-sysroot="$__RootfsDir" --with-gnu-as \
+ --with-gnu-ld --disable-nls --disable-libgomp --disable-libquadmath --disable-libssp --disable-libvtv --disable-libcilkrts --disable-libada --disable-libsanitizer \
+ --disable-libquadmath-support --disable-shared --enable-tls
+ make -j "$JOBS" && make install && cd ..
+ BaseUrl=https://pkgsrc.joyent.com
+ if [[ "$__UseMirror" == 1 ]]; then
+ BaseUrl=http://pkgsrc.smartos.skylime.net
+ fi
+ BaseUrl="$BaseUrl"/packages/SmartOS/2020Q1/x86_64/All
+ echo "Downloading dependencies."
+ read -ra array <<<"$__IllumosPackages"
+ for package in "${array[@]}"; do
+ echo "Installing $package..."
+ wget "$BaseUrl"/"$package".tgz
+ ar -x "$package".tgz
+ tar --skip-old-files -xzf "$package".tmp.tgz -C "$__RootfsDir" 2>/dev/null
+ done
+ echo "Cleaning up temporary files."
+ popd
+ rm -rf "$__RootfsDir"/{tmp,+*}
+ mkdir -p "$__RootfsDir"/usr/include/net
+ mkdir -p "$__RootfsDir"/usr/include/netpacket
+ wget -P "$__RootfsDir"/usr/include/net https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/io/bpf/net/bpf.h
+ wget -P "$__RootfsDir"/usr/include/net https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/io/bpf/net/dlt.h
+ wget -P "$__RootfsDir"/usr/include/netpacket https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/inet/sockmods/netpacket/packet.h
+ wget -P "$__RootfsDir"/usr/include/sys https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/sys/sdt.h
+elif [[ -n $__CodeName ]]; then
+ qemu-debootstrap --arch $__UbuntuArch $__CodeName $__RootfsDir $__UbuntuRepo
+ cp $__CrossDir/$__BuildArch/sources.list.$__CodeName $__RootfsDir/etc/apt/sources.list
chroot $__RootfsDir apt-get update
chroot $__RootfsDir apt-get -f -y install
chroot $__RootfsDir apt-get -y install $__UbuntuPackages
chroot $__RootfsDir symlinks -cr /usr
+ chroot $__RootfsDir apt-get clean
if [ $__SkipUnmount == 0 ]; then
- umount $__RootfsDir/*
+ umount $__RootfsDir/* || true
fi
- if [[ "$__BuildArch" == "arm" && "$__LinuxCodeName" == "trusty" ]]; then
+ if [[ "$__BuildArch" == "arm" && "$__CodeName" == "trusty" ]]; then
pushd $__RootfsDir
patch -p1 < $__CrossDir/$__BuildArch/trusty.patch
patch -p1 < $__CrossDir/$__BuildArch/trusty-lttng-2.4.patch
popd
fi
-elif [ "$__Tizen" == "tizen" ]; then
+
+ if [[ "$__BuildArch" == "armel" && "$__CodeName" == "jessie" ]]; then
+ pushd $__RootfsDir
+ patch -p1 < $__CrossDir/$__BuildArch/armel.jessie.patch
+ popd
+ fi
+elif [[ "$__Tizen" == "tizen" ]]; then
ROOTFS_DIR=$__RootfsDir $__CrossDir/$__BuildArch/tizen-build-rootfs.sh
else
echo "Unsupported target platform."
diff --git a/eng/common/cross/s390x/sources.list.bionic b/eng/common/cross/s390x/sources.list.bionic
new file mode 100644
index 00000000000..21095574095
--- /dev/null
+++ b/eng/common/cross/s390x/sources.list.bionic
@@ -0,0 +1,11 @@
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
+
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse
diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake
index 071d4112419..fc11001aa76 100644
--- a/eng/common/cross/toolchain.cmake
+++ b/eng/common/cross/toolchain.cmake
@@ -1,18 +1,27 @@
set(CROSS_ROOTFS $ENV{ROOTFS_DIR})
set(TARGET_ARCH_NAME $ENV{TARGET_BUILD_ARCH})
-set(CMAKE_SYSTEM_NAME Linux)
+if(EXISTS ${CROSS_ROOTFS}/bin/freebsd-version)
+ set(CMAKE_SYSTEM_NAME FreeBSD)
+elseif(EXISTS ${CROSS_ROOTFS}/usr/platform/i86pc)
+ set(CMAKE_SYSTEM_NAME SunOS)
+ set(ILLUMOS 1)
+else()
+ set(CMAKE_SYSTEM_NAME Linux)
+endif()
set(CMAKE_SYSTEM_VERSION 1)
if(TARGET_ARCH_NAME STREQUAL "armel")
set(CMAKE_SYSTEM_PROCESSOR armv7l)
set(TOOLCHAIN "arm-linux-gnueabi")
if("$ENV{__DistroRid}" MATCHES "tizen.*")
- set(TIZEN_TOOLCHAIN "armv7l-tizen-linux-gnueabi/6.2.1")
+ set(TIZEN_TOOLCHAIN "armv7l-tizen-linux-gnueabi/9.2.0")
endif()
elseif(TARGET_ARCH_NAME STREQUAL "arm")
set(CMAKE_SYSTEM_PROCESSOR armv7l)
- if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf)
+ if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv7-alpine-linux-musleabihf)
+ set(TOOLCHAIN "armv7-alpine-linux-musleabihf")
+ elseif(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf)
set(TOOLCHAIN "armv6-alpine-linux-musleabihf")
else()
set(TOOLCHAIN "arm-linux-gnueabihf")
@@ -24,65 +33,148 @@ elseif(TARGET_ARCH_NAME STREQUAL "arm64")
else()
set(TOOLCHAIN "aarch64-linux-gnu")
endif()
+ if("$ENV{__DistroRid}" MATCHES "tizen.*")
+ set(TIZEN_TOOLCHAIN "aarch64-tizen-linux-gnu/9.2.0")
+ endif()
+elseif(TARGET_ARCH_NAME STREQUAL "s390x")
+ set(CMAKE_SYSTEM_PROCESSOR s390x)
+ set(TOOLCHAIN "s390x-linux-gnu")
elseif(TARGET_ARCH_NAME STREQUAL "x86")
set(CMAKE_SYSTEM_PROCESSOR i686)
set(TOOLCHAIN "i686-linux-gnu")
+elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+ set(CMAKE_SYSTEM_PROCESSOR "x86_64")
+ set(triple "x86_64-unknown-freebsd11")
+elseif (ILLUMOS)
+ set(CMAKE_SYSTEM_PROCESSOR "x86_64")
+ set(TOOLCHAIN "x86_64-illumos")
else()
- message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, arm64 and x86 are supported!")
+ message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, arm64, s390x and x86 are supported!")
+endif()
+
+if(DEFINED ENV{TOOLCHAIN})
+ set(TOOLCHAIN $ENV{TOOLCHAIN})
endif()
# Specify include paths
-if(TARGET_ARCH_NAME STREQUAL "armel")
- if(DEFINED TIZEN_TOOLCHAIN)
+if(DEFINED TIZEN_TOOLCHAIN)
+ if(TARGET_ARCH_NAME STREQUAL "armel")
include_directories(SYSTEM ${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}/include/c++/)
include_directories(SYSTEM ${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}/include/c++/armv7l-tizen-linux-gnueabi)
endif()
+ if(TARGET_ARCH_NAME STREQUAL "arm64")
+ include_directories(SYSTEM ${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}/include/c++/)
+ include_directories(SYSTEM ${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}/include/c++/aarch64-tizen-linux-gnu)
+ endif()
endif()
-# add_compile_param - adds only new options without duplicates.
-# arg0 - list with result options, arg1 - list with new options.
-# arg2 - optional argument, quick summary string for optional using CACHE FORCE mode.
-macro(add_compile_param)
- if(NOT ${ARGC} MATCHES "^(2|3)$")
- message(FATAL_ERROR "Wrong using add_compile_param! Two or three parameters must be given! See add_compile_param description.")
- endif()
- foreach(OPTION ${ARGV1})
- if(NOT ${ARGV0} MATCHES "${OPTION}($| )")
- set(${ARGV0} "${${ARGV0}} ${OPTION}")
- if(${ARGC} EQUAL "3") # CACHE FORCE mode
- set(${ARGV0} "${${ARGV0}}" CACHE STRING "${ARGV2}" FORCE)
- endif()
+if("$ENV{__DistroRid}" MATCHES "android.*")
+ if(TARGET_ARCH_NAME STREQUAL "arm")
+ set(ANDROID_ABI armeabi-v7a)
+ elseif(TARGET_ARCH_NAME STREQUAL "arm64")
+ set(ANDROID_ABI arm64-v8a)
endif()
- endforeach()
-endmacro()
+
+ # extract platform number required by the NDK's toolchain
+ string(REGEX REPLACE ".*\\.([0-9]+)-.*" "\\1" ANDROID_PLATFORM "$ENV{__DistroRid}")
+
+ set(ANDROID_TOOLCHAIN clang)
+ set(FEATURE_EVENT_TRACE 0) # disable event trace as there is no lttng-ust package in termux repository
+ set(CMAKE_SYSTEM_LIBRARY_PATH "${CROSS_ROOTFS}/usr/lib")
+ set(CMAKE_SYSTEM_INCLUDE_PATH "${CROSS_ROOTFS}/usr/include")
+
+ # include official NDK toolchain script
+ include(${CROSS_ROOTFS}/../build/cmake/android.toolchain.cmake)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+ # we cross-compile by instructing clang
+ set(CMAKE_C_COMPILER_TARGET ${triple})
+ set(CMAKE_CXX_COMPILER_TARGET ${triple})
+ set(CMAKE_ASM_COMPILER_TARGET ${triple})
+ set(CMAKE_SYSROOT "${CROSS_ROOTFS}")
+elseif(ILLUMOS)
+ set(CMAKE_SYSROOT "${CROSS_ROOTFS}")
+
+ include_directories(SYSTEM ${CROSS_ROOTFS}/include)
+
+ set(TOOLSET_PREFIX ${TOOLCHAIN}-)
+ function(locate_toolchain_exec exec var)
+ string(TOUPPER ${exec} EXEC_UPPERCASE)
+ if(NOT "$ENV{CLR_${EXEC_UPPERCASE}}" STREQUAL "")
+ set(${var} "$ENV{CLR_${EXEC_UPPERCASE}}" PARENT_SCOPE)
+ return()
+ endif()
+
+ find_program(EXEC_LOCATION_${exec}
+ NAMES
+ "${TOOLSET_PREFIX}${exec}${CLR_CMAKE_COMPILER_FILE_NAME_VERSION}"
+ "${TOOLSET_PREFIX}${exec}")
+
+ if (EXEC_LOCATION_${exec} STREQUAL "EXEC_LOCATION_${exec}-NOTFOUND")
+ message(FATAL_ERROR "Unable to find toolchain executable. Name: ${exec}, Prefix: ${TOOLSET_PREFIX}.")
+ endif()
+ set(${var} ${EXEC_LOCATION_${exec}} PARENT_SCOPE)
+ endfunction()
+
+ set(CMAKE_SYSTEM_PREFIX_PATH "${CROSS_ROOTFS}")
+
+ locate_toolchain_exec(gcc CMAKE_C_COMPILER)
+ locate_toolchain_exec(g++ CMAKE_CXX_COMPILER)
+
+ set(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} -lssp")
+ set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -lssp")
+else()
+ set(CMAKE_SYSROOT "${CROSS_ROOTFS}")
+
+ set(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN "${CROSS_ROOTFS}/usr")
+ set(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN "${CROSS_ROOTFS}/usr")
+ set(CMAKE_ASM_COMPILER_EXTERNAL_TOOLCHAIN "${CROSS_ROOTFS}/usr")
+endif()
# Specify link flags
-add_compile_param(CROSS_LINK_FLAGS "--sysroot=${CROSS_ROOTFS}")
-add_compile_param(CROSS_LINK_FLAGS "--gcc-toolchain=${CROSS_ROOTFS}/usr")
-add_compile_param(CROSS_LINK_FLAGS "--target=${TOOLCHAIN}")
-add_compile_param(CROSS_LINK_FLAGS "-fuse-ld=gold")
+
+function(add_toolchain_linker_flag Flag)
+ set(Config "${ARGV1}")
+ set(CONFIG_SUFFIX "")
+ if (NOT Config STREQUAL "")
+ set(CONFIG_SUFFIX "_${Config}")
+ endif()
+ set("CMAKE_EXE_LINKER_FLAGS${CONFIG_SUFFIX}" "${CMAKE_EXE_LINKER_FLAGS${CONFIG_SUFFIX}} ${Flag}" PARENT_SCOPE)
+ set("CMAKE_SHARED_LINKER_FLAGS${CONFIG_SUFFIX}" "${CMAKE_SHARED_LINKER_FLAGS${CONFIG_SUFFIX}} ${Flag}" PARENT_SCOPE)
+endfunction()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/lib/${TOOLCHAIN}")
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib/${TOOLCHAIN}")
+endif()
if(TARGET_ARCH_NAME STREQUAL "armel")
if(DEFINED TIZEN_TOOLCHAIN) # For Tizen only
- add_compile_param(CROSS_LINK_FLAGS "-B${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}")
- add_compile_param(CROSS_LINK_FLAGS "-L${CROSS_ROOTFS}/lib")
- add_compile_param(CROSS_LINK_FLAGS "-L${CROSS_ROOTFS}/usr/lib")
- add_compile_param(CROSS_LINK_FLAGS "-L${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}")
+ add_toolchain_linker_flag("-B${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}")
+ endif()
+elseif(TARGET_ARCH_NAME STREQUAL "arm64")
+ if(DEFINED TIZEN_TOOLCHAIN) # For Tizen only
+ add_toolchain_linker_flag("-B${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib64")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib64")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}")
+
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/lib64")
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64")
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}")
endif()
elseif(TARGET_ARCH_NAME STREQUAL "x86")
- add_compile_param(CROSS_LINK_FLAGS "-m32")
+ add_toolchain_linker_flag(-m32)
+elseif(ILLUMOS)
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib/amd64")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/amd64/lib")
endif()
-add_compile_param(CMAKE_EXE_LINKER_FLAGS "${CROSS_LINK_FLAGS}" "TOOLCHAIN_EXE_LINKER_FLAGS")
-add_compile_param(CMAKE_SHARED_LINKER_FLAGS "${CROSS_LINK_FLAGS}" "TOOLCHAIN_EXE_LINKER_FLAGS")
-add_compile_param(CMAKE_MODULE_LINKER_FLAGS "${CROSS_LINK_FLAGS}" "TOOLCHAIN_EXE_LINKER_FLAGS")
-
# Specify compile options
-add_compile_options("--sysroot=${CROSS_ROOTFS}")
-add_compile_options("--target=${TOOLCHAIN}")
-add_compile_options("--gcc-toolchain=${CROSS_ROOTFS}/usr")
-if(TARGET_ARCH_NAME MATCHES "^(arm|armel|arm64)$")
+if((TARGET_ARCH_NAME MATCHES "^(arm|armel|arm64|s390x)$" AND NOT "$ENV{__DistroRid}" MATCHES "android.*") OR ILLUMOS)
set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN})
set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN})
set(CMAKE_ASM_COMPILER_TARGET ${TOOLCHAIN})
@@ -90,20 +182,33 @@ endif()
if(TARGET_ARCH_NAME MATCHES "^(arm|armel)$")
add_compile_options(-mthumb)
- add_compile_options(-mfpu=vfpv3)
+ if (NOT DEFINED CLR_ARM_FPU_TYPE)
+ set (CLR_ARM_FPU_TYPE vfpv3)
+ endif (NOT DEFINED CLR_ARM_FPU_TYPE)
+
+ add_compile_options (-mfpu=${CLR_ARM_FPU_TYPE})
+ if (NOT DEFINED CLR_ARM_FPU_CAPABILITY)
+ set (CLR_ARM_FPU_CAPABILITY 0x7)
+ endif (NOT DEFINED CLR_ARM_FPU_CAPABILITY)
+
+ add_definitions (-DCLR_ARM_FPU_CAPABILITY=${CLR_ARM_FPU_CAPABILITY})
+
if(TARGET_ARCH_NAME STREQUAL "armel")
add_compile_options(-mfloat-abi=softfp)
- if(DEFINED TIZEN_TOOLCHAIN)
- add_compile_options(-Wno-deprecated-declarations) # compile-time option
- add_compile_options(-D__extern_always_inline=inline) # compile-time option
- endif()
endif()
elseif(TARGET_ARCH_NAME STREQUAL "x86")
add_compile_options(-m32)
add_compile_options(-Wno-error=unused-command-line-argument)
endif()
-# Set LLDB include and library paths
+if(DEFINED TIZEN_TOOLCHAIN)
+ if(TARGET_ARCH_NAME MATCHES "^(armel|arm64)$")
+ add_compile_options(-Wno-deprecated-declarations) # compile-time option
+ add_compile_options(-D__extern_always_inline=inline) # compile-time option
+ endif()
+endif()
+
+# Set LLDB include and library paths for builds that need lldb.
if(TARGET_ARCH_NAME MATCHES "^(arm|armel|x86)$")
if(TARGET_ARCH_NAME STREQUAL "x86")
set(LLVM_CROSS_DIR "$ENV{LLVM_CROSS_HOME}")
@@ -131,7 +236,6 @@ if(TARGET_ARCH_NAME MATCHES "^(arm|armel|x86)$")
endif()
endif()
-set(CMAKE_FIND_ROOT_PATH "${CROSS_ROOTFS}")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/eng/common/darc-init.ps1 b/eng/common/darc-init.ps1
index 8854d979f37..435e7641341 100644
--- a/eng/common/darc-init.ps1
+++ b/eng/common/darc-init.ps1
@@ -1,13 +1,14 @@
param (
$darcVersion = $null,
- $versionEndpoint = "https://maestro-prod.westus2.cloudapp.azure.com/api/assets/darc-version?api-version=2019-01-16"
+ $versionEndpoint = 'https://maestro-prod.westus2.cloudapp.azure.com/api/assets/darc-version?api-version=2019-01-16',
+ $verbosity = 'minimal',
+ $toolpath = $null
)
-$verbosity = "m"
. $PSScriptRoot\tools.ps1
-function InstallDarcCli ($darcVersion) {
- $darcCliPackageName = "microsoft.dotnet.darc"
+function InstallDarcCli ($darcVersion, $toolpath) {
+ $darcCliPackageName = 'microsoft.dotnet.darc'
$dotnetRoot = InitializeDotNetCli -install:$true
$dotnet = "$dotnetRoot\dotnet.exe"
@@ -23,11 +24,24 @@ function InstallDarcCli ($darcVersion) {
$darcVersion = $(Invoke-WebRequest -Uri $versionEndpoint -UseBasicParsing).Content
}
- $arcadeServicesSource = 'https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json'
+ $arcadeServicesSource = 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
Write-Host "Installing Darc CLI version $darcVersion..."
- Write-Host "You may need to restart your command window if this is the first dotnet tool you have installed."
- & "$dotnet" tool install $darcCliPackageName --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity -g
+ Write-Host 'You may need to restart your command window if this is the first dotnet tool you have installed.'
+ if (-not $toolpath) {
+ Write-Host "'$dotnet' tool install $darcCliPackageName --version $darcVersion --add-source '$arcadeServicesSource' -v $verbosity -g"
+ & "$dotnet" tool install $darcCliPackageName --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity -g
+ }else {
+ Write-Host "'$dotnet' tool install $darcCliPackageName --version $darcVersion --add-source '$arcadeServicesSource' -v $verbosity --tool-path '$toolpath'"
+ & "$dotnet" tool install $darcCliPackageName --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity --tool-path "$toolpath"
+ }
}
-InstallDarcCli $darcVersion
+try {
+ InstallDarcCli $darcVersion $toolpath
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'Darc' -Message $_
+ ExitWithExitCode 1
+}
\ No newline at end of file
diff --git a/eng/common/darc-init.sh b/eng/common/darc-init.sh
index abdd0bc05a1..d981d7bbf38 100755
--- a/eng/common/darc-init.sh
+++ b/eng/common/darc-init.sh
@@ -2,7 +2,8 @@
source="${BASH_SOURCE[0]}"
darcVersion=''
-versionEndpoint="https://maestro-prod.westus2.cloudapp.azure.com/api/assets/darc-version?api-version=2019-01-16"
+versionEndpoint='https://maestro-prod.westus2.cloudapp.azure.com/api/assets/darc-version?api-version=2019-01-16'
+verbosity='minimal'
while [[ $# > 0 ]]; do
opt="$(echo "$1" | awk '{print tolower($0)}')"
@@ -15,6 +16,14 @@ while [[ $# > 0 ]]; do
versionEndpoint=$2
shift
;;
+ --verbosity)
+ verbosity=$2
+ shift
+ ;;
+ --toolpath)
+ toolpath=$2
+ shift
+ ;;
*)
echo "Invalid argument: $1"
usage
@@ -34,7 +43,6 @@ while [[ -h "$source" ]]; do
[[ $source != /* ]] && source="$scriptroot/$source"
done
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
-verbosity=m
. "$scriptroot/tools.sh"
@@ -48,17 +56,27 @@ function InstallDarcCli {
InitializeDotNetCli
local dotnet_root=$_InitializeDotNetCli
- local uninstall_command=`$dotnet_root/dotnet tool uninstall $darc_cli_package_name -g`
- local tool_list=$($dotnet_root/dotnet tool list -g)
- if [[ $tool_list = *$darc_cli_package_name* ]]; then
- echo $($dotnet_root/dotnet tool uninstall $darc_cli_package_name -g)
+ if [ -z "$toolpath" ]; then
+ local tool_list=$($dotnet_root/dotnet tool list -g)
+ if [[ $tool_list = *$darc_cli_package_name* ]]; then
+ echo $($dotnet_root/dotnet tool uninstall $darc_cli_package_name -g)
+ fi
+ else
+ local tool_list=$($dotnet_root/dotnet tool list --tool-path "$toolpath")
+ if [[ $tool_list = *$darc_cli_package_name* ]]; then
+ echo $($dotnet_root/dotnet tool uninstall $darc_cli_package_name --tool-path "$toolpath")
+ fi
fi
- local arcadeServicesSource="https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json"
+ local arcadeServicesSource="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json"
echo "Installing Darc CLI version $darcVersion..."
echo "You may need to restart your command shell if this is the first dotnet tool you have installed."
- echo $($dotnet_root/dotnet tool install $darc_cli_package_name --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity -g)
+ if [ -z "$toolpath" ]; then
+ echo $($dotnet_root/dotnet tool install $darc_cli_package_name --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity -g)
+ else
+ echo $($dotnet_root/dotnet tool install $darc_cli_package_name --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity --tool-path "$toolpath")
+ fi
}
InstallDarcCli
diff --git a/eng/common/dotnet-install.ps1 b/eng/common/dotnet-install.ps1
index 0b629b8301a..811f0f717f7 100644
--- a/eng/common/dotnet-install.ps1
+++ b/eng/common/dotnet-install.ps1
@@ -1,26 +1,27 @@
[CmdletBinding(PositionalBinding=$false)]
Param(
- [string] $verbosity = "minimal",
- [string] $architecture = "",
- [string] $version = "Latest",
- [string] $runtime = "dotnet"
+ [string] $verbosity = 'minimal',
+ [string] $architecture = '',
+ [string] $version = 'Latest',
+ [string] $runtime = 'dotnet',
+ [string] $RuntimeSourceFeed = '',
+ [string] $RuntimeSourceFeedKey = ''
)
. $PSScriptRoot\tools.ps1
-$dotnetRoot = Join-Path $RepoRoot ".dotnet"
+$dotnetRoot = Join-Path $RepoRoot '.dotnet'
$installdir = $dotnetRoot
try {
- if ($architecture -and $architecture.Trim() -eq "x86") {
- $installdir = Join-Path $installdir "x86"
+ if ($architecture -and $architecture.Trim() -eq 'x86') {
+ $installdir = Join-Path $installdir 'x86'
}
- InstallDotNet $installdir $version $architecture $runtime $true
-}
+ InstallDotNet $installdir $version $architecture $runtime $true -RuntimeSourceFeed $RuntimeSourceFeed -RuntimeSourceFeedKey $RuntimeSourceFeedKey
+}
catch {
- Write-Host $_
- Write-Host $_.Exception
Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_
ExitWithExitCode 1
}
diff --git a/eng/common/dotnet-install.sh b/eng/common/dotnet-install.sh
index c3072c958af..ead6a1d9a24 100755
--- a/eng/common/dotnet-install.sh
+++ b/eng/common/dotnet-install.sh
@@ -11,9 +11,13 @@ while [[ -h "$source" ]]; do
done
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+. "$scriptroot/tools.sh"
+
version='Latest'
architecture=''
runtime='dotnet'
+runtimeSourceFeed=''
+runtimeSourceFeedKey=''
while [[ $# > 0 ]]; do
opt="$(echo "$1" | awk '{print tolower($0)}')"
case "$opt" in
@@ -29,20 +33,56 @@ while [[ $# > 0 ]]; do
shift
runtime="$1"
;;
+ -runtimesourcefeed)
+ shift
+ runtimeSourceFeed="$1"
+ ;;
+ -runtimesourcefeedkey)
+ shift
+ runtimeSourceFeedKey="$1"
+ ;;
*)
- echo "Invalid argument: $1"
- usage
+ Write-PipelineTelemetryError -Category 'Build' -Message "Invalid argument: $1"
exit 1
;;
esac
shift
done
-. "$scriptroot/tools.sh"
+# Use uname to determine what the CPU is.
+cpuname=$(uname -p)
+# Some Linux platforms report unknown for platform, but the arch for machine.
+if [[ "$cpuname" == "unknown" ]]; then
+ cpuname=$(uname -m)
+fi
+
+case $cpuname in
+ aarch64)
+ buildarch=arm64
+ ;;
+ amd64|x86_64)
+ buildarch=x64
+ ;;
+ armv*l)
+ buildarch=arm
+ ;;
+ i686)
+ buildarch=x86
+ ;;
+ *)
+ echo "Unknown CPU $cpuname detected, treating it as x64"
+ buildarch=x64
+ ;;
+esac
+
dotnetRoot="$repo_root/.dotnet"
-InstallDotNet $dotnetRoot $version "$architecture" $runtime true || {
+if [[ $architecture != "" ]] && [[ $architecture != $buildarch ]]; then
+ dotnetRoot="$dotnetRoot/$architecture"
+fi
+
+InstallDotNet $dotnetRoot $version "$architecture" $runtime true $runtimeSourceFeed $runtimeSourceFeedKey || {
local exit_code=$?
- echo "dotnet-install.sh failed (exit code '$exit_code')." >&2
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "dotnet-install.sh failed (exit code '$exit_code')." >&2
ExitWithExitCode $exit_code
}
diff --git a/eng/common/enable-cross-org-publishing.ps1 b/eng/common/enable-cross-org-publishing.ps1
new file mode 100644
index 00000000000..da09da4f1fc
--- /dev/null
+++ b/eng/common/enable-cross-org-publishing.ps1
@@ -0,0 +1,13 @@
+param(
+ [string] $token
+)
+
+
+. $PSScriptRoot\pipeline-logging-functions.ps1
+
+# Write-PipelineSetVariable will no-op if a variable named $ci is not defined
+# Since this script is only ever called in AzDO builds, just universally set it
+$ci = $true
+
+Write-PipelineSetVariable -Name 'VSS_NUGET_ACCESSTOKEN' -Value $token -IsMultiJobVariable $false
+Write-PipelineSetVariable -Name 'VSS_NUGET_URI_PREFIXES' -Value 'https://dnceng.pkgs.visualstudio.com/;https://pkgs.dev.azure.com/dnceng/;https://devdiv.pkgs.visualstudio.com/;https://pkgs.dev.azure.com/devdiv/' -IsMultiJobVariable $false
diff --git a/eng/common/generate-graph-files.ps1 b/eng/common/generate-graph-files.ps1
index b056e4c1ac2..0728b1a8b57 100644
--- a/eng/common/generate-graph-files.ps1
+++ b/eng/common/generate-graph-files.ps1
@@ -3,39 +3,39 @@ Param(
[Parameter(Mandatory=$true)][string] $gitHubPat, # GitHub personal access token from https://github.com/settings/tokens (no auth scopes needed)
[Parameter(Mandatory=$true)][string] $azdoPat, # Azure Dev Ops tokens from https://dev.azure.com/dnceng/_details/security/tokens (code read scope needed)
[Parameter(Mandatory=$true)][string] $outputFolder, # Where the graphviz.txt file will be created
- [string] $darcVersion = '1.1.0-beta.19175.6', # darc's version
+ [string] $darcVersion, # darc's version
[string] $graphvizVersion = '2.38', # GraphViz version
[switch] $includeToolset # Whether the graph should include toolset dependencies or not. i.e. arcade, optimization. For more about
# toolset dependencies see https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md#toolset-vs-product-dependencies
)
-$ErrorActionPreference = "Stop"
-. $PSScriptRoot\tools.ps1
-
-Import-Module -Name (Join-Path $PSScriptRoot "native\CommonLibrary.psm1")
-
function CheckExitCode ([string]$stage)
{
$exitCode = $LASTEXITCODE
if ($exitCode -ne 0) {
- Write-Host "Something failed in stage: '$stage'. Check for errors above. Exiting now..."
+ Write-PipelineTelemetryError -Category 'Arcade' -Message "Something failed in stage: '$stage'. Check for errors above. Exiting now..."
ExitWithExitCode $exitCode
}
}
try {
+ $ErrorActionPreference = 'Stop'
+ . $PSScriptRoot\tools.ps1
+
+ Import-Module -Name (Join-Path $PSScriptRoot 'native\CommonLibrary.psm1')
+
Push-Location $PSScriptRoot
- Write-Host "Installing darc..."
+ Write-Host 'Installing darc...'
. .\darc-init.ps1 -darcVersion $darcVersion
- CheckExitCode "Running darc-init"
+ CheckExitCode 'Running darc-init'
- $engCommonBaseDir = Join-Path $PSScriptRoot "native\"
+ $engCommonBaseDir = Join-Path $PSScriptRoot 'native\'
$graphvizInstallDir = CommonLibrary\Get-NativeInstallDirectory
- $nativeToolBaseUri = "https://netcorenativeassets.blob.core.windows.net/resource-packages/external"
- $installBin = Join-Path $graphvizInstallDir "bin"
+ $nativeToolBaseUri = 'https://netcorenativeassets.blob.core.windows.net/resource-packages/external'
+ $installBin = Join-Path $graphvizInstallDir 'bin'
- Write-Host "Installing dot..."
+ Write-Host 'Installing dot...'
.\native\install-tool.ps1 -ToolName graphviz -InstallPath $installBin -BaseUri $nativeToolBaseUri -CommonLibraryDirectory $engCommonBaseDir -Version $graphvizVersion -Verbose
$darcExe = "$env:USERPROFILE\.dotnet\tools"
@@ -51,37 +51,36 @@ try {
$graphVizImageFilePath = "$outputFolder\graph.png"
$normalGraphFilePath = "$outputFolder\graph-full.txt"
$flatGraphFilePath = "$outputFolder\graph-flat.txt"
- $baseOptions = @( "--github-pat", "$gitHubPat", "--azdev-pat", "$azdoPat", "--password", "$barToken" )
+ $baseOptions = @( '--github-pat', "$gitHubPat", '--azdev-pat', "$azdoPat", '--password', "$barToken" )
if ($includeToolset) {
- Write-Host "Toolsets will be included in the graph..."
- $baseOptions += @( "--include-toolset" )
+ Write-Host 'Toolsets will be included in the graph...'
+ $baseOptions += @( '--include-toolset' )
}
- Write-Host "Generating standard dependency graph..."
+ Write-Host 'Generating standard dependency graph...'
& "$darcExe" get-dependency-graph @baseOptions --output-file $normalGraphFilePath
- CheckExitCode "Generating normal dependency graph"
+ CheckExitCode 'Generating normal dependency graph'
- Write-Host "Generating flat dependency graph and graphviz file..."
+ Write-Host 'Generating flat dependency graph and graphviz file...'
& "$darcExe" get-dependency-graph @baseOptions --flat --coherency --graphviz $graphVizFilePath --output-file $flatGraphFilePath
- CheckExitCode "Generating flat and graphviz dependency graph"
+ CheckExitCode 'Generating flat and graphviz dependency graph'
Write-Host "Generating graph image $graphVizFilePath"
$dotFilePath = Join-Path $installBin "graphviz\$graphvizVersion\release\bin\dot.exe"
& "$dotFilePath" -Tpng -o"$graphVizImageFilePath" "$graphVizFilePath"
- CheckExitCode "Generating graphviz image"
+ CheckExitCode 'Generating graphviz image'
Write-Host "'$graphVizFilePath', '$flatGraphFilePath', '$normalGraphFilePath' and '$graphVizImageFilePath' created!"
}
catch {
if (!$includeToolset) {
- Write-Host "This might be a toolset repo which includes only toolset dependencies. " -NoNewline -ForegroundColor Yellow
- Write-Host "Since -includeToolset is not set there is no graph to create. Include -includeToolset and try again..." -ForegroundColor Yellow
+ Write-Host 'This might be a toolset repo which includes only toolset dependencies. ' -NoNewline -ForegroundColor Yellow
+ Write-Host 'Since -includeToolset is not set there is no graph to create. Include -includeToolset and try again...' -ForegroundColor Yellow
}
- Write-Host $_
- Write-Host $_.Exception
Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'Arcade' -Message $_
ExitWithExitCode 1
} finally {
- Pop-Location
+ Pop-Location
}
\ No newline at end of file
diff --git a/eng/common/init-tools-native.ps1 b/eng/common/init-tools-native.ps1
index 8cf18bcfeba..db830c00a6f 100644
--- a/eng/common/init-tools-native.ps1
+++ b/eng/common/init-tools-native.ps1
@@ -35,7 +35,7 @@ File path to global.json file
#>
[CmdletBinding(PositionalBinding=$false)]
Param (
- [string] $BaseUri = "https://netcorenativeassets.blob.core.windows.net/resource-packages/external",
+ [string] $BaseUri = 'https://netcorenativeassets.blob.core.windows.net/resource-packages/external',
[string] $InstallDirectory,
[switch] $Clean = $False,
[switch] $Force = $False,
@@ -45,26 +45,27 @@ Param (
)
if (!$GlobalJsonFile) {
- $GlobalJsonFile = Join-Path (Get-Item $PSScriptRoot).Parent.Parent.FullName "global.json"
+ $GlobalJsonFile = Join-Path (Get-Item $PSScriptRoot).Parent.Parent.FullName 'global.json'
}
Set-StrictMode -version 2.0
-$ErrorActionPreference="Stop"
+$ErrorActionPreference='Stop'
-Import-Module -Name (Join-Path $PSScriptRoot "native\CommonLibrary.psm1")
+. $PSScriptRoot\pipeline-logging-functions.ps1
+Import-Module -Name (Join-Path $PSScriptRoot 'native\CommonLibrary.psm1')
try {
# Define verbose switch if undefined
- $Verbose = $VerbosePreference -Eq "Continue"
+ $Verbose = $VerbosePreference -Eq 'Continue'
- $EngCommonBaseDir = Join-Path $PSScriptRoot "native\"
+ $EngCommonBaseDir = Join-Path $PSScriptRoot 'native\'
$NativeBaseDir = $InstallDirectory
if (!$NativeBaseDir) {
$NativeBaseDir = CommonLibrary\Get-NativeInstallDirectory
}
$Env:CommonLibrary_NativeInstallDir = $NativeBaseDir
- $InstallBin = Join-Path $NativeBaseDir "bin"
- $InstallerPath = Join-Path $EngCommonBaseDir "install-tool.ps1"
+ $InstallBin = Join-Path $NativeBaseDir 'bin'
+ $InstallerPath = Join-Path $EngCommonBaseDir 'install-tool.ps1'
# Process tools list
Write-Host "Processing $GlobalJsonFile"
@@ -74,7 +75,7 @@ try {
}
$NativeTools = Get-Content($GlobalJsonFile) -Raw |
ConvertFrom-Json |
- Select-Object -Expand "native-tools" -ErrorAction SilentlyContinue
+ Select-Object -Expand 'native-tools' -ErrorAction SilentlyContinue
if ($NativeTools) {
$NativeTools.PSObject.Properties | ForEach-Object {
$ToolName = $_.Name
@@ -112,18 +113,21 @@ try {
}
$toolInstallationFailure = $true
} else {
- Write-Error $errMsg
+ # We cannot change this to Write-PipelineTelemetryError because of https://github.com/dotnet/arcade/issues/4482
+ Write-Host $errMsg
exit 1
}
}
}
if ((Get-Variable 'toolInstallationFailure' -ErrorAction 'SilentlyContinue') -and $toolInstallationFailure) {
+ # We cannot change this to Write-PipelineTelemetryError because of https://github.com/dotnet/arcade/issues/4482
+ Write-Host 'Native tools bootstrap failed'
exit 1
}
}
else {
- Write-Host "No native tools defined in global.json"
+ Write-Host 'No native tools defined in global.json'
exit 0
}
@@ -131,17 +135,18 @@ try {
exit 0
}
if (Test-Path $InstallBin) {
- Write-Host "Native tools are available from" (Convert-Path -Path $InstallBin)
+ Write-Host 'Native tools are available from ' (Convert-Path -Path $InstallBin)
Write-Host "##vso[task.prependpath]$(Convert-Path -Path $InstallBin)"
+ return $InstallBin
}
else {
- Write-Error "Native tools install directory does not exist, installation failed"
+ Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message 'Native tools install directory does not exist, installation failed'
exit 1
}
exit 0
}
catch {
- Write-Host $_
- Write-Host $_.Exception
- exit 1
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message $_
+ ExitWithExitCode 1
}
diff --git a/eng/common/init-tools-native.sh b/eng/common/init-tools-native.sh
index 5f2e77f448b..29fc5db8ae0 100755
--- a/eng/common/init-tools-native.sh
+++ b/eng/common/init-tools-native.sh
@@ -12,6 +12,7 @@ retry_wait_time_seconds=30
global_json_file="$(dirname "$(dirname "${scriptroot}")")/global.json"
declare -A native_assets
+. $scriptroot/pipeline-logging-functions.sh
. $scriptroot/native/common-library.sh
while (($# > 0)); do
@@ -33,6 +34,14 @@ while (($# > 0)); do
force=true
shift 1
;;
+ --donotabortonfailure)
+ donotabortonfailure=true
+ shift 1
+ ;;
+ --donotdisplaywarnings)
+ donotdisplaywarnings=true
+ shift 1
+ ;;
--downloadretries)
download_retries=$2
shift 2
@@ -51,6 +60,8 @@ while (($# > 0)); do
echo " - (default) %USERPROFILE%/.netcoreeng/native"
echo ""
echo " --clean Switch specifying not to install anything, but cleanup native asset folders"
+ echo " --donotabortonfailure Switch specifiying whether to abort native tools installation on failure"
+ echo " --donotdisplaywarnings Switch specifiying whether to display warnings during native tools installation on failure"
echo " --force Clean and then install tools"
echo " --help Print help and exit"
echo ""
@@ -70,8 +81,7 @@ function ReadGlobalJsonNativeTools {
# Only extract the contents of the object.
local native_tools_list=$(echo $native_tools_section | awk -F"[{}]" '{print $2}')
native_tools_list=${native_tools_list//[\" ]/}
- native_tools_list=${native_tools_list//,/$'\n'}
- native_tools_list="$(echo -e "${native_tools_list}" | tr -d '[[:space:]]')"
+ native_tools_list=$( echo "$native_tools_list" | sed 's/\s//g' | sed 's/,/\n/g' )
local old_IFS=$IFS
while read -r line; do
@@ -92,6 +102,7 @@ if [[ -z $install_directory ]]; then
fi
install_bin="${native_base_dir}/bin"
+installed_any=false
ReadGlobalJsonNativeTools
@@ -103,11 +114,12 @@ else
for tool in "${!native_assets[@]}"
do
tool_version=${native_assets[$tool]}
- installer_name="install-$tool.sh"
- installer_command="$native_installer_dir/$installer_name"
+ installer_path="$native_installer_dir/install-$tool.sh"
+ installer_command="$installer_path"
installer_command+=" --baseuri $base_uri"
installer_command+=" --installpath $install_bin"
installer_command+=" --version $tool_version"
+ echo $installer_command
if [[ $force = true ]]; then
installer_command+=" --force"
@@ -117,11 +129,29 @@ else
installer_command+=" --clean"
fi
- $installer_command
-
- if [[ $? != 0 ]]; then
- echo "Execution Failed" >&2
- exit 1
+ if [[ -a $installer_path ]]; then
+ $installer_command
+ if [[ $? != 0 ]]; then
+ if [[ $donotabortonfailure = true ]]; then
+ if [[ $donotdisplaywarnings != true ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Execution Failed"
+ fi
+ else
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Execution Failed"
+ exit 1
+ fi
+ else
+ $installed_any = true
+ fi
+ else
+ if [[ $donotabortonfailure == true ]]; then
+ if [[ $donotdisplaywarnings != true ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Execution Failed: no install script"
+ fi
+ else
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Execution Failed: no install script"
+ exit 1
+ fi
fi
done
fi
@@ -134,8 +164,10 @@ if [[ -d $install_bin ]]; then
echo "Native tools are available from $install_bin"
echo "##vso[task.prependpath]$install_bin"
else
- echo "Native tools install directory does not exist, installation failed" >&2
- exit 1
+ if [[ $installed_any = true ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Native tools install directory does not exist, installation failed"
+ exit 1
+ fi
fi
exit 0
diff --git a/eng/common/internal-feed-operations.ps1 b/eng/common/internal-feed-operations.ps1
index 8b8bafd6a89..b8f6529fdc8 100644
--- a/eng/common/internal-feed-operations.ps1
+++ b/eng/common/internal-feed-operations.ps1
@@ -6,9 +6,8 @@ param(
[switch] $IsFeedPrivate
)
-$ErrorActionPreference = "Stop"
+$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 2.0
-
. $PSScriptRoot\tools.ps1
# Sets VSS_NUGET_EXTERNAL_FEED_ENDPOINTS based on the "darc-int-*" feeds defined in NuGet.config. This is needed
@@ -21,7 +20,7 @@ function SetupCredProvider {
)
# Install the Cred Provider NuGet plugin
- Write-Host "Setting up Cred Provider NuGet plugin in the agent..."
+ Write-Host 'Setting up Cred Provider NuGet plugin in the agent...'
Write-Host "Getting 'installcredprovider.ps1' from 'https://github.com/microsoft/artifacts-credprovider'..."
$url = 'https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.ps1'
@@ -29,18 +28,18 @@ function SetupCredProvider {
Write-Host "Writing the contents of 'installcredprovider.ps1' locally..."
Invoke-WebRequest $url -OutFile installcredprovider.ps1
- Write-Host "Installing plugin..."
+ Write-Host 'Installing plugin...'
.\installcredprovider.ps1 -Force
Write-Host "Deleting local copy of 'installcredprovider.ps1'..."
Remove-Item .\installcredprovider.ps1
if (-Not("$env:USERPROFILE\.nuget\plugins\netcore")) {
- Write-Host "CredProvider plugin was not installed correctly!"
+ Write-PipelineTelemetryError -Category 'Arcade' -Message 'CredProvider plugin was not installed correctly!'
ExitWithExitCode 1
}
else {
- Write-Host "CredProvider plugin was installed correctly!"
+ Write-Host 'CredProvider plugin was installed correctly!'
}
# Then, we set the 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS' environment variable to restore from the stable
@@ -49,7 +48,7 @@ function SetupCredProvider {
$nugetConfigPath = "$RepoRoot\NuGet.config"
if (-Not (Test-Path -Path $nugetConfigPath)) {
- Write-Host "NuGet.config file not found in repo's root!"
+ Write-PipelineTelemetryError -Category 'Build' -Message 'NuGet.config file not found in repo root!'
ExitWithExitCode 1
}
@@ -64,6 +63,7 @@ function SetupCredProvider {
}
if (($endpoints | Measure-Object).Count -gt 0) {
+ # [SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Endpoint code example with no real credentials.")]
# Create the JSON object. It should look like '{"endpointCredentials": [{"endpoint":"http://example.index.json", "username":"optional", "password":"accesstoken"}]}'
$endpointCredentials = @{endpointCredentials=$endpoints} | ConvertTo-Json -Compress
@@ -81,7 +81,7 @@ function SetupCredProvider {
}
else
{
- Write-Host "No internal endpoints found in NuGet.config"
+ Write-Host 'No internal endpoints found in NuGet.config'
}
}
@@ -99,7 +99,7 @@ function InstallDotNetSdkAndRestoreArcade {
& $dotnet restore $restoreProjPath
- Write-Host "Arcade SDK restored!"
+ Write-Host 'Arcade SDK restored!'
if (Test-Path -Path $restoreProjPath) {
Remove-Item $restoreProjPath
@@ -113,23 +113,22 @@ function InstallDotNetSdkAndRestoreArcade {
try {
Push-Location $PSScriptRoot
- if ($Operation -like "setup") {
+ if ($Operation -like 'setup') {
SetupCredProvider $AuthToken
}
- elseif ($Operation -like "install-restore") {
+ elseif ($Operation -like 'install-restore') {
InstallDotNetSdkAndRestoreArcade
}
else {
- Write-Host "Unknown operation '$Operation'!"
+ Write-PipelineTelemetryError -Category 'Arcade' -Message "Unknown operation '$Operation'!"
ExitWithExitCode 1
}
}
catch {
- Write-Host $_
- Write-Host $_.Exception
Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'Arcade' -Message $_
ExitWithExitCode 1
}
finally {
- Pop-Location
+ Pop-Location
}
diff --git a/eng/common/internal-feed-operations.sh b/eng/common/internal-feed-operations.sh
index 1ff654d2ffc..9ed225e7e55 100755
--- a/eng/common/internal-feed-operations.sh
+++ b/eng/common/internal-feed-operations.sh
@@ -30,7 +30,7 @@ function SetupCredProvider {
rm installcredprovider.sh
if [ ! -d "$HOME/.nuget/plugins" ]; then
- echo "CredProvider plugin was not installed correctly!"
+ Write-PipelineTelemetryError -category 'Build' 'CredProvider plugin was not installed correctly!'
ExitWithExitCode 1
else
echo "CredProvider plugin was installed correctly!"
@@ -42,7 +42,7 @@ function SetupCredProvider {
local nugetConfigPath="$repo_root/NuGet.config"
if [ ! "$nugetConfigPath" ]; then
- echo "NuGet.config file not found in repo's root!"
+ Write-PipelineTelemetryError -category 'Build' "NuGet.config file not found in repo's root!"
ExitWithExitCode 1
fi
@@ -62,6 +62,7 @@ function SetupCredProvider {
endpoints+=']'
if [ ${#endpoints} -gt 2 ]; then
+ # [SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Endpoint code example with no real credentials.")]
# Create the JSON object. It should look like '{"endpointCredentials": [{"endpoint":"http://example.index.json", "username":"optional", "password":"accesstoken"}]}'
local endpointCredentials="{\"endpointCredentials\": "$endpoints"}"
diff --git a/eng/common/internal/Directory.Build.props b/eng/common/internal/Directory.Build.props
index e33179ef373..dbf99d82a5c 100644
--- a/eng/common/internal/Directory.Build.props
+++ b/eng/common/internal/Directory.Build.props
@@ -1,4 +1,4 @@
-
+
diff --git a/eng/common/internal/Tools.csproj b/eng/common/internal/Tools.csproj
index 1a39a7ef3f6..f46d5efe2e3 100644
--- a/eng/common/internal/Tools.csproj
+++ b/eng/common/internal/Tools.csproj
@@ -4,6 +4,7 @@
net472
false
+ false
diff --git a/eng/common/msbuild.ps1 b/eng/common/msbuild.ps1
index b37fd3d5e97..c6401230002 100644
--- a/eng/common/msbuild.ps1
+++ b/eng/common/msbuild.ps1
@@ -1,6 +1,6 @@
[CmdletBinding(PositionalBinding=$false)]
Param(
- [string] $verbosity = "minimal",
+ [string] $verbosity = 'minimal',
[bool] $warnAsError = $true,
[bool] $nodeReuse = $true,
[switch] $ci,
@@ -18,9 +18,8 @@ try {
MSBuild @extraArgs
}
catch {
- Write-Host $_
- Write-Host $_.Exception
Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'Build' -Message $_
ExitWithExitCode 1
}
diff --git a/eng/common/native/CommonLibrary.psm1 b/eng/common/native/CommonLibrary.psm1
index 2a08d5246e7..adf707c8fe7 100644
--- a/eng/common/native/CommonLibrary.psm1
+++ b/eng/common/native/CommonLibrary.psm1
@@ -48,7 +48,7 @@ function DownloadAndExtract {
-Verbose:$Verbose
if ($DownloadStatus -Eq $False) {
- Write-Error "Download failed"
+ Write-Error "Download failed from $Uri"
return $False
}
@@ -145,18 +145,25 @@ function Get-File {
New-Item -path $DownloadDirectory -force -itemType "Directory" | Out-Null
}
+ $TempPath = "$Path.tmp"
if (Test-Path -IsValid -Path $Uri) {
- Write-Verbose "'$Uri' is a file path, copying file to '$Path'"
- Copy-Item -Path $Uri -Destination $Path
+ Write-Verbose "'$Uri' is a file path, copying temporarily to '$TempPath'"
+ Copy-Item -Path $Uri -Destination $TempPath
+ Write-Verbose "Moving temporary file to '$Path'"
+ Move-Item -Path $TempPath -Destination $Path
return $?
}
else {
Write-Verbose "Downloading $Uri"
+ # Don't display the console progress UI - it's a huge perf hit
+ $ProgressPreference = 'SilentlyContinue'
while($Attempt -Lt $DownloadRetries)
{
try {
- Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $Path
- Write-Verbose "Downloaded to '$Path'"
+ Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $TempPath
+ Write-Verbose "Downloaded to temporary location '$TempPath'"
+ Move-Item -Path $TempPath -Destination $Path
+ Write-Verbose "Moved temporary file to '$Path'"
return $True
}
catch {
@@ -357,16 +364,21 @@ function Expand-Zip {
return $False
}
}
- if (-Not (Test-Path $OutputDirectory)) {
- New-Item -path $OutputDirectory -Force -itemType "Directory" | Out-Null
+
+ $TempOutputDirectory = Join-Path "$(Split-Path -Parent $OutputDirectory)" "$(Split-Path -Leaf $OutputDirectory).tmp"
+ if (Test-Path $TempOutputDirectory) {
+ Remove-Item $TempOutputDirectory -Force -Recurse
}
+ New-Item -Path $TempOutputDirectory -Force -ItemType "Directory" | Out-Null
Add-Type -assembly "system.io.compression.filesystem"
- [io.compression.zipfile]::ExtractToDirectory("$ZipPath", "$OutputDirectory")
+ [io.compression.zipfile]::ExtractToDirectory("$ZipPath", "$TempOutputDirectory")
if ($? -Eq $False) {
Write-Error "Unable to extract '$ZipPath'"
return $False
}
+
+ Move-Item -Path $TempOutputDirectory -Destination $OutputDirectory
}
catch {
Write-Host $_
diff --git a/eng/common/native/common-library.sh b/eng/common/native/common-library.sh
index 271bddfac5a..bf272dcf55a 100755
--- a/eng/common/native/common-library.sh
+++ b/eng/common/native/common-library.sh
@@ -34,7 +34,7 @@ function ExpandZip {
echo "'Force flag enabled, but '$output_directory' exists. Removing directory"
rm -rf $output_directory
if [[ $? != 0 ]]; then
- echo Unable to remove '$output_directory'>&2
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Unable to remove '$output_directory'"
return 1
fi
fi
@@ -45,7 +45,7 @@ function ExpandZip {
echo "Extracting archive"
tar -xf $zip_path -C $output_directory
if [[ $? != 0 ]]; then
- echo "Unable to extract '$zip_path'" >&2
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Unable to extract '$zip_path'"
return 1
fi
@@ -117,7 +117,7 @@ function DownloadAndExtract {
# Download file
GetFile "$uri" "$temp_tool_path" $force $download_retries $retry_wait_time_seconds
if [[ $? != 0 ]]; then
- echo "Failed to download '$uri' to '$temp_tool_path'." >&2
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Failed to download '$uri' to '$temp_tool_path'."
return 1
fi
@@ -125,7 +125,7 @@ function DownloadAndExtract {
echo "extracting from $temp_tool_path to $installDir"
ExpandZip "$temp_tool_path" "$installDir" $force $download_retries $retry_wait_time_seconds
if [[ $? != 0 ]]; then
- echo "Failed to extract '$temp_tool_path' to '$installDir'." >&2
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Failed to extract '$temp_tool_path' to '$installDir'."
return 1
fi
@@ -148,7 +148,7 @@ function NewScriptShim {
fi
if [[ ! -f $tool_file_path ]]; then
- echo "Specified tool file path:'$tool_file_path' does not exist" >&2
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Specified tool file path:'$tool_file_path' does not exist"
return 1
fi
diff --git a/eng/common/native/find-native-compiler.sh b/eng/common/native/find-native-compiler.sh
new file mode 100644
index 00000000000..aed19d07d50
--- /dev/null
+++ b/eng/common/native/find-native-compiler.sh
@@ -0,0 +1,121 @@
+#!/usr/bin/env bash
+#
+# This file locates the native compiler with the given name and version and sets the environment variables to locate it.
+#
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $SOURCE until the file is no longer a symlink
+while [[ -h $source ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+if [ $# -lt 0 ]
+then
+ echo "Usage..."
+ echo "find-native-compiler.sh "
+ echo "Specify the name of compiler (clang or gcc)."
+ echo "Specify the major version of compiler."
+ echo "Specify the minor version of compiler."
+ exit 1
+fi
+
+. $scriptroot/../pipeline-logging-functions.sh
+
+compiler="$1"
+cxxCompiler="$compiler++"
+majorVersion="$2"
+minorVersion="$3"
+
+if [ "$compiler" = "gcc" ]; then cxxCompiler="g++"; fi
+
+check_version_exists() {
+ desired_version=-1
+
+ # Set up the environment to be used for building with the desired compiler.
+ if command -v "$compiler-$1.$2" > /dev/null; then
+ desired_version="-$1.$2"
+ elif command -v "$compiler$1$2" > /dev/null; then
+ desired_version="$1$2"
+ elif command -v "$compiler-$1$2" > /dev/null; then
+ desired_version="-$1$2"
+ fi
+
+ echo "$desired_version"
+}
+
+if [ -z "$CLR_CC" ]; then
+
+ # Set default versions
+ if [ -z "$majorVersion" ]; then
+ # note: gcc (all versions) and clang versions higher than 6 do not have minor version in file name, if it is zero.
+ if [ "$compiler" = "clang" ]; then versions=( 9 8 7 6.0 5.0 4.0 3.9 3.8 3.7 3.6 3.5 )
+ elif [ "$compiler" = "gcc" ]; then versions=( 9 8 7 6 5 4.9 ); fi
+
+ for version in "${versions[@]}"; do
+ parts=(${version//./ })
+ desired_version="$(check_version_exists "${parts[0]}" "${parts[1]}")"
+ if [ "$desired_version" != "-1" ]; then majorVersion="${parts[0]}"; break; fi
+ done
+
+ if [ -z "$majorVersion" ]; then
+ if command -v "$compiler" > /dev/null; then
+ if [ "$(uname)" != "Darwin" ]; then
+ Write-PipelineTelemetryError -category "Build" -type "warning" "Specific version of $compiler not found, falling back to use the one in PATH."
+ fi
+ export CC="$(command -v "$compiler")"
+ export CXX="$(command -v "$cxxCompiler")"
+ else
+ Write-PipelineTelemetryError -category "Build" "No usable version of $compiler found."
+ exit 1
+ fi
+ else
+ if [ "$compiler" = "clang" ] && [ "$majorVersion" -lt 5 ]; then
+ if [ "$build_arch" = "arm" ] || [ "$build_arch" = "armel" ]; then
+ if command -v "$compiler" > /dev/null; then
+ Write-PipelineTelemetryError -category "Build" -type "warning" "Found clang version $majorVersion which is not supported on arm/armel architectures, falling back to use clang from PATH."
+ export CC="$(command -v "$compiler")"
+ export CXX="$(command -v "$cxxCompiler")"
+ else
+ Write-PipelineTelemetryError -category "Build" "Found clang version $majorVersion which is not supported on arm/armel architectures, and there is no clang in PATH."
+ exit 1
+ fi
+ fi
+ fi
+ fi
+ else
+ desired_version="$(check_version_exists "$majorVersion" "$minorVersion")"
+ if [ "$desired_version" = "-1" ]; then
+ Write-PipelineTelemetryError -category "Build" "Could not find specific version of $compiler: $majorVersion $minorVersion."
+ exit 1
+ fi
+ fi
+
+ if [ -z "$CC" ]; then
+ export CC="$(command -v "$compiler$desired_version")"
+ export CXX="$(command -v "$cxxCompiler$desired_version")"
+ if [ -z "$CXX" ]; then export CXX="$(command -v "$cxxCompiler")"; fi
+ fi
+else
+ if [ ! -f "$CLR_CC" ]; then
+ Write-PipelineTelemetryError -category "Build" "CLR_CC is set but path '$CLR_CC' does not exist"
+ exit 1
+ fi
+ export CC="$CLR_CC"
+ export CXX="$CLR_CXX"
+fi
+
+if [ -z "$CC" ]; then
+ Write-PipelineTelemetryError -category "Build" "Unable to find $compiler."
+ exit 1
+fi
+
+export CCC_CC="$CC"
+export CCC_CXX="$CXX"
+export SCAN_BUILD_COMMAND="$(command -v "scan-build$desired_version")"
diff --git a/eng/common/native/install-cmake-test.sh b/eng/common/native/install-cmake-test.sh
new file mode 100755
index 00000000000..12339a40761
--- /dev/null
+++ b/eng/common/native/install-cmake-test.sh
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+. $scriptroot/common-library.sh
+
+base_uri=
+install_path=
+version=
+clean=false
+force=false
+download_retries=5
+retry_wait_time_seconds=30
+
+while (($# > 0)); do
+ lowerI="$(echo $1 | awk '{print tolower($0)}')"
+ case $lowerI in
+ --baseuri)
+ base_uri=$2
+ shift 2
+ ;;
+ --installpath)
+ install_path=$2
+ shift 2
+ ;;
+ --version)
+ version=$2
+ shift 2
+ ;;
+ --clean)
+ clean=true
+ shift 1
+ ;;
+ --force)
+ force=true
+ shift 1
+ ;;
+ --downloadretries)
+ download_retries=$2
+ shift 2
+ ;;
+ --retrywaittimeseconds)
+ retry_wait_time_seconds=$2
+ shift 2
+ ;;
+ --help)
+ echo "Common settings:"
+ echo " --baseuri Base file directory or Url wrom which to acquire tool archives"
+ echo " --installpath Base directory to install native tool to"
+ echo " --clean Don't install the tool, just clean up the current install of the tool"
+ echo " --force Force install of tools even if they previously exist"
+ echo " --help Print help and exit"
+ echo ""
+ echo "Advanced settings:"
+ echo " --downloadretries Total number of retry attempts"
+ echo " --retrywaittimeseconds Wait time between retry attempts in seconds"
+ echo ""
+ exit 0
+ ;;
+ esac
+done
+
+tool_name="cmake-test"
+tool_os=$(GetCurrentOS)
+tool_folder=$(echo $tool_os | awk '{print tolower($0)}')
+tool_arch="x86_64"
+tool_name_moniker="$tool_name-$version-$tool_os-$tool_arch"
+tool_install_directory="$install_path/$tool_name/$version"
+tool_file_path="$tool_install_directory/$tool_name_moniker/bin/$tool_name"
+shim_path="$install_path/$tool_name.sh"
+uri="${base_uri}/$tool_folder/$tool_name/$tool_name_moniker.tar.gz"
+
+# Clean up tool and installers
+if [[ $clean = true ]]; then
+ echo "Cleaning $tool_install_directory"
+ if [[ -d $tool_install_directory ]]; then
+ rm -rf $tool_install_directory
+ fi
+
+ echo "Cleaning $shim_path"
+ if [[ -f $shim_path ]]; then
+ rm -rf $shim_path
+ fi
+
+ tool_temp_path=$(GetTempPathFileName $uri)
+ echo "Cleaning $tool_temp_path"
+ if [[ -f $tool_temp_path ]]; then
+ rm -rf $tool_temp_path
+ fi
+
+ exit 0
+fi
+
+# Install tool
+if [[ -f $tool_file_path ]] && [[ $force = false ]]; then
+ echo "$tool_name ($version) already exists, skipping install"
+ exit 0
+fi
+
+DownloadAndExtract $uri $tool_install_directory $force $download_retries $retry_wait_time_seconds
+
+if [[ $? != 0 ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' 'Installation failed'
+ exit 1
+fi
+
+# Generate Shim
+# Always rewrite shims so that we are referencing the expected version
+NewScriptShim $shim_path $tool_file_path true
+
+if [[ $? != 0 ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' 'Shim generation failed'
+ exit 1
+fi
+
+exit 0
\ No newline at end of file
diff --git a/eng/common/native/install-cmake.sh b/eng/common/native/install-cmake.sh
index 293af6017df..18041be8763 100755
--- a/eng/common/native/install-cmake.sh
+++ b/eng/common/native/install-cmake.sh
@@ -69,7 +69,7 @@ tool_name_moniker="$tool_name-$version-$tool_os-$tool_arch"
tool_install_directory="$install_path/$tool_name/$version"
tool_file_path="$tool_install_directory/$tool_name_moniker/bin/$tool_name"
shim_path="$install_path/$tool_name.sh"
-uri="${base_uri}/$tool_folder/cmake/$tool_name_moniker.tar.gz"
+uri="${base_uri}/$tool_folder/$tool_name/$tool_name_moniker.tar.gz"
# Clean up tool and installers
if [[ $clean = true ]]; then
@@ -101,7 +101,7 @@ fi
DownloadAndExtract $uri $tool_install_directory $force $download_retries $retry_wait_time_seconds
if [[ $? != 0 ]]; then
- echo "Installation failed" >&2
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' 'Installation failed'
exit 1
fi
@@ -110,7 +110,7 @@ fi
NewScriptShim $shim_path $tool_file_path true
if [[ $? != 0 ]]; then
- echo "Shim generation failed" >&2
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' 'Shim generation failed'
exit 1
fi
diff --git a/eng/common/native/install-tool.ps1 b/eng/common/native/install-tool.ps1
index 635ab3fd414..f397e1c75d4 100644
--- a/eng/common/native/install-tool.ps1
+++ b/eng/common/native/install-tool.ps1
@@ -46,6 +46,8 @@ Param (
[int] $RetryWaitTimeInSeconds = 30
)
+. $PSScriptRoot\..\pipeline-logging-functions.ps1
+
# Import common library modules
Import-Module -Name (Join-Path $CommonLibraryDirectory "CommonLibrary.psm1")
@@ -93,7 +95,7 @@ try {
-Verbose:$Verbose
if ($InstallStatus -Eq $False) {
- Write-Error "Installation failed"
+ Write-PipelineTelemetryError "Installation failed" -Category "NativeToolsetBootstrapping"
exit 1
}
}
@@ -103,7 +105,7 @@ try {
Write-Error "There are multiple copies of $ToolName in $($ToolInstallDirectory): `n$(@($ToolFilePath | out-string))"
exit 1
} elseif (@($ToolFilePath).Length -Lt 1) {
- Write-Error "$ToolName was not found in $ToolFilePath."
+ Write-Host "$ToolName was not found in $ToolFilePath."
exit 1
}
@@ -117,14 +119,14 @@ try {
-Verbose:$Verbose
if ($GenerateShimStatus -Eq $False) {
- Write-Error "Generate shim failed"
+ Write-PipelineTelemetryError "Generate shim failed" -Category "NativeToolsetBootstrapping"
return 1
}
exit 0
}
catch {
- Write-Host $_
- Write-Host $_.Exception
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category "NativeToolsetBootstrapping" -Message $_
exit 1
}
diff --git a/eng/common/performance/blazor_perf.proj b/eng/common/performance/blazor_perf.proj
new file mode 100644
index 00000000000..3b25359c438
--- /dev/null
+++ b/eng/common/performance/blazor_perf.proj
@@ -0,0 +1,30 @@
+
+
+ python3
+ $(HelixPreCommands);chmod +x $HELIX_WORKITEM_PAYLOAD/SOD/SizeOnDisk
+
+
+
+
+ %(Identity)
+
+
+
+
+ %HELIX_CORRELATION_PAYLOAD%\performance\src\scenarios\
+ $(ScenarioDirectory)blazor\
+
+
+ $HELIX_CORRELATION_PAYLOAD/performance/src/scenarios/
+ $(ScenarioDirectory)blazor/
+
+
+
+
+ $(WorkItemDirectory)
+ cd $(BlazorDirectory);$(Python) pre.py publish --msbuild %27/p:_TrimmerDumpDependencies=true%27 --msbuild-static AdditionalMonoLinkerOptions=%27"%24(AdditionalMonoLinkerOptions) --dump-dependencies"%27 --binlog %27./traces/blazor_publish.binlog%27
+ $(Python) test.py sod --scenario-name "%(Identity)"
+ $(Python) post.py
+
+
+
\ No newline at end of file
diff --git a/eng/common/performance/crossgen_perf.proj b/eng/common/performance/crossgen_perf.proj
new file mode 100644
index 00000000000..eb8bdd9c440
--- /dev/null
+++ b/eng/common/performance/crossgen_perf.proj
@@ -0,0 +1,110 @@
+
+
+
+
+ %(Identity)
+
+
+
+
+
+ py -3
+ $(HelixPreCommands)
+ %HELIX_CORRELATION_PAYLOAD%\Core_Root
+ %HELIX_CORRELATION_PAYLOAD%\performance\src\scenarios\
+ $(ScenarioDirectory)crossgen\
+ $(ScenarioDirectory)crossgen2\
+
+
+ python3
+ $(HelixPreCommands);chmod +x $HELIX_WORKITEM_PAYLOAD/startup/Startup;chmod +x $HELIX_WORKITEM_PAYLOAD/startup/perfcollect;sudo apt update;chmod +x $HELIX_WORKITEM_PAYLOAD/SOD/SizeOnDisk
+ $HELIX_CORRELATION_PAYLOAD/Core_Root
+ $HELIX_CORRELATION_PAYLOAD/performance/src/scenarios/
+ $(ScenarioDirectory)crossgen/
+ $(ScenarioDirectory)crossgen2/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(WorkItemDirectory)
+ $(Python) $(CrossgenDirectory)test.py crossgen --core-root $(CoreRoot) --test-name %(Identity)
+
+
+
+
+
+ $(WorkItemDirectory)
+ $(Python) $(Crossgen2Directory)test.py crossgen2 --core-root $(CoreRoot) --single %(Identity)
+
+
+
+
+
+ $(WorkItemDirectory)
+ $(Python) $(Crossgen2Directory)test.py crossgen2 --core-root $(CoreRoot) --single %(Identity) --singlethreaded True
+
+
+
+
+
+ $(WorkItemDirectory)
+ $(Python) $(CrossgenDirectory)pre.py crossgen --core-root $(CoreRoot) --single %(Identity)
+ $(Python) $(CrossgenDirectory)test.py sod --scenario-name "Crossgen %(Identity) Size" --dirs ./crossgen.out/
+ $(Python) $(CrossgenDirectory)post.py
+
+
+
+
+
+ $(WorkItemDirectory)
+ $(Python) $(Crossgen2Directory)pre.py crossgen2 --core-root $(CoreRoot) --single %(Identity)
+ $(Python) $(Crossgen2Directory)test.py sod --scenario-name "Crossgen2 %(Identity) Size" --dirs ./crossgen.out/
+ $(Python) $(Crossgen2Directory)post.py
+
+
+
+
+
+
+ 4:00
+
+
+
+ 4:00
+
+
+ 4:00
+
+
+ $(WorkItemDirectory)
+ $(Python) $(Crossgen2Directory)test.py crossgen2 --core-root $(CoreRoot) --composite $(Crossgen2Directory)framework-r2r.dll.rsp
+ 1:00
+
+
+ 4:00
+
+
+ 4:00
+
+
+
\ No newline at end of file
diff --git a/eng/common/performance/microbenchmarks.proj b/eng/common/performance/microbenchmarks.proj
new file mode 100644
index 00000000000..318ca5f1b8d
--- /dev/null
+++ b/eng/common/performance/microbenchmarks.proj
@@ -0,0 +1,144 @@
+
+
+
+ %HELIX_CORRELATION_PAYLOAD%\performance\scripts\benchmarks_ci.py --csproj %HELIX_CORRELATION_PAYLOAD%\performance\$(TargetCsproj)
+ --dotnet-versions %DOTNET_VERSION% --cli-source-info args --cli-branch %PERFLAB_BRANCH% --cli-commit-sha %PERFLAB_HASH% --cli-repository https://github.com/%PERFLAB_REPO% --cli-source-timestamp %PERFLAB_BUILDTIMESTAMP%
+ py -3
+ %HELIX_CORRELATION_PAYLOAD%\Core_Root\CoreRun.exe
+ %HELIX_CORRELATION_PAYLOAD%\Baseline_Core_Root\CoreRun.exe
+
+ $(HelixPreCommands);call %HELIX_CORRELATION_PAYLOAD%\performance\tools\machine-setup.cmd;set PYTHONPATH=%HELIX_WORKITEM_PAYLOAD%\scripts%3B%HELIX_WORKITEM_PAYLOAD%
+ %HELIX_CORRELATION_PAYLOAD%\artifacts\BenchmarkDotNet.Artifacts
+ %HELIX_CORRELATION_PAYLOAD%\artifacts\BenchmarkDotNet.Artifacts_Baseline
+ %HELIX_CORRELATION_PAYLOAD%\performance\src\tools\ResultsComparer\ResultsComparer.csproj
+ %HELIX_CORRELATION_PAYLOAD%\performance\tools\dotnet\$(Architecture)\dotnet.exe
+ %25%25
+ %HELIX_WORKITEM_ROOT%\testResults.xml
+
+
+
+ $HELIX_CORRELATION_PAYLOAD
+ $(BaseDirectory)/performance
+
+
+
+ $HELIX_WORKITEM_PAYLOAD
+ $(BaseDirectory)
+
+
+
+ $(PerformanceDirectory)/scripts/benchmarks_ci.py --csproj $(PerformanceDirectory)/$(TargetCsproj)
+ --dotnet-versions $DOTNET_VERSION --cli-source-info args --cli-branch $PERFLAB_BRANCH --cli-commit-sha $PERFLAB_HASH --cli-repository https://github.com/$PERFLAB_REPO --cli-source-timestamp $PERFLAB_BUILDTIMESTAMP
+ python3
+ $(BaseDirectory)/Core_Root/corerun
+ $(BaseDirectory)/Baseline_Core_Root/corerun
+ $(HelixPreCommands);chmod +x $(PerformanceDirectory)/tools/machine-setup.sh;. $(PerformanceDirectory)/tools/machine-setup.sh
+ $(BaseDirectory)/artifacts/BenchmarkDotNet.Artifacts
+ $(BaseDirectory)/artifacts/BenchmarkDotNet.Artifacts_Baseline
+ $(PerformanceDirectory)/src/tools/ResultsComparer/ResultsComparer.csproj
+ $(PerformanceDirectory)/tools/dotnet/$(Architecture)/dotnet
+ %25
+ $HELIX_WORKITEM_ROOT/testResults.xml
+
+
+
+ $(CliArguments) --wasm
+
+
+
+ --corerun %HELIX_CORRELATION_PAYLOAD%\dotnet-mono\shared\Microsoft.NETCore.App\6.0.0\corerun.exe
+
+
+ --corerun $(BaseDirectory)/dotnet-mono/shared/Microsoft.NETCore.App/6.0.0/corerun
+
+
+
+ --corerun $(CoreRun)
+
+
+
+ --corerun $(BaselineCoreRun)
+
+
+
+ $(Python) $(WorkItemCommand) --incremental no --architecture $(Architecture) -f $(_Framework) $(PerfLabArguments)
+
+
+
+ $(WorkItemCommand) $(CliArguments)
+
+
+
+ 2:30
+ 0:15
+
+
+
+
+ %(Identity)
+
+
+
+
+ 30
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+ $(WorkItemDirectory)
+ $(WorkItemCommand) --bdn-artifacts $(BaselineArtifactsDirectory) --bdn-arguments="--anyCategories $(BDNCategories) $(ExtraBenchmarkDotNetArguments) $(BaselineCoreRunArgument) --partition-count $(PartitionCount) --partition-index %(HelixWorkItem.Index)"
+ $(WorkItemCommand) --bdn-artifacts $(ArtifactsDirectory) --bdn-arguments="--anyCategories $(BDNCategories) $(ExtraBenchmarkDotNetArguments) $(CoreRunArgument) --partition-count $(PartitionCount) --partition-index %(HelixWorkItem.Index)"
+ $(DotnetExe) run -f $(_Framework) -p $(ResultsComparer) --base $(BaselineArtifactsDirectory) --diff $(ArtifactsDirectory) --threshold 2$(Percent) --xml $(XMLResults);$(FinalCommand)
+ $(WorkItemTimeout)
+
+
+
+
+
+ $(WorkItemDirectory)
+ $(WorkItemCommand) --bdn-artifacts $(BaselineArtifactsDirectory) --bdn-arguments="--anyCategories $(BDNCategories) $(ExtraBenchmarkDotNetArguments) $(BaselineCoreRunArgument)"
+ $(WorkItemCommand) --bdn-artifacts $(ArtifactsDirectory) --bdn-arguments="--anyCategories $(BDNCategories) $(ExtraBenchmarkDotNetArguments) $(CoreRunArgument)"
+ $(DotnetExe) run -f $(_Framework) -p $(ResultsComparer) --base $(BaselineArtifactsDirectory) --diff $(ArtifactsDirectory) --threshold 2$(Percent) --xml $(XMLResults)
+ 4:00
+
+
+
diff --git a/eng/common/performance/perfhelixpublish.proj b/eng/common/performance/perfhelixpublish.proj
deleted file mode 100644
index 05e5f098915..00000000000
--- a/eng/common/performance/perfhelixpublish.proj
+++ /dev/null
@@ -1,77 +0,0 @@
-
-
-
- %HELIX_CORRELATION_PAYLOAD%\performance\scripts\benchmarks_ci.py --csproj %HELIX_CORRELATION_PAYLOAD%\performance\$(TargetCsproj)
- --dotnet-versions %DOTNET_VERSION% --cli-source-info args --cli-branch %PERFLAB_BRANCH% --cli-commit-sha %PERFLAB_HASH% --cli-repository https://github.com/%PERFLAB_REPO% --cli-source-timestamp %PERFLAB_BUILDTIMESTAMP%
- py -3
- %HELIX_CORRELATION_PAYLOAD%\Core_Root\CoreRun.exe
- $(HelixPreCommands);call %HELIX_CORRELATION_PAYLOAD%\performance\tools\machine-setup.cmd
- %HELIX_CORRELATION_PAYLOAD%\artifacts\BenchmarkDotNet.Artifacts
-
-
-
- $HELIX_CORRELATION_PAYLOAD
- $(BaseDirectory)/performance
-
-
-
- $HELIX_WORKITEM_PAYLOAD
- $(BaseDirectory)
-
-
-
- $(PerformanceDirectory)/scripts/benchmarks_ci.py --csproj $(PerformanceDirectory)/$(TargetCsproj)
- --dotnet-versions $DOTNET_VERSION --cli-source-info args --cli-branch $PERFLAB_BRANCH --cli-commit-sha $PERFLAB_HASH --cli-repository https://github.com/$PERFLAB_REPO --cli-source-timestamp $PERFLAB_BUILDTIMESTAMP
- python3
- $(BaseDirectory)/Core_Root/corerun
- $(HelixPreCommands);chmod +x $(PerformanceDirectory)/tools/machine-setup.sh;. $(PerformanceDirectory)/tools/machine-setup.sh
- $(BaseDirectory)/artifacts/BenchmarkDotNet.Artifacts
-
-
-
- --corerun $(CoreRun)
-
-
-
- $(Python) $(WorkItemCommand) --incremental no --architecture $(Architecture) -f $(_Framework) $(PerfLabArguments)
-
-
-
- $(WorkItemCommand) $(CliArguments)
-
-
-
-
- %(Identity)
-
-
-
-
- 5
-
-
-
-
-
-
-
-
-
-
-
-
- $(WorkItemDirectory)
- $(WorkItemCommand) --bdn-arguments="--anyCategories $(BDNCategories) $(ExtraBenchmarkDotNetArguments) $(CoreRunArgument) --artifacts $(ArtifactsDirectory) --partition-count $(PartitionCount) --partition-index %(HelixWorkItem.Index)"
- 4:00
-
-
-
-
- $(WorkItemDirectory)
- $(WorkItemCommand) --bdn-arguments="--anyCategories $(BDNCategories) $(ExtraBenchmarkDotNetArguments) $(CoreRunArgument) --artifacts $(ArtifactsDirectory)"
- 4:00
-
-
-
\ No newline at end of file
diff --git a/eng/common/performance/performance-setup.ps1 b/eng/common/performance/performance-setup.ps1
index 7e5441f7974..0edb2ae276e 100644
--- a/eng/common/performance/performance-setup.ps1
+++ b/eng/common/performance/performance-setup.ps1
@@ -1,22 +1,29 @@
Param(
[string] $SourceDirectory=$env:BUILD_SOURCESDIRECTORY,
[string] $CoreRootDirectory,
+ [string] $BaselineCoreRootDirectory,
[string] $Architecture="x64",
- [string] $Framework="netcoreapp3.0",
+ [string] $Framework="net5.0",
[string] $CompilationMode="Tiered",
[string] $Repository=$env:BUILD_REPOSITORY_NAME,
[string] $Branch=$env:BUILD_SOURCEBRANCH,
[string] $CommitSha=$env:BUILD_SOURCEVERSION,
[string] $BuildNumber=$env:BUILD_BUILDNUMBER,
- [string] $RunCategories="coreclr corefx",
+ [string] $RunCategories="Libraries Runtime",
[string] $Csproj="src\benchmarks\micro\MicroBenchmarks.csproj",
[string] $Kind="micro",
+ [switch] $LLVM,
+ [switch] $MonoInterpreter,
+ [switch] $MonoAOT,
[switch] $Internal,
- [string] $Configurations="CompilationMode=$CompilationMode"
+ [switch] $Compare,
+ [string] $MonoDotnet="",
+ [string] $Configurations="CompilationMode=$CompilationMode RunKind=$Kind"
)
-$RunFromPerformanceRepo = ($Repository -eq "dotnet/performance")
+$RunFromPerformanceRepo = ($Repository -eq "dotnet/performance") -or ($Repository -eq "dotnet-performance")
$UseCoreRun = ($CoreRootDirectory -ne [string]::Empty)
+$UseBaselineCoreRun = ($BaselineCoreRootDirectory -ne [string]::Empty)
$PayloadDirectory = (Join-Path $SourceDirectory "Payload")
$PerformanceDirectory = (Join-Path $PayloadDirectory "performance")
@@ -28,21 +35,58 @@ $HelixSourcePrefix = "pr"
$Queue = "Windows.10.Amd64.ClientRS4.DevEx.15.8.Open"
-if ($Framework.StartsWith("netcoreapp")) {
- $Queue = "Windows.10.Amd64.ClientRS4.Open"
+# TODO: Implement a better logic to determine if Framework is .NET Core or >= .NET 5.
+if ($Framework.StartsWith("netcoreapp") -or ($Framework -eq "net5.0")) {
+ $Queue = "Windows.10.Amd64.ClientRS5.Open"
+}
+
+if ($Compare) {
+ $Queue = "Windows.10.Amd64.19H1.Tiger.Perf.Open"
+ $PerfLabArguments = ""
+ $ExtraBenchmarkDotNetArguments = ""
}
if ($Internal) {
- $Queue = "Windows.10.Amd64.ClientRS5.Perf"
+ $Queue = "Windows.10.Amd64.19H1.Tiger.Perf"
$PerfLabArguments = "--upload-to-perflab-container"
$ExtraBenchmarkDotNetArguments = ""
$Creator = ""
$HelixSourcePrefix = "official"
}
-$CommonSetupArguments="--frameworks $Framework --queue $Queue --build-number $BuildNumber --build-configs $Configurations"
+if($MonoInterpreter)
+{
+ $ExtraBenchmarkDotNetArguments = "--category-exclusion-filter NoInterpreter"
+}
+
+if($MonoDotnet -ne "")
+{
+ $Configurations += " LLVM=$LLVM MonoInterpreter=$MonoInterpreter MonoAOT=$MonoAOT"
+ if($ExtraBenchmarkDotNetArguments -eq "")
+ {
+ #FIX ME: We need to block these tests as they don't run on mono for now
+ $ExtraBenchmarkDotNetArguments = "--exclusion-filter *Perf_Image* *Perf_NamedPipeStream*"
+ }
+ else
+ {
+ #FIX ME: We need to block these tests as they don't run on mono for now
+ $ExtraBenchmarkDotNetArguments += " --exclusion-filter *Perf_Image* *Perf_NamedPipeStream*"
+ }
+}
+
+# FIX ME: This is a workaround until we get this from the actual pipeline
+$CommonSetupArguments="--channel master --queue $Queue --build-number $BuildNumber --build-configs $Configurations --architecture $Architecture"
$SetupArguments = "--repository https://github.com/$Repository --branch $Branch --get-perf-hash --commit-sha $CommitSha $CommonSetupArguments"
+
+#This grabs the LKG version number of dotnet and passes it to our scripts
+$VersionJSON = Get-Content global.json | ConvertFrom-Json
+$DotNetVersion = $VersionJSON.tools.dotnet
+# TODO: Change this back to parsing when we have a good story for dealing with TFM changes or when the LKG in runtime gets updated to include net6.0
+# $SetupArguments = "--dotnet-versions $DotNetVersion $SetupArguments"
+$SetupArguments = "--dotnet-versions 6.0.100-alpha.1.20553.6 $SetupArguments"
+
+
if ($RunFromPerformanceRepo) {
$SetupArguments = "--perf-hash $CommitSha $CommonSetupArguments"
@@ -52,10 +96,21 @@ else {
git clone --branch master --depth 1 --quiet https://github.com/dotnet/performance $PerformanceDirectory
}
+if($MonoDotnet -ne "")
+{
+ $UsingMono = "true"
+ $MonoDotnetPath = (Join-Path $PayloadDirectory "dotnet-mono")
+ Move-Item -Path $MonoDotnet -Destination $MonoDotnetPath
+}
+
if ($UseCoreRun) {
$NewCoreRoot = (Join-Path $PayloadDirectory "Core_Root")
Move-Item -Path $CoreRootDirectory -Destination $NewCoreRoot
}
+if ($UseBaselineCoreRun) {
+ $NewBaselineCoreRoot = (Join-Path $PayloadDirectory "Baseline_Core_Root")
+ Move-Item -Path $BaselineCoreRootDirectory -Destination $NewBaselineCoreRoot
+}
$DocsDir = (Join-Path $PerformanceDirectory "docs")
robocopy $DocsDir $WorkItemDirectory
@@ -80,7 +135,10 @@ Write-PipelineSetVariable -Name 'TargetCsproj' -Value "$Csproj" -IsMultiJobVaria
Write-PipelineSetVariable -Name 'Kind' -Value "$Kind" -IsMultiJobVariable $false
Write-PipelineSetVariable -Name 'Architecture' -Value "$Architecture" -IsMultiJobVariable $false
Write-PipelineSetVariable -Name 'UseCoreRun' -Value "$UseCoreRun" -IsMultiJobVariable $false
+Write-PipelineSetVariable -Name 'UseBaselineCoreRun' -Value "$UseBaselineCoreRun" -IsMultiJobVariable $false
Write-PipelineSetVariable -Name 'RunFromPerfRepo' -Value "$RunFromPerformanceRepo" -IsMultiJobVariable $false
+Write-PipelineSetVariable -Name 'Compare' -Value "$Compare" -IsMultiJobVariable $false
+Write-PipelineSetVariable -Name 'MonoDotnet' -Value "$UsingMono" -IsMultiJobVariable $false
# Helix Arguments
Write-PipelineSetVariable -Name 'Creator' -Value "$Creator" -IsMultiJobVariable $false
diff --git a/eng/common/performance/performance-setup.sh b/eng/common/performance/performance-setup.sh
index 126da5f76d4..c8e211bcb1b 100755
--- a/eng/common/performance/performance-setup.sh
+++ b/eng/common/performance/performance-setup.sh
@@ -2,20 +2,31 @@
source_directory=$BUILD_SOURCESDIRECTORY
core_root_directory=
+baseline_core_root_directory=
architecture=x64
-framework=netcoreapp3.0
+framework=net5.0
compilation_mode=tiered
repository=$BUILD_REPOSITORY_NAME
branch=$BUILD_SOURCEBRANCH
commit_sha=$BUILD_SOURCEVERSION
build_number=$BUILD_BUILDNUMBER
internal=false
+compare=false
+mono_dotnet=
kind="micro"
-run_categories="coreclr corefx"
+llvm=false
+monointerpreter=false
+monoaot=false
+run_categories="Libraries Runtime"
csproj="src\benchmarks\micro\MicroBenchmarks.csproj"
-configurations=
+configurations="CompliationMode=$compilation_mode RunKind=$kind"
run_from_perf_repo=false
use_core_run=true
+use_baseline_core_run=true
+using_mono=false
+wasm_runtime_loc=
+using_wasm=false
+use_latest_dotnet=false
while (($# > 0)); do
lowerI="$(echo $1 | awk '{print tolower($0)}')"
@@ -28,6 +39,10 @@ while (($# > 0)); do
core_root_directory=$2
shift 2
;;
+ --baselinecorerootdirectory)
+ baseline_core_root_directory=$2
+ shift 2
+ ;;
--architecture)
architecture=$2
shift 2
@@ -58,6 +73,7 @@ while (($# > 0)); do
;;
--kind)
kind=$2
+ configurations="CompilationMode=$compilation_mode RunKind=$kind"
shift 2
;;
--runcategories)
@@ -72,11 +88,39 @@ while (($# > 0)); do
internal=true
shift 1
;;
+ --llvm)
+ llvm=true
+ shift 1
+ ;;
+ --monointerpreter)
+ monointerpreter=true
+ shift 1
+ ;;
+ --monoaot)
+ monoaot=true
+ shift 1
+ ;;
+ --monodotnet)
+ mono_dotnet=$2
+ shift 2
+ ;;
+ --wasm)
+ wasm_runtime_loc=$2
+ shift 2
+ ;;
+ --compare)
+ compare=true
+ shift 1
+ ;;
--configurations)
configurations=$2
shift 2
;;
- --help)
+ --latestdotnet)
+ use_latest_dotnet=true
+ shift 1
+ ;;
+ *)
echo "Common settings:"
echo " --corerootdirectory Directory where Core_Root exists, if running perf testing with --corerun"
echo " --architecture Architecture of the testing being run"
@@ -96,24 +140,31 @@ while (($# > 0)); do
echo " --kind Related to csproj. The kind of benchmarks that should be run. Defaults to micro"
echo " --runcategories Related to csproj. Categories of benchmarks to run. Defaults to \"coreclr corefx\""
echo " --internal If the benchmarks are running as an official job."
+ echo " --monodotnet Pass the path to the mono dotnet for mono performance testing."
+ echo " --wasm Path to the unpacked wasm runtime pack."
+ echo " --latestdotnet --dotnet-versions will not be specified. --dotnet-versions defaults to LKG version in global.json "
echo ""
exit 0
;;
esac
done
-if [[ "$repository" == "dotnet/performance" ]]; then
+if [ "$repository" == "dotnet/performance" ] || [ "$repository" == "dotnet-performance" ]; then
run_from_perf_repo=true
fi
if [ -z "$configurations" ]; then
- configurations="CompliationMode=$compilation_mode"
+ configurations="CompilationMode=$compilation_mode"
fi
if [ -z "$core_root_directory" ]; then
use_core_run=false
fi
+if [ -z "$baseline_core_root_directory" ]; then
+ use_baseline_core_run=false
+fi
+
payload_directory=$source_directory/Payload
performance_directory=$payload_directory/performance
workitem_directory=$source_directory/workitem
@@ -123,6 +174,19 @@ queue=Ubuntu.1804.Amd64.Open
creator=$BUILD_DEFINITIONNAME
helix_source_prefix="pr"
+if [[ "$compare" == true ]]; then
+ extra_benchmark_dotnet_arguments=
+ perflab_arguments=
+
+ # No open queues for arm64
+ if [[ "$architecture" = "arm64" ]]; then
+ echo "Compare not available for arm64"
+ exit 1
+ fi
+
+ queue=Ubuntu.1804.Amd64.Tiger.Perf.Open
+fi
+
if [[ "$internal" == true ]]; then
perflab_arguments="--upload-to-perflab-container"
helix_source_prefix="official"
@@ -132,13 +196,44 @@ if [[ "$internal" == true ]]; then
if [[ "$architecture" = "arm64" ]]; then
queue=Ubuntu.1804.Arm64.Perf
else
- queue=Ubuntu.1804.Amd64.Perf
+ queue=Ubuntu.1804.Amd64.Tiger.Perf
fi
+else
+ if [[ "$architecture" = "arm64" ]]; then
+ queue=ubuntu.1804.armarch.open
+ else
+ queue=Ubuntu.1804.Amd64.Open
+ fi
+fi
+
+if [[ "$mono_dotnet" != "" ]] && [[ "$monointerpreter" == "false" ]]; then
+ configurations="$configurations LLVM=$llvm MonoInterpreter=$monointerpreter MonoAOT=$monoaot"
+ extra_benchmark_dotnet_arguments="$extra_benchmark_dotnet_arguments --category-exclusion-filter NoMono"
fi
-common_setup_arguments="--frameworks $framework --queue $queue --build-number $build_number --build-configs $configurations"
+if [[ "$wasm_runtime_loc" != "" ]]; then
+ configurations="CompilationMode=wasm RunKind=$kind"
+ extra_benchmark_dotnet_arguments="$extra_benchmark_dotnet_arguments --category-exclusion-filter NoInterpreter NoWASM NoMono"
+fi
+
+if [[ "$mono_dotnet" != "" ]] && [[ "$monointerpreter" == "true" ]]; then
+ configurations="$configurations LLVM=$llvm MonoInterpreter=$monointerpreter MonoAOT=$monoaot"
+ extra_benchmark_dotnet_arguments="$extra_benchmark_dotnet_arguments --category-exclusion-filter NoInterpreter NoMono"
+fi
+
+common_setup_arguments="--channel master --queue $queue --build-number $build_number --build-configs $configurations --architecture $architecture"
setup_arguments="--repository https://github.com/$repository --branch $branch --get-perf-hash --commit-sha $commit_sha $common_setup_arguments"
+
+if [[ "$use_latest_dotnet" = false ]]; then
+ # Get the tools section from the global.json.
+ # This grabs the LKG version number of dotnet and passes it to our scripts
+ dotnet_version=`cat global.json | python3 -c 'import json,sys;obj=json.load(sys.stdin);print(obj["tools"]["dotnet"])'`
+ # TODO: Change this back to parsing when we have a good story for dealing with TFM changes or when the LKG in runtime gets updated to include net6.0
+ # setup_arguments="--dotnet-versions $dotnet_version $setup_arguments"
+ setup_arguments="--dotnet-versions 6.0.100-alpha.1.20553.6 $setup_arguments"
+fi
+
if [[ "$run_from_perf_repo" = true ]]; then
payload_directory=
workitem_directory=$source_directory
@@ -151,26 +246,53 @@ else
mv $docs_directory $workitem_directory
fi
+if [[ "$wasm_runtime_loc" != "" ]]; then
+ using_wasm=true
+ wasm_dotnet_path=$payload_directory/dotnet-wasm
+ mv $wasm_runtime_loc $wasm_dotnet_path
+ extra_benchmark_dotnet_arguments="$extra_benchmark_dotnet_arguments --wasmMainJS \$HELIX_CORRELATION_PAYLOAD/dotnet-wasm/runtime-test.js --wasmEngine /home/helixbot/.jsvu/v8 --customRuntimePack \$HELIX_CORRELATION_PAYLOAD/dotnet-wasm"
+fi
+
+if [[ "$mono_dotnet" != "" ]]; then
+ using_mono=true
+ mono_dotnet_path=$payload_directory/dotnet-mono
+ mv $mono_dotnet $mono_dotnet_path
+fi
+
if [[ "$use_core_run" = true ]]; then
new_core_root=$payload_directory/Core_Root
mv $core_root_directory $new_core_root
fi
+if [[ "$use_baseline_core_run" = true ]]; then
+ new_baseline_core_root=$payload_directory/Baseline_Core_Root
+ mv $baseline_core_root_directory $new_baseline_core_root
+fi
+
+ci=true
+
+_script_dir=$(pwd)/eng/common
+. "$_script_dir/pipeline-logging-functions.sh"
+
# Make sure all of our variables are available for future steps
-echo "##vso[task.setvariable variable=UseCoreRun]$use_core_run"
-echo "##vso[task.setvariable variable=Architecture]$architecture"
-echo "##vso[task.setvariable variable=PayloadDirectory]$payload_directory"
-echo "##vso[task.setvariable variable=PerformanceDirectory]$performance_directory"
-echo "##vso[task.setvariable variable=WorkItemDirectory]$workitem_directory"
-echo "##vso[task.setvariable variable=Queue]$queue"
-echo "##vso[task.setvariable variable=SetupArguments]$setup_arguments"
-echo "##vso[task.setvariable variable=Python]python3"
-echo "##vso[task.setvariable variable=PerfLabArguments]$perflab_arguments"
-echo "##vso[task.setvariable variable=ExtraBenchmarkDotNetArguments]$extra_benchmark_dotnet_arguments"
-echo "##vso[task.setvariable variable=BDNCategories]$run_categories"
-echo "##vso[task.setvariable variable=TargetCsproj]$csproj"
-echo "##vso[task.setvariable variable=RunFromPerfRepo]$run_from_perf_repo"
-echo "##vso[task.setvariable variable=Creator]$creator"
-echo "##vso[task.setvariable variable=HelixSourcePrefix]$helix_source_prefix"
-echo "##vso[task.setvariable variable=Kind]$kind"
-echo "##vso[task.setvariable variable=_BuildConfig]$architecture.$kind.$framework"
\ No newline at end of file
+Write-PipelineSetVariable -name "UseCoreRun" -value "$use_core_run" -is_multi_job_variable false
+Write-PipelineSetVariable -name "UseBaselineCoreRun" -value "$use_baseline_core_run" -is_multi_job_variable false
+Write-PipelineSetVariable -name "Architecture" -value "$architecture" -is_multi_job_variable false
+Write-PipelineSetVariable -name "PayloadDirectory" -value "$payload_directory" -is_multi_job_variable false
+Write-PipelineSetVariable -name "PerformanceDirectory" -value "$performance_directory" -is_multi_job_variable false
+Write-PipelineSetVariable -name "WorkItemDirectory" -value "$workitem_directory" -is_multi_job_variable false
+Write-PipelineSetVariable -name "Queue" -value "$queue" -is_multi_job_variable false
+Write-PipelineSetVariable -name "SetupArguments" -value "$setup_arguments" -is_multi_job_variable false
+Write-PipelineSetVariable -name "Python" -value "python3" -is_multi_job_variable false
+Write-PipelineSetVariable -name "PerfLabArguments" -value "$perflab_arguments" -is_multi_job_variable false
+Write-PipelineSetVariable -name "ExtraBenchmarkDotNetArguments" -value "$extra_benchmark_dotnet_arguments" -is_multi_job_variable false
+Write-PipelineSetVariable -name "BDNCategories" -value "$run_categories" -is_multi_job_variable false
+Write-PipelineSetVariable -name "TargetCsproj" -value "$csproj" -is_multi_job_variable false
+Write-PipelineSetVariable -name "RunFromPerfRepo" -value "$run_from_perf_repo" -is_multi_job_variable false
+Write-PipelineSetVariable -name "Creator" -value "$creator" -is_multi_job_variable false
+Write-PipelineSetVariable -name "HelixSourcePrefix" -value "$helix_source_prefix" -is_multi_job_variable false
+Write-PipelineSetVariable -name "Kind" -value "$kind" -is_multi_job_variable false
+Write-PipelineSetVariable -name "_BuildConfig" -value "$architecture.$kind.$framework" -is_multi_job_variable false
+Write-PipelineSetVariable -name "Compare" -value "$compare" -is_multi_job_variable false
+Write-PipelineSetVariable -name "MonoDotnet" -value "$using_mono" -is_multi_job_variable false
+Write-PipelineSetVariable -name "WasmDotnet" -value "$using_wasm" -is_multi_job_variable false
diff --git a/eng/common/pipeline-logging-functions.ps1 b/eng/common/pipeline-logging-functions.ps1
index af5f48aaceb..8e422c561e4 100644
--- a/eng/common/pipeline-logging-functions.ps1
+++ b/eng/common/pipeline-logging-functions.ps1
@@ -12,6 +12,7 @@ $script:loggingCommandEscapeMappings = @( # TODO: WHAT ABOUT "="? WHAT ABOUT "%"
# TODO: BUG: Escape % ???
# TODO: Add test to verify don't need to escape "=".
+# Specify "-Force" to force pipeline formatted output even if "$ci" is false or not set
function Write-PipelineTelemetryError {
[CmdletBinding()]
param(
@@ -25,80 +26,101 @@ function Write-PipelineTelemetryError {
[string]$SourcePath,
[string]$LineNumber,
[string]$ColumnNumber,
- [switch]$AsOutput)
+ [switch]$AsOutput,
+ [switch]$Force)
- $PSBoundParameters.Remove("Category") | Out-Null
+ $PSBoundParameters.Remove('Category') | Out-Null
+ if ($Force -Or ((Test-Path variable:ci) -And $ci)) {
$Message = "(NETCORE_ENGINEERING_TELEMETRY=$Category) $Message"
- $PSBoundParameters.Remove("Message") | Out-Null
- $PSBoundParameters.Add("Message", $Message)
-
- Write-PipelineTaskError @PSBoundParameters
+ }
+ $PSBoundParameters.Remove('Message') | Out-Null
+ $PSBoundParameters.Add('Message', $Message)
+ Write-PipelineTaskError @PSBoundParameters
}
+# Specify "-Force" to force pipeline formatted output even if "$ci" is false or not set
function Write-PipelineTaskError {
[CmdletBinding()]
param(
- [Parameter(Mandatory = $true)]
- [string]$Message,
- [Parameter(Mandatory = $false)]
- [string]$Type = 'error',
- [string]$ErrCode,
- [string]$SourcePath,
- [string]$LineNumber,
- [string]$ColumnNumber,
- [switch]$AsOutput)
-
- if(!$ci) {
- if($Type -eq 'error') {
- Write-Host $Message -ForegroundColor Red
- return
+ [Parameter(Mandatory = $true)]
+ [string]$Message,
+ [Parameter(Mandatory = $false)]
+ [string]$Type = 'error',
+ [string]$ErrCode,
+ [string]$SourcePath,
+ [string]$LineNumber,
+ [string]$ColumnNumber,
+ [switch]$AsOutput,
+ [switch]$Force
+ )
+
+ if (!$Force -And (-Not (Test-Path variable:ci) -Or !$ci)) {
+ if ($Type -eq 'error') {
+ Write-Host $Message -ForegroundColor Red
+ return
}
elseif ($Type -eq 'warning') {
- Write-Host $Message -ForegroundColor Yellow
- return
+ Write-Host $Message -ForegroundColor Yellow
+ return
}
- }
-
- if(($Type -ne 'error') -and ($Type -ne 'warning')) {
+ }
+
+ if (($Type -ne 'error') -and ($Type -ne 'warning')) {
Write-Host $Message
return
- }
- if(-not $PSBoundParameters.ContainsKey('Type')) {
+ }
+ $PSBoundParameters.Remove('Force') | Out-Null
+ if (-not $PSBoundParameters.ContainsKey('Type')) {
$PSBoundParameters.Add('Type', 'error')
- }
- Write-LogIssue @PSBoundParameters
- }
+ }
+ Write-LogIssue @PSBoundParameters
+}
- function Write-PipelineSetVariable {
+function Write-PipelineSetVariable {
[CmdletBinding()]
param(
- [Parameter(Mandatory = $true)]
- [string]$Name,
- [string]$Value,
- [switch]$Secret,
- [switch]$AsOutput,
- [bool]$IsMultiJobVariable=$true)
-
- if($ci) {
+ [Parameter(Mandatory = $true)]
+ [string]$Name,
+ [string]$Value,
+ [switch]$Secret,
+ [switch]$AsOutput,
+ [bool]$IsMultiJobVariable = $true)
+
+ if ((Test-Path variable:ci) -And $ci) {
Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data $Value -Properties @{
- 'variable' = $Name
- 'isSecret' = $Secret
- 'isOutput' = $IsMultiJobVariable
+ 'variable' = $Name
+ 'isSecret' = $Secret
+ 'isOutput' = $IsMultiJobVariable
} -AsOutput:$AsOutput
- }
- }
+ }
+}
- function Write-PipelinePrependPath {
+function Write-PipelinePrependPath {
[CmdletBinding()]
param(
- [Parameter(Mandatory=$true)]
- [string]$Path,
- [switch]$AsOutput)
- if($ci) {
+ [Parameter(Mandatory = $true)]
+ [string]$Path,
+ [switch]$AsOutput)
+
+ if ((Test-Path variable:ci) -And $ci) {
Write-LoggingCommand -Area 'task' -Event 'prependpath' -Data $Path -AsOutput:$AsOutput
- }
- }
+ }
+}
+
+function Write-PipelineSetResult {
+ [CmdletBinding()]
+ param(
+ [ValidateSet("Succeeded", "SucceededWithIssues", "Failed", "Cancelled", "Skipped")]
+ [Parameter(Mandatory = $true)]
+ [string]$Result,
+ [string]$Message)
+ if ((Test-Path variable:ci) -And $ci) {
+ Write-LoggingCommand -Area 'task' -Event 'complete' -Data $Message -Properties @{
+ 'result' = $Result
+ }
+ }
+}
<########################################
# Private functions.
@@ -115,7 +137,8 @@ function Format-LoggingCommandData {
foreach ($mapping in $script:loggingCommandEscapeMappings) {
$Value = $Value.Replace($mapping.Token, $mapping.Replacement)
}
- } else {
+ }
+ else {
for ($i = $script:loggingCommandEscapeMappings.Length - 1 ; $i -ge 0 ; $i--) {
$mapping = $script:loggingCommandEscapeMappings[$i]
$Value = $Value.Replace($mapping.Replacement, $mapping.Token)
@@ -148,7 +171,8 @@ function Format-LoggingCommand {
if ($first) {
$null = $sb.Append(' ')
$first = $false
- } else {
+ }
+ else {
$null = $sb.Append(';')
}
@@ -185,7 +209,8 @@ function Write-LoggingCommand {
$command = Format-LoggingCommand -Area $Area -Event $Event -Data $Data -Properties $Properties
if ($AsOutput) {
$command
- } else {
+ }
+ else {
Write-Host $command
}
}
@@ -204,12 +229,12 @@ function Write-LogIssue {
[switch]$AsOutput)
$command = Format-LoggingCommand -Area 'task' -Event 'logissue' -Data $Message -Properties @{
- 'type' = $Type
- 'code' = $ErrCode
- 'sourcepath' = $SourcePath
- 'linenumber' = $LineNumber
- 'columnnumber' = $ColumnNumber
- }
+ 'type' = $Type
+ 'code' = $ErrCode
+ 'sourcepath' = $SourcePath
+ 'linenumber' = $LineNumber
+ 'columnnumber' = $ColumnNumber
+ }
if ($AsOutput) {
return $command
}
@@ -221,7 +246,8 @@ function Write-LogIssue {
$foregroundColor = [System.ConsoleColor]::Red
$backgroundColor = [System.ConsoleColor]::Black
}
- } else {
+ }
+ else {
$foregroundColor = $host.PrivateData.WarningForegroundColor
$backgroundColor = $host.PrivateData.WarningBackgroundColor
if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) {
@@ -231,4 +257,4 @@ function Write-LogIssue {
}
Write-Host $command -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor
-}
\ No newline at end of file
+}
diff --git a/eng/common/pipeline-logging-functions.sh b/eng/common/pipeline-logging-functions.sh
index 1c560a50613..da5a7e6129e 100755
--- a/eng/common/pipeline-logging-functions.sh
+++ b/eng/common/pipeline-logging-functions.sh
@@ -2,6 +2,7 @@
function Write-PipelineTelemetryError {
local telemetry_category=''
+ local force=false
local function_args=()
local message=''
while [[ $# -gt 0 ]]; do
@@ -11,6 +12,9 @@ function Write-PipelineTelemetryError {
telemetry_category=$2
shift
;;
+ -force|-f)
+ force=true
+ ;;
-*)
function_args+=("$1 $2")
shift
@@ -22,28 +26,26 @@ function Write-PipelineTelemetryError {
shift
done
- if [[ "$ci" != true ]]; then
+ if [[ $force != true ]] && [[ "$ci" != true ]]; then
echo "$message" >&2
return
fi
+ if [[ $force == true ]]; then
+ function_args+=("-force")
+ fi
message="(NETCORE_ENGINEERING_TELEMETRY=$telemetry_category) $message"
function_args+=("$message")
-
- Write-PipelineTaskError $function_args
+ Write-PipelineTaskError ${function_args[@]}
}
function Write-PipelineTaskError {
- if [[ "$ci" != true ]]; then
- echo "$@" >&2
- return
- fi
-
local message_type="error"
local sourcepath=''
local linenumber=''
local columnnumber=''
local error_code=''
+ local force=false
while [[ $# -gt 0 ]]; do
opt="$(echo "${1/#--/-}" | awk '{print tolower($0)}')"
@@ -68,6 +70,9 @@ function Write-PipelineTaskError {
error_code=$2
shift
;;
+ -force|-f)
+ force=true
+ ;;
*)
break
;;
@@ -76,6 +81,11 @@ function Write-PipelineTaskError {
shift
done
+ if [[ $force != true ]] && [[ "$ci" != true ]]; then
+ echo "$@" >&2
+ return
+ fi
+
local message="##vso[task.logissue"
message="$message type=$message_type"
@@ -169,4 +179,28 @@ function Write-PipelinePrependPath {
if [[ "$ci" == true ]]; then
echo "##vso[task.prependpath]$prepend_path"
fi
-}
\ No newline at end of file
+}
+
+function Write-PipelineSetResult {
+ local result=''
+ local message=''
+
+ while [[ $# -gt 0 ]]; do
+ opt="$(echo "${1/#--/-}" | awk '{print tolower($0)}')"
+ case "$opt" in
+ -result|-r)
+ result=$2
+ shift
+ ;;
+ -message|-m)
+ message=$2
+ shift
+ ;;
+ esac
+ shift
+ done
+
+ if [[ "$ci" == true ]]; then
+ echo "##vso[task.complete result=$result;]$message"
+ fi
+}
diff --git a/eng/common/post-build/add-build-to-channel.ps1 b/eng/common/post-build/add-build-to-channel.ps1
new file mode 100644
index 00000000000..de2d957922a
--- /dev/null
+++ b/eng/common/post-build/add-build-to-channel.ps1
@@ -0,0 +1,48 @@
+param(
+ [Parameter(Mandatory=$true)][int] $BuildId,
+ [Parameter(Mandatory=$true)][int] $ChannelId,
+ [Parameter(Mandatory=$true)][string] $MaestroApiAccessToken,
+ [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro-prod.westus2.cloudapp.azure.com',
+ [Parameter(Mandatory=$false)][string] $MaestroApiVersion = '2019-01-16'
+)
+
+try {
+ . $PSScriptRoot\post-build-utils.ps1
+
+ # Check that the channel we are going to promote the build to exist
+ $channelInfo = Get-MaestroChannel -ChannelId $ChannelId
+
+ if (!$channelInfo) {
+ Write-PipelineTelemetryCategory -Category 'PromoteBuild' -Message "Channel with BAR ID $ChannelId was not found in BAR!"
+ ExitWithExitCode 1
+ }
+
+ # Get info about which channel(s) the build has already been promoted to
+ $buildInfo = Get-MaestroBuild -BuildId $BuildId
+
+ if (!$buildInfo) {
+ Write-PipelineTelemetryError -Category 'PromoteBuild' -Message "Build with BAR ID $BuildId was not found in BAR!"
+ ExitWithExitCode 1
+ }
+
+ # Find whether the build is already assigned to the channel or not
+ if ($buildInfo.channels) {
+ foreach ($channel in $buildInfo.channels) {
+ if ($channel.Id -eq $ChannelId) {
+ Write-Host "The build with BAR ID $BuildId is already on channel $ChannelId!"
+ ExitWithExitCode 0
+ }
+ }
+ }
+
+ Write-Host "Promoting build '$BuildId' to channel '$ChannelId'."
+
+ Assign-BuildToChannel -BuildId $BuildId -ChannelId $ChannelId
+
+ Write-Host 'done.'
+}
+catch {
+ Write-Host $_
+ Write-PipelineTelemetryError -Category 'PromoteBuild' -Message "There was an error while trying to promote build '$BuildId' to channel '$ChannelId'"
+ ExitWithExitCode 1
+}
diff --git a/eng/common/post-build/check-channel-consistency.ps1 b/eng/common/post-build/check-channel-consistency.ps1
new file mode 100644
index 00000000000..63f3464c986
--- /dev/null
+++ b/eng/common/post-build/check-channel-consistency.ps1
@@ -0,0 +1,40 @@
+param(
+ [Parameter(Mandatory=$true)][string] $PromoteToChannels, # List of channels that the build should be promoted to
+ [Parameter(Mandatory=$true)][array] $AvailableChannelIds # List of channel IDs available in the YAML implementation
+)
+
+try {
+ . $PSScriptRoot\post-build-utils.ps1
+
+ if ($PromoteToChannels -eq "") {
+ Write-PipelineTaskError -Type 'warning' -Message "This build won't publish assets as it's not configured to any Maestro channel. If that wasn't intended use Darc to configure a default channel using add-default-channel for this branch or to promote it to a channel using add-build-to-channel. See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md#assigning-an-individual-build-to-a-channel for more info."
+ ExitWithExitCode 0
+ }
+
+ # Check that every channel that Maestro told to promote the build to
+ # is available in YAML
+ $PromoteToChannelsIds = $PromoteToChannels -split "\D" | Where-Object { $_ }
+
+ $hasErrors = $false
+
+ foreach ($id in $PromoteToChannelsIds) {
+ if (($id -ne 0) -and ($id -notin $AvailableChannelIds)) {
+ Write-PipelineTaskError -Message "Channel $id is not present in the post-build YAML configuration! This is an error scenario. Please contact @dnceng."
+ $hasErrors = $true
+ }
+ }
+
+ # The `Write-PipelineTaskError` doesn't error the script and we might report several errors
+ # in the previous lines. The check below makes sure that we return an error state from the
+ # script if we reported any validation error
+ if ($hasErrors) {
+ ExitWithExitCode 1
+ }
+
+ Write-Host 'done.'
+}
+catch {
+ Write-Host $_
+ Write-PipelineTelemetryError -Category 'CheckChannelConsistency' -Message "There was an error while trying to check consistency of Maestro default channels for the build and post-build YAML configuration."
+ ExitWithExitCode 1
+}
diff --git a/eng/common/post-build/darc-gather-drop.ps1 b/eng/common/post-build/darc-gather-drop.ps1
deleted file mode 100644
index 93a0bd83285..00000000000
--- a/eng/common/post-build/darc-gather-drop.ps1
+++ /dev/null
@@ -1,35 +0,0 @@
-param(
- [Parameter(Mandatory=$true)][int] $BarBuildId, # ID of the build which assets should be downloaded
- [Parameter(Mandatory=$true)][string] $DropLocation, # Where the assets should be downloaded to
- [Parameter(Mandatory=$true)][string] $MaestroApiAccessToken, # Token used to access Maestro API
- [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = "https://maestro-prod.westus2.cloudapp.azure.com", # Maestro API URL
- [Parameter(Mandatory=$false)][string] $MaestroApiVersion = "2019-01-16" # Version of Maestro API to use
-)
-
-. $PSScriptRoot\post-build-utils.ps1
-
-try {
- Write-Host "Installing DARC ..."
-
- . $PSScriptRoot\..\darc-init.ps1
- $exitCode = $LASTEXITCODE
-
- if ($exitCode -ne 0) {
- Write-PipelineTaskError "Something failed while running 'darc-init.ps1'. Check for errors above. Exiting now..."
- ExitWithExitCode $exitCode
- }
-
- darc gather-drop --non-shipping `
- --continue-on-error `
- --id $BarBuildId `
- --output-dir $DropLocation `
- --bar-uri $MaestroApiEndpoint `
- --password $MaestroApiAccessToken `
- --latest-location
-}
-catch {
- Write-Host $_
- Write-Host $_.Exception
- Write-Host $_.ScriptStackTrace
- ExitWithExitCode 1
-}
diff --git a/eng/common/post-build/dotnetsymbol-init.ps1 b/eng/common/post-build/dotnetsymbol-init.ps1
deleted file mode 100644
index e7659b98c8c..00000000000
--- a/eng/common/post-build/dotnetsymbol-init.ps1
+++ /dev/null
@@ -1,29 +0,0 @@
-param (
- $dotnetsymbolVersion = $null
-)
-
-$ErrorActionPreference = "Stop"
-Set-StrictMode -Version 2.0
-
-. $PSScriptRoot\..\tools.ps1
-
-$verbosity = "minimal"
-
-function Installdotnetsymbol ($dotnetsymbolVersion) {
- $dotnetsymbolPackageName = "dotnet-symbol"
-
- $dotnetRoot = InitializeDotNetCli -install:$true
- $dotnet = "$dotnetRoot\dotnet.exe"
- $toolList = & "$dotnet" tool list --global
-
- if (($toolList -like "*$dotnetsymbolPackageName*") -and ($toolList -like "*$dotnetsymbolVersion*")) {
- Write-Host "dotnet-symbol version $dotnetsymbolVersion is already installed."
- }
- else {
- Write-Host "Installing dotnet-symbol version $dotnetsymbolVersion..."
- Write-Host "You may need to restart your command window if this is the first dotnet tool you have installed."
- & "$dotnet" tool install $dotnetsymbolPackageName --version $dotnetsymbolVersion --verbosity $verbosity --global
- }
-}
-
-Installdotnetsymbol $dotnetsymbolVersion
diff --git a/eng/common/post-build/nuget-validation.ps1 b/eng/common/post-build/nuget-validation.ps1
index 78ed0d540f5..dab3534ab53 100644
--- a/eng/common/post-build/nuget-validation.ps1
+++ b/eng/common/post-build/nuget-validation.ps1
@@ -6,20 +6,19 @@ param(
[Parameter(Mandatory=$true)][string] $ToolDestinationPath # Where the validation tool should be downloaded to
)
-. $PSScriptRoot\post-build-utils.ps1
-
try {
- $url = "https://raw.githubusercontent.com/NuGet/NuGetGallery/jver-verify/src/VerifyMicrosoftPackage/verify.ps1"
+ . $PSScriptRoot\post-build-utils.ps1
+
+ $url = 'https://raw.githubusercontent.com/NuGet/NuGetGallery/3e25ad135146676bcab0050a516939d9958bfa5d/src/VerifyMicrosoftPackage/verify.ps1'
- New-Item -ItemType "directory" -Path ${ToolDestinationPath} -Force
+ New-Item -ItemType 'directory' -Path ${ToolDestinationPath} -Force
Invoke-WebRequest $url -OutFile ${ToolDestinationPath}\verify.ps1
& ${ToolDestinationPath}\verify.ps1 ${PackagesPath}\*.nupkg
}
catch {
- Write-PipelineTaskError "NuGet package validation failed. Please check error logs."
- Write-Host $_
Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'NuGetValidation' -Message $_
ExitWithExitCode 1
}
diff --git a/eng/common/post-build/post-build-utils.ps1 b/eng/common/post-build/post-build-utils.ps1
index 551ae113f89..534f6988d5b 100644
--- a/eng/common/post-build/post-build-utils.ps1
+++ b/eng/common/post-build/post-build-utils.ps1
@@ -1,16 +1,17 @@
# Most of the functions in this file require the variables `MaestroApiEndPoint`,
# `MaestroApiVersion` and `MaestroApiAccessToken` to be globally available.
-$ErrorActionPreference = "Stop"
+$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 2.0
# `tools.ps1` checks $ci to perform some actions. Since the post-build
# scripts don't necessarily execute in the same agent that run the
# build.ps1/sh script this variable isn't automatically set.
$ci = $true
+$disableConfigureToolsetImport = $true
. $PSScriptRoot\..\tools.ps1
-function Create-MaestroApiRequestHeaders([string]$ContentType = "application/json") {
+function Create-MaestroApiRequestHeaders([string]$ContentType = 'application/json') {
Validate-MaestroVars
$headers = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]'
@@ -50,40 +51,40 @@ function Get-MaestroSubscriptions([string]$SourceRepository, [int]$ChannelId) {
return $result
}
-function Trigger-Subscription([string]$SubscriptionId) {
+function Assign-BuildToChannel([int]$BuildId, [int]$ChannelId) {
Validate-MaestroVars
$apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken
- $apiEndpoint = "$MaestroApiEndPoint/api/subscriptions/$SubscriptionId/trigger?api-version=$MaestroApiVersion"
- Invoke-WebRequest -Uri $apiEndpoint -Headers $apiHeaders -Method Post | Out-Null
+ $apiEndpoint = "$MaestroApiEndPoint/api/channels/${ChannelId}/builds/${BuildId}?api-version=$MaestroApiVersion"
+ Invoke-WebRequest -Method Post -Uri $apiEndpoint -Headers $apiHeaders | Out-Null
}
-function Assign-BuildToChannel([int]$BuildId, [int]$ChannelId) {
+function Trigger-Subscription([string]$SubscriptionId) {
Validate-MaestroVars
$apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken
- $apiEndpoint = "$MaestroApiEndPoint/api/channels/${ChannelId}/builds/${BuildId}?api-version=$MaestroApiVersion"
- Invoke-WebRequest -Method Post -Uri $apiEndpoint -Headers $apiHeaders | Out-Null
+ $apiEndpoint = "$MaestroApiEndPoint/api/subscriptions/$SubscriptionId/trigger?api-version=$MaestroApiVersion"
+ Invoke-WebRequest -Uri $apiEndpoint -Headers $apiHeaders -Method Post | Out-Null
}
function Validate-MaestroVars {
try {
- Get-Variable MaestroApiEndPoint -Scope Global | Out-Null
- Get-Variable MaestroApiVersion -Scope Global | Out-Null
- Get-Variable MaestroApiAccessToken -Scope Global | Out-Null
+ Get-Variable MaestroApiEndPoint | Out-Null
+ Get-Variable MaestroApiVersion | Out-Null
+ Get-Variable MaestroApiAccessToken | Out-Null
- if (!($MaestroApiEndPoint -Match "^http[s]?://maestro-(int|prod).westus2.cloudapp.azure.com$")) {
- Write-PipelineTaskError "MaestroApiEndPoint is not a valid Maestro URL. '$MaestroApiEndPoint'"
+ if (!($MaestroApiEndPoint -Match '^http[s]?://maestro-(int|prod).westus2.cloudapp.azure.com$')) {
+ Write-PipelineTelemetryError -Category 'MaestroVars' -Message "MaestroApiEndPoint is not a valid Maestro URL. '$MaestroApiEndPoint'"
ExitWithExitCode 1
}
- if (!($MaestroApiVersion -Match "^[0-9]{4}-[0-9]{2}-[0-9]{2}$")) {
- Write-PipelineTaskError "MaestroApiVersion does not match a version string in the format yyyy-MM-DD. '$MaestroApiVersion'"
+ if (!($MaestroApiVersion -Match '^[0-9]{4}-[0-9]{2}-[0-9]{2}$')) {
+ Write-PipelineTelemetryError -Category 'MaestroVars' -Message "MaestroApiVersion does not match a version string in the format yyyy-MM-DD. '$MaestroApiVersion'"
ExitWithExitCode 1
}
}
catch {
- Write-PipelineTaskError "Error: Variables `MaestroApiEndPoint`, `MaestroApiVersion` and `MaestroApiAccessToken` are required while using this script."
+ Write-PipelineTelemetryError -Category 'MaestroVars' -Message 'Error: Variables `MaestroApiEndPoint`, `MaestroApiVersion` and `MaestroApiAccessToken` are required while using this script.'
Write-Host $_
ExitWithExitCode 1
}
diff --git a/eng/common/post-build/promote-build.ps1 b/eng/common/post-build/promote-build.ps1
deleted file mode 100644
index e5ae85f2517..00000000000
--- a/eng/common/post-build/promote-build.ps1
+++ /dev/null
@@ -1,48 +0,0 @@
-param(
- [Parameter(Mandatory=$true)][int] $BuildId,
- [Parameter(Mandatory=$true)][int] $ChannelId,
- [Parameter(Mandatory=$true)][string] $MaestroApiAccessToken,
- [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = "https://maestro-prod.westus2.cloudapp.azure.com",
- [Parameter(Mandatory=$false)][string] $MaestroApiVersion = "2019-01-16"
-)
-
-. $PSScriptRoot\post-build-utils.ps1
-
-try {
- # Check that the channel we are going to promote the build to exist
- $channelInfo = Get-MaestroChannel -ChannelId $ChannelId
-
- if (!$channelInfo) {
- Write-Host "Channel with BAR ID $ChannelId was not found in BAR!"
- ExitWithExitCode 1
- }
-
- # Get info about which channels the build has already been promoted to
- $buildInfo = Get-MaestroBuild -BuildId $BuildId
-
- if (!$buildInfo) {
- Write-Host "Build with BAR ID $BuildId was not found in BAR!"
- ExitWithExitCode 1
- }
-
- # Find whether the build is already assigned to the channel or not
- if ($buildInfo.channels) {
- foreach ($channel in $buildInfo.channels) {
- if ($channel.Id -eq $ChannelId) {
- Write-Host "The build with BAR ID $BuildId is already on channel $ChannelId!"
- ExitWithExitCode 0
- }
- }
- }
-
- Write-Host "Promoting build '$BuildId' to channel '$ChannelId'."
-
- Assign-BuildToChannel -BuildId $BuildId -ChannelId $ChannelId
-
- Write-Host "done."
-}
-catch {
- Write-Host "There was an error while trying to promote build '$BuildId' to channel '$ChannelId'"
- Write-Host $_
- Write-Host $_.ScriptStackTrace
-}
diff --git a/eng/common/post-build/publish-using-darc.ps1 b/eng/common/post-build/publish-using-darc.ps1
new file mode 100644
index 00000000000..6b68ee84728
--- /dev/null
+++ b/eng/common/post-build/publish-using-darc.ps1
@@ -0,0 +1,80 @@
+param(
+ [Parameter(Mandatory=$true)][int] $BuildId,
+ [Parameter(Mandatory=$true)][int] $PublishingInfraVersion,
+ [Parameter(Mandatory=$true)][string] $AzdoToken,
+ [Parameter(Mandatory=$true)][string] $MaestroToken,
+ [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro-prod.westus2.cloudapp.azure.com',
+ [Parameter(Mandatory=$true)][string] $WaitPublishingFinish,
+ [Parameter(Mandatory=$false)][string] $EnableSourceLinkValidation,
+ [Parameter(Mandatory=$false)][string] $EnableSigningValidation,
+ [Parameter(Mandatory=$false)][string] $EnableNugetValidation,
+ [Parameter(Mandatory=$false)][string] $PublishInstallersAndChecksums,
+ [Parameter(Mandatory=$false)][string] $ArtifactsPublishingAdditionalParameters,
+ [Parameter(Mandatory=$false)][string] $SymbolPublishingAdditionalParameters,
+ [Parameter(Mandatory=$false)][string] $SigningValidationAdditionalParameters
+)
+
+try {
+ . $PSScriptRoot\post-build-utils.ps1
+ # Hard coding darc version till the next arcade-services roll out, cos this version has required API changes for darc add-build-to-channel
+ $darc = Get-Darc "1.1.0-beta.20418.1"
+
+ $optionalParams = [System.Collections.ArrayList]::new()
+
+ if ("" -ne $ArtifactsPublishingAdditionalParameters) {
+ $optionalParams.Add("--artifact-publishing-parameters") | Out-Null
+ $optionalParams.Add($ArtifactsPublishingAdditionalParameters) | Out-Null
+ }
+
+ if ("" -ne $SymbolPublishingAdditionalParameters) {
+ $optionalParams.Add("--symbol-publishing-parameters") | Out-Null
+ $optionalParams.Add($SymbolPublishingAdditionalParameters) | Out-Null
+ }
+
+ if ("false" -eq $WaitPublishingFinish) {
+ $optionalParams.Add("--no-wait") | Out-Null
+ }
+
+ if ("false" -ne $PublishInstallersAndChecksums) {
+ $optionalParams.Add("--publish-installers-and-checksums") | Out-Null
+ }
+
+ if ("true" -eq $EnableNugetValidation) {
+ $optionalParams.Add("--validate-nuget") | Out-Null
+ }
+
+ if ("true" -eq $EnableSourceLinkValidation) {
+ $optionalParams.Add("--validate-sourcelinkchecksums") | Out-Null
+ }
+
+ if ("true" -eq $EnableSigningValidation) {
+ $optionalParams.Add("--validate-signingchecksums") | Out-Null
+
+ if ("" -ne $SigningValidationAdditionalParameters) {
+ $optionalParams.Add("--signing-validation-parameters") | Out-Null
+ $optionalParams.Add($SigningValidationAdditionalParameters) | Out-Null
+ }
+ }
+
+ & $darc add-build-to-channel `
+ --id $buildId `
+ --publishing-infra-version $PublishingInfraVersion `
+ --default-channels `
+ --source-branch master `
+ --azdev-pat $AzdoToken `
+ --bar-uri $MaestroApiEndPoint `
+ --password $MaestroToken `
+ @optionalParams
+
+ if ($LastExitCode -ne 0) {
+ Write-Host "Problems using Darc to promote build ${buildId} to default channels. Stopping execution..."
+ exit 1
+ }
+
+ Write-Host 'done.'
+}
+catch {
+ Write-Host $_
+ Write-PipelineTelemetryError -Category 'PromoteBuild' -Message "There was an error while trying to publish build '$BuildId' to default channels."
+ ExitWithExitCode 1
+}
diff --git a/eng/common/post-build/setup-maestro-vars.ps1 b/eng/common/post-build/setup-maestro-vars.ps1
deleted file mode 100644
index d7f64dc63cb..00000000000
--- a/eng/common/post-build/setup-maestro-vars.ps1
+++ /dev/null
@@ -1,26 +0,0 @@
-param(
- [Parameter(Mandatory=$true)][string] $ReleaseConfigsPath # Full path to ReleaseConfigs.txt asset
-)
-
-. $PSScriptRoot\post-build-utils.ps1
-
-try {
- $Content = Get-Content $ReleaseConfigsPath
-
- $BarId = $Content | Select -Index 0
-
- $Channels = ""
- $Content | Select -Index 1 | ForEach-Object { $Channels += "$_ ," }
-
- $IsStableBuild = $Content | Select -Index 2
-
- Write-PipelineSetVariable -Name 'BARBuildId' -Value $BarId
- Write-PipelineSetVariable -Name 'InitialChannels' -Value "$Channels"
- Write-PipelineSetVariable -Name 'IsStableBuild' -Value $IsStableBuild
-}
-catch {
- Write-Host $_
- Write-Host $_.Exception
- Write-Host $_.ScriptStackTrace
- ExitWithExitCode 1
-}
diff --git a/eng/common/post-build/sourcelink-cli-init.ps1 b/eng/common/post-build/sourcelink-cli-init.ps1
deleted file mode 100644
index 9eaa25b3b50..00000000000
--- a/eng/common/post-build/sourcelink-cli-init.ps1
+++ /dev/null
@@ -1,29 +0,0 @@
-param (
- $sourcelinkCliVersion = $null
-)
-
-$ErrorActionPreference = "Stop"
-Set-StrictMode -Version 2.0
-
-. $PSScriptRoot\..\tools.ps1
-
-$verbosity = "minimal"
-
-function InstallSourcelinkCli ($sourcelinkCliVersion) {
- $sourcelinkCliPackageName = "sourcelink"
-
- $dotnetRoot = InitializeDotNetCli -install:$true
- $dotnet = "$dotnetRoot\dotnet.exe"
- $toolList = & "$dotnet" tool list --global
-
- if (($toolList -like "*$sourcelinkCliPackageName*") -and ($toolList -like "*$sourcelinkCliVersion*")) {
- Write-Host "SourceLink CLI version $sourcelinkCliVersion is already installed."
- }
- else {
- Write-Host "Installing SourceLink CLI version $sourcelinkCliVersion..."
- Write-Host "You may need to restart your command window if this is the first dotnet tool you have installed."
- & "$dotnet" tool install $sourcelinkCliPackageName --version $sourcelinkCliVersion --verbosity $verbosity --global
- }
-}
-
-InstallSourcelinkCli $sourcelinkCliVersion
diff --git a/eng/common/post-build/sourcelink-validation.ps1 b/eng/common/post-build/sourcelink-validation.ps1
index 41e01ae6e67..1c46f7b6341 100644
--- a/eng/common/post-build/sourcelink-validation.ps1
+++ b/eng/common/post-build/sourcelink-validation.ps1
@@ -1,8 +1,8 @@
param(
[Parameter(Mandatory=$true)][string] $InputPath, # Full path to directory where Symbols.NuGet packages to be checked are stored
[Parameter(Mandatory=$true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation
- [Parameter(Mandatory=$true)][string] $GHRepoName, # GitHub name of the repo including the Org. E.g., dotnet/arcade
- [Parameter(Mandatory=$true)][string] $GHCommit, # GitHub commit SHA used to build the packages
+ [Parameter(Mandatory=$false)][string] $GHRepoName, # GitHub name of the repo including the Org. E.g., dotnet/arcade
+ [Parameter(Mandatory=$false)][string] $GHCommit, # GitHub commit SHA used to build the packages
[Parameter(Mandatory=$true)][string] $SourcelinkCliVersion # Version of SourceLink CLI to use
)
@@ -13,6 +13,12 @@ param(
# all files present in the repo at a specific commit point.
$global:RepoFiles = @{}
+# Maximum number of jobs to run in parallel
+$MaxParallelJobs = 6
+
+# Wait time between check for system load
+$SecondsBetweenLoadChecks = 10
+
$ValidatePackage = {
param(
[string] $PackagePath # Full path to a Symbols.NuGet package
@@ -22,15 +28,15 @@ $ValidatePackage = {
# Ensure input file exist
if (!(Test-Path $PackagePath)) {
- Write-PipelineTaskError "Input file does not exist: $PackagePath"
- ExitWithExitCode 1
+ Write-Host "Input file does not exist: $PackagePath"
+ return 1
}
# Extensions for which we'll look for SourceLink information
# For now we'll only care about Portable & Embedded PDBs
- $RelevantExtensions = @(".dll", ".exe", ".pdb")
+ $RelevantExtensions = @('.dll', '.exe', '.pdb')
- Write-Host -NoNewLine "Validating" ([System.IO.Path]::GetFileName($PackagePath)) "... "
+ Write-Host -NoNewLine 'Validating ' ([System.IO.Path]::GetFileName($PackagePath)) '...'
$PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)
$ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageId
@@ -38,7 +44,7 @@ $ValidatePackage = {
Add-Type -AssemblyName System.IO.Compression.FileSystem
- [System.IO.Directory]::CreateDirectory($ExtractPath);
+ [System.IO.Directory]::CreateDirectory($ExtractPath) | Out-Null
try {
$zip = [System.IO.Compression.ZipFile]::OpenRead($PackagePath)
@@ -52,7 +58,7 @@ $ValidatePackage = {
$TargetFile = Join-Path -Path $ExtractPath -ChildPath $FakeName
# We ignore resource DLLs
- if ($FileName.EndsWith(".resources.dll")) {
+ if ($FileName.EndsWith('.resources.dll')) {
return
}
@@ -90,7 +96,7 @@ $ValidatePackage = {
$Uri = $Link -as [System.URI]
# Only GitHub links are valid
- if ($Uri.AbsoluteURI -ne $null -and ($Uri.Host -match "github" -or $Uri.Host -match "githubusercontent")) {
+ if ($Uri.AbsoluteURI -ne $null -and ($Uri.Host -match 'github' -or $Uri.Host -match 'githubusercontent')) {
$Status = (Invoke-WebRequest -Uri $Link -UseBasicParsing -Method HEAD -TimeoutSec 5).StatusCode
}
else {
@@ -137,17 +143,38 @@ $ValidatePackage = {
}
if ($FailedFiles -eq 0) {
- Write-Host "Passed."
+ Write-Host 'Passed.'
+ return [pscustomobject]@{
+ result = 0
+ packagePath = $PackagePath
+ }
}
else {
- Write-PipelineTaskError "$PackagePath has broken SourceLink links."
+ Write-PipelineTelemetryError -Category 'SourceLink' -Message "$PackagePath has broken SourceLink links."
+ return [pscustomobject]@{
+ result = 1
+ packagePath = $PackagePath
+ }
+ }
+}
+
+function CheckJobResult(
+ $result,
+ $packagePath,
+ [ref]$ValidationFailures,
+ [switch]$logErrors) {
+ if ($result -ne '0') {
+ if ($logErrors) {
+ Write-PipelineTelemetryError -Category 'SourceLink' -Message "$packagePath has broken SourceLink links."
+ }
+ $ValidationFailures.Value++
}
}
function ValidateSourceLinkLinks {
- if (!($GHRepoName -Match "^[^\s\/]+/[^\s\/]+$")) {
- if (!($GHRepoName -Match "^[^\s-]+-[^\s]+$")) {
- Write-PipelineTaskError "GHRepoName should be in the format / or -"
+ if ($GHRepoName -ne '' -and !($GHRepoName -Match '^[^\s\/]+/[^\s\/]+$')) {
+ if (!($GHRepoName -Match '^[^\s-]+-[^\s]+$')) {
+ Write-PipelineTelemetryError -Category 'SourceLink' -Message "GHRepoName should be in the format / or -. '$GHRepoName'"
ExitWithExitCode 1
}
else {
@@ -155,50 +182,73 @@ function ValidateSourceLinkLinks {
}
}
- if (!($GHCommit -Match "^[0-9a-fA-F]{40}$")) {
- Write-PipelineTaskError "GHCommit should be a 40 chars hexadecimal string"
+ if ($GHCommit -ne '' -and !($GHCommit -Match '^[0-9a-fA-F]{40}$')) {
+ Write-PipelineTelemetryError -Category 'SourceLink' -Message "GHCommit should be a 40 chars hexadecimal string. '$GHCommit'"
ExitWithExitCode 1
}
- $RepoTreeURL = -Join("http://api.github.com/repos/", $GHRepoName, "/git/trees/", $GHCommit, "?recursive=1")
- $CodeExtensions = @(".cs", ".vb", ".fs", ".fsi", ".fsx", ".fsscript")
+ if ($GHRepoName -ne '' -and $GHCommit -ne '') {
+ $RepoTreeURL = -Join('http://api.github.com/repos/', $GHRepoName, '/git/trees/', $GHCommit, '?recursive=1')
+ $CodeExtensions = @('.cs', '.vb', '.fs', '.fsi', '.fsx', '.fsscript')
- try {
- # Retrieve the list of files in the repo at that particular commit point and store them in the RepoFiles hash
- $Data = Invoke-WebRequest $RepoTreeURL -UseBasicParsing | ConvertFrom-Json | Select-Object -ExpandProperty tree
+ try {
+ # Retrieve the list of files in the repo at that particular commit point and store them in the RepoFiles hash
+ $Data = Invoke-WebRequest $RepoTreeURL -UseBasicParsing | ConvertFrom-Json | Select-Object -ExpandProperty tree
- foreach ($file in $Data) {
- $Extension = [System.IO.Path]::GetExtension($file.path)
+ foreach ($file in $Data) {
+ $Extension = [System.IO.Path]::GetExtension($file.path)
- if ($CodeExtensions.Contains($Extension)) {
- $RepoFiles[$file.path] = 1
+ if ($CodeExtensions.Contains($Extension)) {
+ $RepoFiles[$file.path] = 1
+ }
}
}
+ catch {
+ Write-Host "Problems downloading the list of files from the repo. Url used: $RepoTreeURL . Execution will proceed without caching."
+ }
}
- catch {
- Write-PipelineTaskError "Problems downloading the list of files from the repo. Url used: $RepoTreeURL"
- Write-Host $_
- ExitWithExitCode 1
+ elseif ($GHRepoName -ne '' -or $GHCommit -ne '') {
+ Write-Host 'For using the http caching mechanism both GHRepoName and GHCommit should be informed.'
}
if (Test-Path $ExtractPath) {
Remove-Item $ExtractPath -Force -Recurse -ErrorAction SilentlyContinue
}
+ $ValidationFailures = 0
+
# Process each NuGet package in parallel
- $Jobs = @()
Get-ChildItem "$InputPath\*.symbols.nupkg" |
ForEach-Object {
- $Jobs += Start-Job -ScriptBlock $ValidatePackage -ArgumentList $_.FullName
+ Start-Job -ScriptBlock $ValidatePackage -ArgumentList $_.FullName | Out-Null
+ $NumJobs = @(Get-Job -State 'Running').Count
+
+ while ($NumJobs -ge $MaxParallelJobs) {
+ Write-Host "There are $NumJobs validation jobs running right now. Waiting $SecondsBetweenLoadChecks seconds to check again."
+ sleep $SecondsBetweenLoadChecks
+ $NumJobs = @(Get-Job -State 'Running').Count
+ }
+
+ foreach ($Job in @(Get-Job -State 'Completed')) {
+ $jobResult = Wait-Job -Id $Job.Id | Receive-Job
+ CheckJobResult $jobResult.result $jobResult.packagePath ([ref]$ValidationFailures) -LogErrors
+ Remove-Job -Id $Job.Id
+ }
}
- foreach ($Job in $Jobs) {
- Wait-Job -Id $Job.Id | Receive-Job
+ foreach ($Job in @(Get-Job)) {
+ $jobResult = Wait-Job -Id $Job.Id | Receive-Job
+ CheckJobResult $jobResult.result $jobResult.packagePath ([ref]$ValidationFailures)
+ Remove-Job -Id $Job.Id
+ }
+ if ($ValidationFailures -gt 0) {
+ Write-PipelineTelemetryError -Category 'SourceLink' -Message "$ValidationFailures package(s) failed validation."
+ ExitWithExitCode 1
}
}
function InstallSourcelinkCli {
- $sourcelinkCliPackageName = "sourcelink"
+ $sourcelinkCliPackageName = 'sourcelink'
$dotnetRoot = InitializeDotNetCli -install:$true
$dotnet = "$dotnetRoot\dotnet.exe"
@@ -209,7 +259,7 @@ function InstallSourcelinkCli {
}
else {
Write-Host "Installing SourceLink CLI version $sourcelinkCliVersion..."
- Write-Host "You may need to restart your command window if this is the first dotnet tool you have installed."
+ Write-Host 'You may need to restart your command window if this is the first dotnet tool you have installed.'
& "$dotnet" tool install $sourcelinkCliPackageName --version $sourcelinkCliVersion --verbosity "minimal" --global
}
}
@@ -220,8 +270,8 @@ try {
ValidateSourceLinkLinks
}
catch {
- Write-Host $_
Write-Host $_.Exception
Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'SourceLink' -Message $_
ExitWithExitCode 1
}
diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1
index d5ec51b150f..99bf28cd5c1 100644
--- a/eng/common/post-build/symbols-validation.ps1
+++ b/eng/common/post-build/symbols-validation.ps1
@@ -1,127 +1,198 @@
param(
[Parameter(Mandatory=$true)][string] $InputPath, # Full path to directory where NuGet packages to be checked are stored
[Parameter(Mandatory=$true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation
- [Parameter(Mandatory=$true)][string] $DotnetSymbolVersion # Version of dotnet symbol to use
+ [Parameter(Mandatory=$true)][string] $DotnetSymbolVersion, # Version of dotnet symbol to use
+ [Parameter(Mandatory=$false)][switch] $ContinueOnError, # If we should keep checking symbols after an error
+ [Parameter(Mandatory=$false)][switch] $Clean # Clean extracted symbols directory after checking symbols
)
-. $PSScriptRoot\post-build-utils.ps1
+# Maximum number of jobs to run in parallel
+$MaxParallelJobs = 6
-Add-Type -AssemblyName System.IO.Compression.FileSystem
+# Max number of retries
+$MaxRetry = 5
-function FirstMatchingSymbolDescriptionOrDefault {
- param(
- [string] $FullPath, # Full path to the module that has to be checked
- [string] $TargetServerParam, # Parameter to pass to `Symbol Tool` indicating the server to lookup for symbols
- [string] $SymbolsPath
- )
-
- $FileName = [System.IO.Path]::GetFileName($FullPath)
- $Extension = [System.IO.Path]::GetExtension($FullPath)
-
- # Those below are potential symbol files that the `dotnet symbol` might
- # return. Which one will be returned depend on the type of file we are
- # checking and which type of file was uploaded.
-
- # The file itself is returned
- $SymbolPath = $SymbolsPath + "\" + $FileName
-
- # PDB file for the module
- $PdbPath = $SymbolPath.Replace($Extension, ".pdb")
-
- # PDB file for R2R module (created by crossgen)
- $NGenPdb = $SymbolPath.Replace($Extension, ".ni.pdb")
-
- # DBG file for a .so library
- $SODbg = $SymbolPath.Replace($Extension, ".so.dbg")
-
- # DWARF file for a .dylib
- $DylibDwarf = $SymbolPath.Replace($Extension, ".dylib.dwarf")
-
- $dotnetsymbolExe = "$env:USERPROFILE\.dotnet\tools"
- $dotnetsymbolExe = Resolve-Path "$dotnetsymbolExe\dotnet-symbol.exe"
+# Wait time between check for system load
+$SecondsBetweenLoadChecks = 10
- & $dotnetsymbolExe --symbols --modules --windows-pdbs $TargetServerParam $FullPath -o $SymbolsPath | Out-Null
+# Set error codes
+Set-Variable -Name "ERROR_BADEXTRACT" -Option Constant -Value -1
+Set-Variable -Name "ERROR_FILEDOESNOTEXIST" -Option Constant -Value -2
- if (Test-Path $PdbPath) {
- return "PDB"
- }
- elseif (Test-Path $NGenPdb) {
- return "NGen PDB"
- }
- elseif (Test-Path $SODbg) {
- return "DBG for SO"
- }
- elseif (Test-Path $DylibDwarf) {
- return "Dwarf for Dylib"
- }
- elseif (Test-Path $SymbolPath) {
- return "Module"
- }
- else {
- return $null
- }
-}
-
-function CountMissingSymbols {
+$CountMissingSymbols = {
param(
[string] $PackagePath # Path to a NuGet package
)
+ . $using:PSScriptRoot\..\tools.ps1
+
+ Add-Type -AssemblyName System.IO.Compression.FileSystem
+
+ Write-Host "Validating $PackagePath "
+
# Ensure input file exist
if (!(Test-Path $PackagePath)) {
Write-PipelineTaskError "Input file does not exist: $PackagePath"
- ExitWithExitCode 1
+ return [pscustomobject]@{
+ result = $using:ERROR_FILEDOESNOTEXIST
+ packagePath = $PackagePath
+ }
}
# Extensions for which we'll look for symbols
- $RelevantExtensions = @(".dll", ".exe", ".so", ".dylib")
+ $RelevantExtensions = @('.dll', '.exe', '.so', '.dylib')
# How many files are missing symbol information
$MissingSymbols = 0
$PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)
$PackageGuid = New-Guid
- $ExtractPath = Join-Path -Path $ExtractPath -ChildPath $PackageGuid
- $SymbolsPath = Join-Path -Path $ExtractPath -ChildPath "Symbols"
+ $ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageGuid
+ $SymbolsPath = Join-Path -Path $ExtractPath -ChildPath 'Symbols'
- [System.IO.Compression.ZipFile]::ExtractToDirectory($PackagePath, $ExtractPath)
+ try {
+ [System.IO.Compression.ZipFile]::ExtractToDirectory($PackagePath, $ExtractPath)
+ }
+ catch {
+ Write-Host "Something went wrong extracting $PackagePath"
+ Write-Host $_
+ return [pscustomobject]@{
+ result = $using:ERROR_BADEXTRACT
+ packagePath = $PackagePath
+ }
+ }
Get-ChildItem -Recurse $ExtractPath |
Where-Object {$RelevantExtensions -contains $_.Extension} |
ForEach-Object {
- if ($_.FullName -Match "\\ref\\") {
- Write-Host "`t Ignoring reference assembly file" $_.FullName
+ $FileName = $_.FullName
+ if ($FileName -Match '\\ref\\') {
+ Write-Host "`t Ignoring reference assembly file " $FileName
return
}
- $SymbolsOnMSDL = FirstMatchingSymbolDescriptionOrDefault $_.FullName "--microsoft-symbol-server" $SymbolsPath
- $SymbolsOnSymWeb = FirstMatchingSymbolDescriptionOrDefault $_.FullName "--internal-server" $SymbolsPath
+ $FirstMatchingSymbolDescriptionOrDefault = {
+ param(
+ [string] $FullPath, # Full path to the module that has to be checked
+ [string] $TargetServerParam, # Parameter to pass to `Symbol Tool` indicating the server to lookup for symbols
+ [string] $SymbolsPath
+ )
+
+ $FileName = [System.IO.Path]::GetFileName($FullPath)
+ $Extension = [System.IO.Path]::GetExtension($FullPath)
+
+ # Those below are potential symbol files that the `dotnet symbol` might
+ # return. Which one will be returned depend on the type of file we are
+ # checking and which type of file was uploaded.
+
+ # The file itself is returned
+ $SymbolPath = $SymbolsPath + '\' + $FileName
+
+ # PDB file for the module
+ $PdbPath = $SymbolPath.Replace($Extension, '.pdb')
+
+ # PDB file for R2R module (created by crossgen)
+ $NGenPdb = $SymbolPath.Replace($Extension, '.ni.pdb')
+
+ # DBG file for a .so library
+ $SODbg = $SymbolPath.Replace($Extension, '.so.dbg')
+
+ # DWARF file for a .dylib
+ $DylibDwarf = $SymbolPath.Replace($Extension, '.dylib.dwarf')
+
+ $dotnetSymbolExe = "$env:USERPROFILE\.dotnet\tools"
+ $dotnetSymbolExe = Resolve-Path "$dotnetSymbolExe\dotnet-symbol.exe"
+
+ $totalRetries = 0
+
+ while ($totalRetries -lt $using:MaxRetry) {
+ # Save the output and get diagnostic output
+ $output = & $dotnetSymbolExe --symbols --modules --windows-pdbs $TargetServerParam $FullPath -o $SymbolsPath --diagnostics | Out-String
+
+ if (Test-Path $PdbPath) {
+ return 'PDB'
+ }
+ elseif (Test-Path $NGenPdb) {
+ return 'NGen PDB'
+ }
+ elseif (Test-Path $SODbg) {
+ return 'DBG for SO'
+ }
+ elseif (Test-Path $DylibDwarf) {
+ return 'Dwarf for Dylib'
+ }
+ elseif (Test-Path $SymbolPath) {
+ return 'Module'
+ }
+ elseif ($output.Contains("503 Service Unavailable")) {
+ # If we got a 503 error, we should retry.
+ $totalRetries++
+ }
+ else {
+ return $null
+ }
+ }
+
+ return $null
+ }
+
+ $SymbolsOnMSDL = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--microsoft-symbol-server' $SymbolsPath
+ $SymbolsOnSymWeb = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--internal-server' $SymbolsPath
- Write-Host -NoNewLine "`t Checking file" $_.FullName "... "
+ Write-Host -NoNewLine "`t Checking file " $FileName "... "
if ($SymbolsOnMSDL -ne $null -and $SymbolsOnSymWeb -ne $null) {
- Write-Host "Symbols found on MSDL (" $SymbolsOnMSDL ") and SymWeb (" $SymbolsOnSymWeb ")"
+ Write-Host "Symbols found on MSDL ($SymbolsOnMSDL) and SymWeb ($SymbolsOnSymWeb)"
}
else {
$MissingSymbols++
if ($SymbolsOnMSDL -eq $null -and $SymbolsOnSymWeb -eq $null) {
- Write-Host "No symbols found on MSDL or SymWeb!"
+ Write-Host 'No symbols found on MSDL or SymWeb!'
}
else {
if ($SymbolsOnMSDL -eq $null) {
- Write-Host "No symbols found on MSDL!"
+ Write-Host 'No symbols found on MSDL!'
}
else {
- Write-Host "No symbols found on SymWeb!"
+ Write-Host 'No symbols found on SymWeb!'
}
}
}
}
+ if ($using:Clean) {
+ Remove-Item $ExtractPath -Recurse -Force
+ }
+
Pop-Location
- return $MissingSymbols
+ return [pscustomobject]@{
+ result = $MissingSymbols
+ packagePath = $PackagePath
+ }
+}
+
+function CheckJobResult(
+ $result,
+ $packagePath,
+ [ref]$DupedSymbols,
+ [ref]$TotalFailures) {
+ if ($result -eq $ERROR_BADEXTRACT) {
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$packagePath has duplicated symbol files"
+ $DupedSymbols.Value++
+ }
+ elseif ($result -eq $ERROR_FILEDOESNOTEXIST) {
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$packagePath does not exist"
+ $TotalFailures.Value++
+ }
+ elseif ($result -gt '0') {
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "Missing symbols for $result modules in the package $packagePath"
+ $TotalFailures.Value++
+ }
+ else {
+ Write-Host "All symbols verified for package $packagePath"
+ }
}
function CheckSymbolsAvailable {
@@ -129,61 +200,97 @@ function CheckSymbolsAvailable {
Remove-Item $ExtractPath -Force -Recurse -ErrorAction SilentlyContinue
}
+ $TotalFailures = 0
+ $DupedSymbols = 0
+
Get-ChildItem "$InputPath\*.nupkg" |
ForEach-Object {
$FileName = $_.Name
-
+ $FullName = $_.FullName
+
# These packages from Arcade-Services include some native libraries that
# our current symbol uploader can't handle. Below is a workaround until
# we get issue: https://github.com/dotnet/arcade/issues/2457 sorted.
- if ($FileName -Match "Microsoft\.DotNet\.Darc\.") {
+ if ($FileName -Match 'Microsoft\.DotNet\.Darc\.') {
Write-Host "Ignoring Arcade-services file: $FileName"
Write-Host
return
}
- elseif ($FileName -Match "Microsoft\.DotNet\.Maestro\.Tasks\.") {
+ elseif ($FileName -Match 'Microsoft\.DotNet\.Maestro\.Tasks\.') {
Write-Host "Ignoring Arcade-services file: $FileName"
Write-Host
return
}
-
- Write-Host "Validating $FileName "
- $Status = CountMissingSymbols "$InputPath\$FileName"
-
- if ($Status -ne 0) {
- Write-PipelineTaskError "Missing symbols for $Status modules in the package $FileName"
- ExitWithExitCode $exitCode
+
+ Start-Job -ScriptBlock $CountMissingSymbols -ArgumentList $FullName | Out-Null
+
+ $NumJobs = @(Get-Job -State 'Running').Count
+
+ while ($NumJobs -ge $MaxParallelJobs) {
+ Write-Host "There are $NumJobs validation jobs running right now. Waiting $SecondsBetweenLoadChecks seconds to check again."
+ sleep $SecondsBetweenLoadChecks
+ $NumJobs = @(Get-Job -State 'Running').Count
}
+ foreach ($Job in @(Get-Job -State 'Completed')) {
+ $jobResult = Wait-Job -Id $Job.Id | Receive-Job
+ CheckJobResult $jobResult.result $jobResult.packagePath ([ref]$DupedSymbols) ([ref]$TotalFailures)
+ Remove-Job -Id $Job.Id
+ }
Write-Host
}
+
+ foreach ($Job in @(Get-Job)) {
+ $jobResult = Wait-Job -Id $Job.Id | Receive-Job
+ CheckJobResult $jobResult.result $jobResult.packagePath ([ref]$DupedSymbols) ([ref]$TotalFailures)
+ }
+
+ if ($TotalFailures -gt 0 -or $DupedSymbols -gt 0) {
+ if ($TotalFailures -gt 0) {
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "Symbols missing for $TotalFailures packages"
+ }
+
+ if ($DupedSymbols -gt 0) {
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$DupedSymbols packages had duplicated symbol files"
+ }
+
+ ExitWithExitCode 1
+ }
+ else {
+ Write-Host "All symbols validated!"
+ }
}
-function Installdotnetsymbol {
- $dotnetsymbolPackageName = "dotnet-symbol"
+function InstallDotnetSymbol {
+ $dotnetSymbolPackageName = 'dotnet-symbol'
$dotnetRoot = InitializeDotNetCli -install:$true
$dotnet = "$dotnetRoot\dotnet.exe"
$toolList = & "$dotnet" tool list --global
- if (($toolList -like "*$dotnetsymbolPackageName*") -and ($toolList -like "*$dotnetsymbolVersion*")) {
- Write-Host "dotnet-symbol version $dotnetsymbolVersion is already installed."
+ if (($toolList -like "*$dotnetSymbolPackageName*") -and ($toolList -like "*$dotnetSymbolVersion*")) {
+ Write-Host "dotnet-symbol version $dotnetSymbolVersion is already installed."
}
else {
- Write-Host "Installing dotnet-symbol version $dotnetsymbolVersion..."
- Write-Host "You may need to restart your command window if this is the first dotnet tool you have installed."
- & "$dotnet" tool install $dotnetsymbolPackageName --version $dotnetsymbolVersion --verbosity "minimal" --global
+ Write-Host "Installing dotnet-symbol version $dotnetSymbolVersion..."
+ Write-Host 'You may need to restart your command window if this is the first dotnet tool you have installed.'
+ & "$dotnet" tool install $dotnetSymbolPackageName --version $dotnetSymbolVersion --verbosity "minimal" --global
}
}
try {
- Installdotnetsymbol
+ . $PSScriptRoot\post-build-utils.ps1
+
+ InstallDotnetSymbol
+
+ foreach ($Job in @(Get-Job)) {
+ Remove-Job -Id $Job.Id
+ }
CheckSymbolsAvailable
}
catch {
- Write-Host $_
- Write-Host $_.Exception
Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message $_
ExitWithExitCode 1
}
diff --git a/eng/common/post-build/trigger-subscriptions.ps1 b/eng/common/post-build/trigger-subscriptions.ps1
index 926d5b45513..55dea518ac5 100644
--- a/eng/common/post-build/trigger-subscriptions.ps1
+++ b/eng/common/post-build/trigger-subscriptions.ps1
@@ -2,56 +2,63 @@ param(
[Parameter(Mandatory=$true)][string] $SourceRepo,
[Parameter(Mandatory=$true)][int] $ChannelId,
[Parameter(Mandatory=$true)][string] $MaestroApiAccessToken,
- [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = "https://maestro-prod.westus2.cloudapp.azure.com",
- [Parameter(Mandatory=$false)][string] $MaestroApiVersion = "2019-01-16"
+ [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro-prod.westus2.cloudapp.azure.com',
+ [Parameter(Mandatory=$false)][string] $MaestroApiVersion = '2019-01-16'
)
-. $PSScriptRoot\post-build-utils.ps1
+try {
+ . $PSScriptRoot\post-build-utils.ps1
-# Get all the $SourceRepo subscriptions
-$normalizedSourceRepo = $SourceRepo.Replace('dnceng@', '')
-$subscriptions = Get-MaestroSubscriptions -SourceRepository $normalizedSourceRepo -ChannelId $ChannelId
+ # Get all the $SourceRepo subscriptions
+ $normalizedSourceRepo = $SourceRepo.Replace('dnceng@', '')
+ $subscriptions = Get-MaestroSubscriptions -SourceRepository $normalizedSourceRepo -ChannelId $ChannelId
-if (!$subscriptions) {
- Write-Host "No subscriptions found for source repo '$normalizedSourceRepo' in channel '$ChannelId'"
- ExitWithExitCode 0
-}
+ if (!$subscriptions) {
+ Write-PipelineTelemetryError -Category 'TriggerSubscriptions' -Message "No subscriptions found for source repo '$normalizedSourceRepo' in channel '$ChannelId'"
+ ExitWithExitCode 0
+ }
-$subscriptionsToTrigger = New-Object System.Collections.Generic.List[string]
-$failedTriggeredSubscription = $false
+ $subscriptionsToTrigger = New-Object System.Collections.Generic.List[string]
+ $failedTriggeredSubscription = $false
-# Get all enabled subscriptions that need dependency flow on 'everyBuild'
-foreach ($subscription in $subscriptions) {
- if ($subscription.enabled -and $subscription.policy.updateFrequency -like 'everyBuild' -and $subscription.channel.id -eq $ChannelId) {
- Write-Host "Should trigger this subscription: $subscription.id"
- [void]$subscriptionsToTrigger.Add($subscription.id)
+ # Get all enabled subscriptions that need dependency flow on 'everyBuild'
+ foreach ($subscription in $subscriptions) {
+ if ($subscription.enabled -and $subscription.policy.updateFrequency -like 'everyBuild' -and $subscription.channel.id -eq $ChannelId) {
+ Write-Host "Should trigger this subscription: ${$subscription.id}"
+ [void]$subscriptionsToTrigger.Add($subscription.id)
+ }
}
-}
-foreach ($subscriptionToTrigger in $subscriptionsToTrigger) {
- try {
- Write-Host "Triggering subscription '$subscriptionToTrigger'."
-
- Trigger-Subscription -SubscriptionId $subscriptionToTrigger
-
- Write-Host "done."
- }
- catch
- {
- Write-Host "There was an error while triggering subscription '$subscriptionToTrigger'"
- Write-Host $_
- Write-Host $_.ScriptStackTrace
- $failedTriggeredSubscription = $true
+ foreach ($subscriptionToTrigger in $subscriptionsToTrigger) {
+ try {
+ Write-Host "Triggering subscription '$subscriptionToTrigger'."
+
+ Trigger-Subscription -SubscriptionId $subscriptionToTrigger
+
+ Write-Host 'done.'
+ }
+ catch
+ {
+ Write-Host "There was an error while triggering subscription '$subscriptionToTrigger'"
+ Write-Host $_
+ Write-Host $_.ScriptStackTrace
+ $failedTriggeredSubscription = $true
+ }
}
-}
-if ($subscriptionsToTrigger.Count -eq 0) {
- Write-Host "No subscription matched source repo '$normalizedSourceRepo' and channel ID '$ChannelId'."
+ if ($subscriptionsToTrigger.Count -eq 0) {
+ Write-Host "No subscription matched source repo '$normalizedSourceRepo' and channel ID '$ChannelId'."
+ }
+ elseif ($failedTriggeredSubscription) {
+ Write-PipelineTelemetryError -Category 'TriggerSubscriptions' -Message 'At least one subscription failed to be triggered...'
+ ExitWithExitCode 1
+ }
+ else {
+ Write-Host 'All subscriptions were triggered successfully!'
+ }
}
-elseif ($failedTriggeredSubscription) {
- Write-Host "At least one subscription failed to be triggered..."
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'TriggerSubscriptions' -Message $_
ExitWithExitCode 1
}
-else {
- Write-Host "All subscriptions were triggered successfully!"
-}
diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1
index d0eec5163ef..f55c43c6f47 100644
--- a/eng/common/sdk-task.ps1
+++ b/eng/common/sdk-task.ps1
@@ -1,8 +1,8 @@
[CmdletBinding(PositionalBinding=$false)]
Param(
- [string] $configuration = "Debug",
+ [string] $configuration = 'Debug',
[string] $task,
- [string] $verbosity = "minimal",
+ [string] $verbosity = 'minimal',
[string] $msbuildEngine = $null,
[switch] $restore,
[switch] $prepareMachine,
@@ -32,7 +32,7 @@ function Print-Usage() {
}
function Build([string]$target) {
- $logSuffix = if ($target -eq "Execute") { "" } else { ".$target" }
+ $logSuffix = if ($target -eq 'Execute') { '' } else { ".$target" }
$log = Join-Path $LogDir "$task$logSuffix.binlog"
$outputPath = Join-Path $ToolsetDir "$task\\"
@@ -42,37 +42,55 @@ function Build([string]$target) {
/p:Configuration=$configuration `
/p:RepoRoot=$RepoRoot `
/p:BaseIntermediateOutputPath=$outputPath `
+ /v:$verbosity `
@properties
}
try {
- if ($help -or (($null -ne $properties) -and ($properties.Contains("/help") -or $properties.Contains("/?")))) {
+ if ($help -or (($null -ne $properties) -and ($properties.Contains('/help') -or $properties.Contains('/?')))) {
Print-Usage
exit 0
}
if ($task -eq "") {
- Write-Host "Missing required parameter '-task '" -ForegroundColor Red
+ Write-PipelineTelemetryError -Category 'Build' -Message "Missing required parameter '-task '" -ForegroundColor Red
Print-Usage
ExitWithExitCode 1
}
+ if( $msbuildEngine -eq "vs") {
+ # Ensure desktop MSBuild is available for sdk tasks.
+ if( -not ($GlobalJson.tools.PSObject.Properties.Name -contains "vs" )) {
+ $GlobalJson.tools | Add-Member -Name "vs" -Value (ConvertFrom-Json "{ `"version`": `"16.5`" }") -MemberType NoteProperty
+ }
+ if( -not ($GlobalJson.tools.PSObject.Properties.Name -match "xcopy-msbuild" )) {
+ $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "16.8.0-preview3" -MemberType NoteProperty
+ }
+ if ($GlobalJson.tools."xcopy-msbuild".Trim() -ine "none") {
+ $xcopyMSBuildToolsFolder = InitializeXCopyMSBuild $GlobalJson.tools."xcopy-msbuild" -install $true
+ }
+ if ($xcopyMSBuildToolsFolder -eq $null) {
+ throw 'Unable to get xcopy downloadable version of msbuild'
+ }
+
+ $global:_MSBuildExe = "$($xcopyMSBuildToolsFolder)\MSBuild\Current\Bin\MSBuild.exe"
+ }
+
$taskProject = GetSdkTaskProject $task
if (!(Test-Path $taskProject)) {
- Write-Host "Unknown task: $task" -ForegroundColor Red
+ Write-PipelineTelemetryError -Category 'Build' -Message "Unknown task: $task" -ForegroundColor Red
ExitWithExitCode 1
}
if ($restore) {
- Build "Restore"
+ Build 'Restore'
}
- Build "Execute"
+ Build 'Execute'
}
catch {
- Write-Host $_
- Write-Host $_.Exception
Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'Build' -Message $_
ExitWithExitCode 1
}
diff --git a/eng/common/sdl/execute-all-sdl-tools.ps1 b/eng/common/sdl/execute-all-sdl-tools.ps1
index aab7589f2cc..b681d797cda 100644
--- a/eng/common/sdl/execute-all-sdl-tools.ps1
+++ b/eng/common/sdl/execute-all-sdl-tools.ps1
@@ -1,99 +1,120 @@
Param(
- [string] $GuardianPackageName, # Required: the name of guardian CLI package (not needed if GuardianCliLocation is specified)
- [string] $NugetPackageDirectory, # Required: directory where NuGet packages are installed (not needed if GuardianCliLocation is specified)
- [string] $GuardianCliLocation, # Optional: Direct location of Guardian CLI executable if GuardianPackageName & NugetPackageDirectory are not specified
- [string] $Repository=$env:BUILD_REPOSITORY_NAME, # Required: the name of the repository (e.g. dotnet/arcade)
- [string] $BranchName=$env:BUILD_SOURCEBRANCH, # Optional: name of branch or version of gdn settings; defaults to master
- [string] $SourceDirectory=$env:BUILD_SOURCESDIRECTORY, # Required: the directory where source files are located
- [string] $ArtifactsDirectory = (Join-Path $env:BUILD_SOURCESDIRECTORY ("artifacts")), # Required: the directory where build artifacts are located
- [string] $AzureDevOpsAccessToken, # Required: access token for dnceng; should be provided via KeyVault
- [string[]] $SourceToolsList, # Optional: list of SDL tools to run on source code
- [string[]] $ArtifactToolsList, # Optional: list of SDL tools to run on built artifacts
- [bool] $TsaPublish=$False, # Optional: true will publish results to TSA; only set to true after onboarding to TSA; TSA is the automated framework used to upload test results as bugs.
- [string] $TsaBranchName=$env:BUILD_SOURCEBRANCH, # Optional: required for TSA publish; defaults to $(Build.SourceBranchName); TSA is the automated framework used to upload test results as bugs.
- [string] $TsaRepositoryName=$env:BUILD_REPOSITORY_NAME, # Optional: TSA repository name; will be generated automatically if not submitted; TSA is the automated framework used to upload test results as bugs.
- [string] $BuildNumber=$env:BUILD_BUILDNUMBER, # Optional: required for TSA publish; defaults to $(Build.BuildNumber)
- [bool] $UpdateBaseline=$False, # Optional: if true, will update the baseline in the repository; should only be run after fixing any issues which need to be fixed
- [bool] $TsaOnboard=$False, # Optional: if true, will onboard the repository to TSA; should only be run once; TSA is the automated framework used to upload test results as bugs.
- [string] $TsaInstanceUrl, # Optional: only needed if TsaOnboard or TsaPublish is true; the instance-url registered with TSA; TSA is the automated framework used to upload test results as bugs.
- [string] $TsaCodebaseName, # Optional: only needed if TsaOnboard or TsaPublish is true; the name of the codebase registered with TSA; TSA is the automated framework used to upload test results as bugs.
- [string] $TsaProjectName, # Optional: only needed if TsaOnboard or TsaPublish is true; the name of the project registered with TSA; TSA is the automated framework used to upload test results as bugs.
- [string] $TsaNotificationEmail, # Optional: only needed if TsaOnboard is true; the email(s) which will receive notifications of TSA bug filings (e.g. alias@microsoft.com); TSA is the automated framework used to upload test results as bugs.
- [string] $TsaCodebaseAdmin, # Optional: only needed if TsaOnboard is true; the aliases which are admins of the TSA codebase (e.g. DOMAIN\alias); TSA is the automated framework used to upload test results as bugs.
- [string] $TsaBugAreaPath, # Optional: only needed if TsaOnboard is true; the area path where TSA will file bugs in AzDO; TSA is the automated framework used to upload test results as bugs.
- [string] $TsaIterationPath, # Optional: only needed if TsaOnboard is true; the iteration path where TSA will file bugs in AzDO; TSA is the automated framework used to upload test results as bugs.
- [string] $GuardianLoggerLevel="Standard", # Optional: the logger level for the Guardian CLI; options are Trace, Verbose, Standard, Warning, and Error
- [string[]] $CrScanAdditionalRunConfigParams, # Optional: Additional Params to custom build a CredScan run config in the format @("xyz:abc","sdf:1")
- [string[]] $PoliCheckAdditionalRunConfigParams # Optional: Additional Params to custom build a Policheck run config in the format @("xyz:abc","sdf:1")
+ [string] $GuardianPackageName, # Required: the name of guardian CLI package (not needed if GuardianCliLocation is specified)
+ [string] $NugetPackageDirectory, # Required: directory where NuGet packages are installed (not needed if GuardianCliLocation is specified)
+ [string] $GuardianCliLocation, # Optional: Direct location of Guardian CLI executable if GuardianPackageName & NugetPackageDirectory are not specified
+ [string] $Repository=$env:BUILD_REPOSITORY_NAME, # Required: the name of the repository (e.g. dotnet/arcade)
+ [string] $BranchName=$env:BUILD_SOURCEBRANCH, # Optional: name of branch or version of gdn settings; defaults to master
+ [string] $SourceDirectory=$env:BUILD_SOURCESDIRECTORY, # Required: the directory where source files are located
+ [string] $ArtifactsDirectory = (Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY ('artifacts')), # Required: the directory where build artifacts are located
+ [string] $AzureDevOpsAccessToken, # Required: access token for dnceng; should be provided via KeyVault
+ [string[]] $SourceToolsList, # Optional: list of SDL tools to run on source code
+ [string[]] $ArtifactToolsList, # Optional: list of SDL tools to run on built artifacts
+ [bool] $TsaPublish=$False, # Optional: true will publish results to TSA; only set to true after onboarding to TSA; TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaBranchName=$env:BUILD_SOURCEBRANCH, # Optional: required for TSA publish; defaults to $(Build.SourceBranchName); TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaRepositoryName=$env:BUILD_REPOSITORY_NAME, # Optional: TSA repository name; will be generated automatically if not submitted; TSA is the automated framework used to upload test results as bugs.
+ [string] $BuildNumber=$env:BUILD_BUILDNUMBER, # Optional: required for TSA publish; defaults to $(Build.BuildNumber)
+ [bool] $UpdateBaseline=$False, # Optional: if true, will update the baseline in the repository; should only be run after fixing any issues which need to be fixed
+ [bool] $TsaOnboard=$False, # Optional: if true, will onboard the repository to TSA; should only be run once; TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaInstanceUrl, # Optional: only needed if TsaOnboard or TsaPublish is true; the instance-url registered with TSA; TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaCodebaseName, # Optional: only needed if TsaOnboard or TsaPublish is true; the name of the codebase registered with TSA; TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaProjectName, # Optional: only needed if TsaOnboard or TsaPublish is true; the name of the project registered with TSA; TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaNotificationEmail, # Optional: only needed if TsaOnboard is true; the email(s) which will receive notifications of TSA bug filings (e.g. alias@microsoft.com); TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaCodebaseAdmin, # Optional: only needed if TsaOnboard is true; the aliases which are admins of the TSA codebase (e.g. DOMAIN\alias); TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaBugAreaPath, # Optional: only needed if TsaOnboard is true; the area path where TSA will file bugs in AzDO; TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaIterationPath, # Optional: only needed if TsaOnboard is true; the iteration path where TSA will file bugs in AzDO; TSA is the automated framework used to upload test results as bugs.
+ [string] $GuardianLoggerLevel='Standard', # Optional: the logger level for the Guardian CLI; options are Trace, Verbose, Standard, Warning, and Error
+ [string[]] $CrScanAdditionalRunConfigParams, # Optional: Additional Params to custom build a CredScan run config in the format @("xyz:abc","sdf:1")
+ [string[]] $PoliCheckAdditionalRunConfigParams, # Optional: Additional Params to custom build a Policheck run config in the format @("xyz:abc","sdf:1")
+ [bool] $BreakOnFailure=$False # Optional: Fail the build if there were errors during the run
)
-$ErrorActionPreference = "Stop"
-Set-StrictMode -Version 2.0
-$LASTEXITCODE = 0
+try {
+ $ErrorActionPreference = 'Stop'
+ Set-StrictMode -Version 2.0
+ $disableConfigureToolsetImport = $true
+ $LASTEXITCODE = 0
-#Replace repo names to the format of org/repo
-if (!($Repository.contains('/'))) {
- $RepoName = $Repository -replace '(.*?)-(.*)', '$1/$2';
-}
-else{
- $RepoName = $Repository;
-}
+ # `tools.ps1` checks $ci to perform some actions. Since the SDL
+ # scripts don't necessarily execute in the same agent that run the
+ # build.ps1/sh script this variable isn't automatically set.
+ $ci = $true
+ . $PSScriptRoot\..\tools.ps1
-if ($GuardianPackageName) {
- $guardianCliLocation = Join-Path $NugetPackageDirectory (Join-Path $GuardianPackageName (Join-Path "tools" "guardian.cmd"))
-} else {
- $guardianCliLocation = $GuardianCliLocation
-}
+ #Replace repo names to the format of org/repo
+ if (!($Repository.contains('/'))) {
+ $RepoName = $Repository -replace '(.*?)-(.*)', '$1/$2';
+ }
+ else{
+ $RepoName = $Repository;
+ }
-$ValidPath = Test-Path $guardianCliLocation
+ if ($GuardianPackageName) {
+ $guardianCliLocation = Join-Path $NugetPackageDirectory (Join-Path $GuardianPackageName (Join-Path 'tools' 'guardian.cmd'))
+ } else {
+ $guardianCliLocation = $GuardianCliLocation
+ }
-if ($ValidPath -eq $False)
-{
- Write-Host "Invalid Guardian CLI Location."
- exit 1
-}
+ $workingDirectory = (Split-Path $SourceDirectory -Parent)
+ $ValidPath = Test-Path $guardianCliLocation
+
+ if ($ValidPath -eq $False)
+ {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message 'Invalid Guardian CLI Location.'
+ ExitWithExitCode 1
+ }
-& $(Join-Path $PSScriptRoot "init-sdl.ps1") -GuardianCliLocation $guardianCliLocation -Repository $RepoName -BranchName $BranchName -WorkingDirectory $ArtifactsDirectory -AzureDevOpsAccessToken $AzureDevOpsAccessToken -GuardianLoggerLevel $GuardianLoggerLevel
-$gdnFolder = Join-Path $ArtifactsDirectory ".gdn"
+ & $(Join-Path $PSScriptRoot 'init-sdl.ps1') -GuardianCliLocation $guardianCliLocation -Repository $RepoName -BranchName $BranchName -WorkingDirectory $workingDirectory -AzureDevOpsAccessToken $AzureDevOpsAccessToken -GuardianLoggerLevel $GuardianLoggerLevel
+ $gdnFolder = Join-Path $workingDirectory '.gdn'
-if ($TsaOnboard) {
- if ($TsaCodebaseName -and $TsaNotificationEmail -and $TsaCodebaseAdmin -and $TsaBugAreaPath) {
- Write-Host "$guardianCliLocation tsa-onboard --codebase-name `"$TsaCodebaseName`" --notification-alias `"$TsaNotificationEmail`" --codebase-admin `"$TsaCodebaseAdmin`" --instance-url `"$TsaInstanceUrl`" --project-name `"$TsaProjectName`" --area-path `"$TsaBugAreaPath`" --iteration-path `"$TsaIterationPath`" --working-directory $ArtifactsDirectory --logger-level $GuardianLoggerLevel"
- & $guardianCliLocation tsa-onboard --codebase-name "$TsaCodebaseName" --notification-alias "$TsaNotificationEmail" --codebase-admin "$TsaCodebaseAdmin" --instance-url "$TsaInstanceUrl" --project-name "$TsaProjectName" --area-path "$TsaBugAreaPath" --iteration-path "$TsaIterationPath" --working-directory $ArtifactsDirectory --logger-level $GuardianLoggerLevel
- if ($LASTEXITCODE -ne 0) {
- Write-Host "Guardian tsa-onboard failed with exit code $LASTEXITCODE."
- exit $LASTEXITCODE
+ if ($TsaOnboard) {
+ if ($TsaCodebaseName -and $TsaNotificationEmail -and $TsaCodebaseAdmin -and $TsaBugAreaPath) {
+ Write-Host "$guardianCliLocation tsa-onboard --codebase-name `"$TsaCodebaseName`" --notification-alias `"$TsaNotificationEmail`" --codebase-admin `"$TsaCodebaseAdmin`" --instance-url `"$TsaInstanceUrl`" --project-name `"$TsaProjectName`" --area-path `"$TsaBugAreaPath`" --iteration-path `"$TsaIterationPath`" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel"
+ & $guardianCliLocation tsa-onboard --codebase-name "$TsaCodebaseName" --notification-alias "$TsaNotificationEmail" --codebase-admin "$TsaCodebaseAdmin" --instance-url "$TsaInstanceUrl" --project-name "$TsaProjectName" --area-path "$TsaBugAreaPath" --iteration-path "$TsaIterationPath" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Guardian tsa-onboard failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
+ } else {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message 'Could not onboard to TSA -- not all required values ($TsaCodebaseName, $TsaNotificationEmail, $TsaCodebaseAdmin, $TsaBugAreaPath) were specified.'
+ ExitWithExitCode 1
}
- } else {
- Write-Host "Could not onboard to TSA -- not all required values ($$TsaCodebaseName, $$TsaNotificationEmail, $$TsaCodebaseAdmin, $$TsaBugAreaPath) were specified."
- exit 1
}
-}
-if ($ArtifactToolsList -and $ArtifactToolsList.Count -gt 0) {
- & $(Join-Path $PSScriptRoot "run-sdl.ps1") -GuardianCliLocation $guardianCliLocation -WorkingDirectory $ArtifactsDirectory -TargetDirectory $ArtifactsDirectory -GdnFolder $gdnFolder -ToolsList $ArtifactToolsList -AzureDevOpsAccessToken $AzureDevOpsAccessToken -UpdateBaseline $UpdateBaseline -GuardianLoggerLevel $GuardianLoggerLevel -CrScanAdditionalRunConfigParams $CrScanAdditionalRunConfigParams -PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams
-}
-if ($SourceToolsList -and $SourceToolsList.Count -gt 0) {
- & $(Join-Path $PSScriptRoot "run-sdl.ps1") -GuardianCliLocation $guardianCliLocation -WorkingDirectory $ArtifactsDirectory -TargetDirectory $SourceDirectory -GdnFolder $gdnFolder -ToolsList $SourceToolsList -AzureDevOpsAccessToken $AzureDevOpsAccessToken -UpdateBaseline $UpdateBaseline -GuardianLoggerLevel $GuardianLoggerLevel -CrScanAdditionalRunConfigParams $CrScanAdditionalRunConfigParams -PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams
-}
+ if ($ArtifactToolsList -and $ArtifactToolsList.Count -gt 0) {
+ & $(Join-Path $PSScriptRoot 'run-sdl.ps1') -GuardianCliLocation $guardianCliLocation -WorkingDirectory $workingDirectory -TargetDirectory $ArtifactsDirectory -GdnFolder $gdnFolder -ToolsList $ArtifactToolsList -AzureDevOpsAccessToken $AzureDevOpsAccessToken -UpdateBaseline $UpdateBaseline -GuardianLoggerLevel $GuardianLoggerLevel -CrScanAdditionalRunConfigParams $CrScanAdditionalRunConfigParams -PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams
+ }
+ if ($SourceToolsList -and $SourceToolsList.Count -gt 0) {
+ & $(Join-Path $PSScriptRoot 'run-sdl.ps1') -GuardianCliLocation $guardianCliLocation -WorkingDirectory $workingDirectory -TargetDirectory $SourceDirectory -GdnFolder $gdnFolder -ToolsList $SourceToolsList -AzureDevOpsAccessToken $AzureDevOpsAccessToken -UpdateBaseline $UpdateBaseline -GuardianLoggerLevel $GuardianLoggerLevel -CrScanAdditionalRunConfigParams $CrScanAdditionalRunConfigParams -PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams
+ }
-if ($UpdateBaseline) {
- & (Join-Path $PSScriptRoot "push-gdn.ps1") -Repository $RepoName -BranchName $BranchName -GdnFolder $GdnFolder -AzureDevOpsAccessToken $AzureDevOpsAccessToken -PushReason "Update baseline"
-}
+ if ($UpdateBaseline) {
+ & (Join-Path $PSScriptRoot 'push-gdn.ps1') -Repository $RepoName -BranchName $BranchName -GdnFolder $GdnFolder -AzureDevOpsAccessToken $AzureDevOpsAccessToken -PushReason 'Update baseline'
+ }
-if ($TsaPublish) {
- if ($TsaBranchName -and $BuildNumber) {
- if (-not $TsaRepositoryName) {
- $TsaRepositoryName = "$($Repository)-$($BranchName)"
+ if ($TsaPublish) {
+ if ($TsaBranchName -and $BuildNumber) {
+ if (-not $TsaRepositoryName) {
+ $TsaRepositoryName = "$($Repository)-$($BranchName)"
+ }
+ Write-Host "$guardianCliLocation tsa-publish --all-tools --repository-name `"$TsaRepositoryName`" --branch-name `"$TsaBranchName`" --build-number `"$BuildNumber`" --codebase-name `"$TsaCodebaseName`" --notification-alias `"$TsaNotificationEmail`" --codebase-admin `"$TsaCodebaseAdmin`" --instance-url `"$TsaInstanceUrl`" --project-name `"$TsaProjectName`" --area-path `"$TsaBugAreaPath`" --iteration-path `"$TsaIterationPath`" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel"
+ & $guardianCliLocation tsa-publish --all-tools --repository-name "$TsaRepositoryName" --branch-name "$TsaBranchName" --build-number "$BuildNumber" --onboard $True --codebase-name "$TsaCodebaseName" --notification-alias "$TsaNotificationEmail" --codebase-admin "$TsaCodebaseAdmin" --instance-url "$TsaInstanceUrl" --project-name "$TsaProjectName" --area-path "$TsaBugAreaPath" --iteration-path "$TsaIterationPath" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Guardian tsa-publish failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
+ } else {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message 'Could not publish to TSA -- not all required values ($TsaBranchName, $BuildNumber) were specified.'
+ ExitWithExitCode 1
}
- Write-Host "$guardianCliLocation tsa-publish --all-tools --repository-name `"$TsaRepositoryName`" --branch-name `"$TsaBranchName`" --build-number `"$BuildNumber`" --codebase-name `"$TsaCodebaseName`" --notification-alias `"$TsaNotificationEmail`" --codebase-admin `"$TsaCodebaseAdmin`" --instance-url `"$TsaInstanceUrl`" --project-name `"$TsaProjectName`" --area-path `"$TsaBugAreaPath`" --iteration-path `"$TsaIterationPath`" --working-directory $SourceDirectory --logger-level $GuardianLoggerLevel"
- & $guardianCliLocation tsa-publish --all-tools --repository-name "$TsaRepositoryName" --branch-name "$TsaBranchName" --build-number "$BuildNumber" --codebase-name "$TsaCodebaseName" --notification-alias "$TsaNotificationEmail" --codebase-admin "$TsaCodebaseAdmin" --instance-url "$TsaInstanceUrl" --project-name "$TsaProjectName" --area-path "$TsaBugAreaPath" --iteration-path "$TsaIterationPath" --working-directory $ArtifactsDirectory --logger-level $GuardianLoggerLevel
- if ($LASTEXITCODE -ne 0) {
- Write-Host "Guardian tsa-publish failed with exit code $LASTEXITCODE."
- exit $LASTEXITCODE
- }
- } else {
- Write-Host "Could not publish to TSA -- not all required values ($$TsaBranchName, $$BuildNumber) were specified."
- exit 1
}
+
+ if ($BreakOnFailure) {
+ Write-Host "Failing the build in case of breaking results..."
+ & $guardianCliLocation break
+ }
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
+ exit 1
}
diff --git a/eng/common/sdl/extract-artifact-packages.ps1 b/eng/common/sdl/extract-artifact-packages.ps1
index 1fdbb14329c..7f28d9c59ec 100644
--- a/eng/common/sdl/extract-artifact-packages.ps1
+++ b/eng/common/sdl/extract-artifact-packages.ps1
@@ -3,47 +3,12 @@ param(
[Parameter(Mandatory=$true)][string] $ExtractPath # Full path to directory where the packages will be extracted
)
-$ErrorActionPreference = "Stop"
+$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 2.0
-$ExtractPackage = {
- param(
- [string] $PackagePath # Full path to a NuGet package
- )
-
- if (!(Test-Path $PackagePath)) {
- Write-PipelineTaskError "Input file does not exist: $PackagePath"
- ExitWithExitCode 1
- }
-
- $RelevantExtensions = @(".dll", ".exe", ".pdb")
- Write-Host -NoNewLine "Extracting" ([System.IO.Path]::GetFileName($PackagePath)) "... "
-
- $PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)
- $ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageId
-
- Add-Type -AssemblyName System.IO.Compression.FileSystem
-
- [System.IO.Directory]::CreateDirectory($ExtractPath);
- try {
- $zip = [System.IO.Compression.ZipFile]::OpenRead($PackagePath)
+$disableConfigureToolsetImport = $true
- $zip.Entries |
- Where-Object {$RelevantExtensions -contains [System.IO.Path]::GetExtension($_.Name)} |
- ForEach-Object {
- $TargetFile = Join-Path -Path $ExtractPath -ChildPath $_.Name
-
- [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile, $true)
- }
- }
- catch {
-
- }
- finally {
- $zip.Dispose()
- }
- }
- function ExtractArtifacts {
+function ExtractArtifacts {
if (!(Test-Path $InputPath)) {
Write-Host "Input Path does not exist: $InputPath"
ExitWithExitCode 0
@@ -60,11 +25,56 @@ $ExtractPackage = {
}
try {
+ # `tools.ps1` checks $ci to perform some actions. Since the SDL
+ # scripts don't necessarily execute in the same agent that run the
+ # build.ps1/sh script this variable isn't automatically set.
+ $ci = $true
+ . $PSScriptRoot\..\tools.ps1
+
+ $ExtractPackage = {
+ param(
+ [string] $PackagePath # Full path to a NuGet package
+ )
+
+ if (!(Test-Path $PackagePath)) {
+ Write-PipelineTelemetryError -Category 'Build' -Message "Input file does not exist: $PackagePath"
+ ExitWithExitCode 1
+ }
+
+ $RelevantExtensions = @('.dll', '.exe', '.pdb')
+ Write-Host -NoNewLine 'Extracting ' ([System.IO.Path]::GetFileName($PackagePath)) '...'
+
+ $PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)
+ $ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageId
+
+ Add-Type -AssemblyName System.IO.Compression.FileSystem
+
+ [System.IO.Directory]::CreateDirectory($ExtractPath);
+
+ try {
+ $zip = [System.IO.Compression.ZipFile]::OpenRead($PackagePath)
+
+ $zip.Entries |
+ Where-Object {$RelevantExtensions -contains [System.IO.Path]::GetExtension($_.Name)} |
+ ForEach-Object {
+ $TargetFile = Join-Path -Path $ExtractPath -ChildPath $_.Name
+
+ [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile, $true)
+ }
+ }
+ catch {
+ Write-Host $_
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
+ ExitWithExitCode 1
+ }
+ finally {
+ $zip.Dispose()
+ }
+ }
Measure-Command { ExtractArtifacts }
}
catch {
Write-Host $_
- Write-Host $_.Exception
- Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
ExitWithExitCode 1
}
diff --git a/eng/common/sdl/init-sdl.ps1 b/eng/common/sdl/init-sdl.ps1
index 26e01c0673c..a68bf0b88ea 100644
--- a/eng/common/sdl/init-sdl.ps1
+++ b/eng/common/sdl/init-sdl.ps1
@@ -1,28 +1,37 @@
Param(
[string] $GuardianCliLocation,
[string] $Repository,
- [string] $BranchName="master",
+ [string] $BranchName='master',
[string] $WorkingDirectory,
[string] $AzureDevOpsAccessToken,
- [string] $GuardianLoggerLevel="Standard"
+ [string] $GuardianLoggerLevel='Standard'
)
-$ErrorActionPreference = "Stop"
+$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 2.0
+$disableConfigureToolsetImport = $true
$LASTEXITCODE = 0
+# `tools.ps1` checks $ci to perform some actions. Since the SDL
+# scripts don't necessarily execute in the same agent that run the
+# build.ps1/sh script this variable isn't automatically set.
+$ci = $true
+. $PSScriptRoot\..\tools.ps1
+
+# Don't display the console progress UI - it's a huge perf hit
+$ProgressPreference = 'SilentlyContinue'
+
# Construct basic auth from AzDO access token; construct URI to the repository's gdn folder stored in that repository; construct location of zip file
$encodedPat = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$AzureDevOpsAccessToken"))
$escapedRepository = [Uri]::EscapeDataString("/$Repository/$BranchName/.gdn")
-$uri = "https://dev.azure.com/dnceng/internal/_apis/git/repositories/sdl-tool-cfg/Items?path=$escapedRepository&versionDescriptor[versionOptions]=0&`$format=zip&api-version=5.0-preview.1"
+$uri = "https://dev.azure.com/dnceng/internal/_apis/git/repositories/sdl-tool-cfg/Items?path=$escapedRepository&versionDescriptor[versionOptions]=0&`$format=zip&api-version=5.0"
$zipFile = "$WorkingDirectory/gdn.zip"
Add-Type -AssemblyName System.IO.Compression.FileSystem
-$gdnFolder = (Join-Path $WorkingDirectory ".gdn")
-Try
-{
+$gdnFolder = (Join-Path $WorkingDirectory '.gdn')
+try {
# We try to download the zip; if the request fails (e.g. the file doesn't exist), we catch it and init guardian instead
- Write-Host "Downloading gdn folder from internal config repostiory..."
+ Write-Host 'Downloading gdn folder from internal config repostiory...'
Invoke-WebRequest -Headers @{ "Accept"="application/zip"; "Authorization"="Basic $encodedPat" } -Uri $uri -OutFile $zipFile
if (Test-Path $gdnFolder) {
# Remove the gdn folder if it exists (it shouldn't unless there's too much caching; this is just in case)
@@ -30,19 +39,29 @@ Try
}
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipFile, $WorkingDirectory)
Write-Host $gdnFolder
-} Catch [System.Net.WebException] {
+ ExitWithExitCode 0
+} catch [System.Net.WebException] { } # Catch and ignore webexception
+try {
# if the folder does not exist, we'll do a guardian init and push it to the remote repository
- Write-Host "Initializing Guardian..."
+ Write-Host 'Initializing Guardian...'
Write-Host "$GuardianCliLocation init --working-directory $WorkingDirectory --logger-level $GuardianLoggerLevel"
& $GuardianCliLocation init --working-directory $WorkingDirectory --logger-level $GuardianLoggerLevel
if ($LASTEXITCODE -ne 0) {
- Write-Error "Guardian init failed with exit code $LASTEXITCODE."
+ Write-PipelineTelemetryError -Force -Category 'Build' -Message "Guardian init failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
}
# We create the mainbaseline so it can be edited later
Write-Host "$GuardianCliLocation baseline --working-directory $WorkingDirectory --name mainbaseline"
& $GuardianCliLocation baseline --working-directory $WorkingDirectory --name mainbaseline
if ($LASTEXITCODE -ne 0) {
- Write-Error "Guardian baseline failed with exit code $LASTEXITCODE."
+ Write-PipelineTelemetryError -Force -Category 'Build' -Message "Guardian baseline failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
}
- & $(Join-Path $PSScriptRoot "push-gdn.ps1") -Repository $Repository -BranchName $BranchName -GdnFolder $gdnFolder -AzureDevOpsAccessToken $AzureDevOpsAccessToken -PushReason "Initialize gdn folder"
-}
\ No newline at end of file
+ & $(Join-Path $PSScriptRoot 'push-gdn.ps1') -Repository $Repository -BranchName $BranchName -GdnFolder $gdnFolder -AzureDevOpsAccessToken $AzureDevOpsAccessToken -PushReason 'Initialize gdn folder'
+ ExitWithExitCode 0
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
+ ExitWithExitCode 1
+}
diff --git a/eng/common/sdl/packages.config b/eng/common/sdl/packages.config
index 3f97ac2f16c..968b39bef5f 100644
--- a/eng/common/sdl/packages.config
+++ b/eng/common/sdl/packages.config
@@ -1,4 +1,4 @@
-
+
-
+
diff --git a/eng/common/sdl/push-gdn.ps1 b/eng/common/sdl/push-gdn.ps1
index 79c707d6d8a..d8fd2d82a68 100644
--- a/eng/common/sdl/push-gdn.ps1
+++ b/eng/common/sdl/push-gdn.ps1
@@ -1,51 +1,69 @@
Param(
[string] $Repository,
- [string] $BranchName="master",
+ [string] $BranchName='master',
[string] $GdnFolder,
[string] $AzureDevOpsAccessToken,
[string] $PushReason
)
-$ErrorActionPreference = "Stop"
+$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 2.0
+$disableConfigureToolsetImport = $true
$LASTEXITCODE = 0
-# We create the temp directory where we'll store the sdl-config repository
-$sdlDir = Join-Path $env:TEMP "sdl"
-if (Test-Path $sdlDir) {
- Remove-Item -Force -Recurse $sdlDir
-}
+try {
+ # `tools.ps1` checks $ci to perform some actions. Since the SDL
+ # scripts don't necessarily execute in the same agent that run the
+ # build.ps1/sh script this variable isn't automatically set.
+ $ci = $true
+ . $PSScriptRoot\..\tools.ps1
-Write-Host "git clone https://dnceng:`$AzureDevOpsAccessToken@dev.azure.com/dnceng/internal/_git/sdl-tool-cfg $sdlDir"
-git clone https://dnceng:$AzureDevOpsAccessToken@dev.azure.com/dnceng/internal/_git/sdl-tool-cfg $sdlDir
-if ($LASTEXITCODE -ne 0) {
- Write-Error "Git clone failed with exit code $LASTEXITCODE."
-}
-# We copy the .gdn folder from our local run into the git repository so it can be committed
-$sdlRepositoryFolder = Join-Path (Join-Path (Join-Path $sdlDir $Repository) $BranchName) ".gdn"
-if (Get-Command Robocopy) {
- Robocopy /S $GdnFolder $sdlRepositoryFolder
-} else {
- rsync -r $GdnFolder $sdlRepositoryFolder
-}
-# cd to the sdl-config directory so we can run git there
-Push-Location $sdlDir
-# git add . --> git commit --> git push
-Write-Host "git add ."
-git add .
-if ($LASTEXITCODE -ne 0) {
- Write-Error "Git add failed with exit code $LASTEXITCODE."
-}
-Write-Host "git -c user.email=`"dn-bot@microsoft.com`" -c user.name=`"Dotnet Bot`" commit -m `"$PushReason for $Repository/$BranchName`""
-git -c user.email="dn-bot@microsoft.com" -c user.name="Dotnet Bot" commit -m "$PushReason for $Repository/$BranchName"
-if ($LASTEXITCODE -ne 0) {
- Write-Error "Git commit failed with exit code $LASTEXITCODE."
+ # We create the temp directory where we'll store the sdl-config repository
+ $sdlDir = Join-Path $env:TEMP 'sdl'
+ if (Test-Path $sdlDir) {
+ Remove-Item -Force -Recurse $sdlDir
+ }
+
+ Write-Host "git clone https://dnceng:`$AzureDevOpsAccessToken@dev.azure.com/dnceng/internal/_git/sdl-tool-cfg $sdlDir"
+ git clone https://dnceng:$AzureDevOpsAccessToken@dev.azure.com/dnceng/internal/_git/sdl-tool-cfg $sdlDir
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Git clone failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
+ # We copy the .gdn folder from our local run into the git repository so it can be committed
+ $sdlRepositoryFolder = Join-Path (Join-Path (Join-Path $sdlDir $Repository) $BranchName) '.gdn'
+ if (Get-Command Robocopy) {
+ Robocopy /S $GdnFolder $sdlRepositoryFolder
+ } else {
+ rsync -r $GdnFolder $sdlRepositoryFolder
+ }
+ # cd to the sdl-config directory so we can run git there
+ Push-Location $sdlDir
+ # git add . --> git commit --> git push
+ Write-Host 'git add .'
+ git add .
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Git add failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
+ Write-Host "git -c user.email=`"dn-bot@microsoft.com`" -c user.name=`"Dotnet Bot`" commit -m `"$PushReason for $Repository/$BranchName`""
+ git -c user.email="dn-bot@microsoft.com" -c user.name="Dotnet Bot" commit -m "$PushReason for $Repository/$BranchName"
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Git commit failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
+ Write-Host 'git push'
+ git push
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Git push failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
+
+ # Return to the original directory
+ Pop-Location
}
-Write-Host "git push"
-git push
-if ($LASTEXITCODE -ne 0) {
- Write-Error "Git push failed with exit code $LASTEXITCODE."
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'Sdl' -Message $_
+ ExitWithExitCode 1
}
-
-# Return to the original directory
-Pop-Location
\ No newline at end of file
diff --git a/eng/common/sdl/run-sdl.ps1 b/eng/common/sdl/run-sdl.ps1
index d7b85644581..fe95ab35aa5 100644
--- a/eng/common/sdl/run-sdl.ps1
+++ b/eng/common/sdl/run-sdl.ps1
@@ -5,63 +5,69 @@ Param(
[string] $GdnFolder,
[string[]] $ToolsList,
[string] $UpdateBaseline,
- [string] $GuardianLoggerLevel="Standard",
+ [string] $GuardianLoggerLevel='Standard',
[string[]] $CrScanAdditionalRunConfigParams,
[string[]] $PoliCheckAdditionalRunConfigParams
)
-$ErrorActionPreference = "Stop"
+$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 2.0
+$disableConfigureToolsetImport = $true
$LASTEXITCODE = 0
-# We store config files in the r directory of .gdn
-Write-Host $ToolsList
-$gdnConfigPath = Join-Path $GdnFolder "r"
-$ValidPath = Test-Path $GuardianCliLocation
+try {
+ # `tools.ps1` checks $ci to perform some actions. Since the SDL
+ # scripts don't necessarily execute in the same agent that run the
+ # build.ps1/sh script this variable isn't automatically set.
+ $ci = $true
+ . $PSScriptRoot\..\tools.ps1
-if ($ValidPath -eq $False)
-{
- Write-Host "Invalid Guardian CLI Location."
- exit 1
-}
+ # We store config files in the r directory of .gdn
+ Write-Host $ToolsList
+ $gdnConfigPath = Join-Path $GdnFolder 'r'
+ $ValidPath = Test-Path $GuardianCliLocation
-foreach ($tool in $ToolsList) {
- $gdnConfigFile = Join-Path $gdnConfigPath "$tool-configure.gdnconfig"
- $config = $False
- Write-Host $tool
- # We have to manually configure tools that run on source to look at the source directory only
- if ($tool -eq "credscan") {
- Write-Host "$GuardianCliLocation configure --working-directory $WorkingDirectory --tool $tool --output-path $gdnConfigFile --logger-level $GuardianLoggerLevel --noninteractive --force --args `" TargetDirectory : $TargetDirectory `" $(If ($CrScanAdditionalRunConfigParams) {$CrScanAdditionalRunConfigParams})"
- & $GuardianCliLocation configure --working-directory $WorkingDirectory --tool $tool --output-path $gdnConfigFile --logger-level $GuardianLoggerLevel --noninteractive --force --args " TargetDirectory : $TargetDirectory " $(If ($CrScanAdditionalRunConfigParams) {$CrScanAdditionalRunConfigParams})
- if ($LASTEXITCODE -ne 0) {
- Write-Host "Guardian configure for $tool failed with exit code $LASTEXITCODE."
- exit $LASTEXITCODE
- }
- $config = $True
- }
- if ($tool -eq "policheck") {
- Write-Host "$GuardianCliLocation configure --working-directory $WorkingDirectory --tool $tool --output-path $gdnConfigFile --logger-level $GuardianLoggerLevel --noninteractive --force --args `" Target : $TargetDirectory `" $(If ($PoliCheckAdditionalRunConfigParams) {$PoliCheckAdditionalRunConfigParams})"
- & $GuardianCliLocation configure --working-directory $WorkingDirectory --tool $tool --output-path $gdnConfigFile --logger-level $GuardianLoggerLevel --noninteractive --force --args " Target : $TargetDirectory " $(If ($PoliCheckAdditionalRunConfigParams) {$PoliCheckAdditionalRunConfigParams})
- if ($LASTEXITCODE -ne 0) {
- Write-Host "Guardian configure for $tool failed with exit code $LASTEXITCODE."
- exit $LASTEXITCODE
- }
- $config = $True
+ if ($ValidPath -eq $False)
+ {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Invalid Guardian CLI Location."
+ ExitWithExitCode 1
}
- Write-Host "$GuardianCliLocation run --working-directory $WorkingDirectory --tool $tool --baseline mainbaseline --update-baseline $UpdateBaseline --logger-level $GuardianLoggerLevel --config $gdnConfigFile $config"
- if ($config) {
- & $GuardianCliLocation run --working-directory $WorkingDirectory --tool $tool --baseline mainbaseline --update-baseline $UpdateBaseline --logger-level $GuardianLoggerLevel --config $gdnConfigFile
- if ($LASTEXITCODE -ne 0) {
- Write-Host "Guardian run for $tool using $gdnConfigFile failed with exit code $LASTEXITCODE."
- exit $LASTEXITCODE
+ $configParam = @('--config')
+
+ foreach ($tool in $ToolsList) {
+ $gdnConfigFile = Join-Path $gdnConfigPath "$tool-configure.gdnconfig"
+ Write-Host $tool
+ # We have to manually configure tools that run on source to look at the source directory only
+ if ($tool -eq 'credscan') {
+ Write-Host "$GuardianCliLocation configure --working-directory $WorkingDirectory --tool $tool --output-path $gdnConfigFile --logger-level $GuardianLoggerLevel --noninteractive --force --args `" TargetDirectory < $TargetDirectory `" `" OutputType < pre `" $(If ($CrScanAdditionalRunConfigParams) {$CrScanAdditionalRunConfigParams})"
+ & $GuardianCliLocation configure --working-directory $WorkingDirectory --tool $tool --output-path $gdnConfigFile --logger-level $GuardianLoggerLevel --noninteractive --force --args " TargetDirectory < $TargetDirectory " "OutputType < pre" $(If ($CrScanAdditionalRunConfigParams) {$CrScanAdditionalRunConfigParams})
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Guardian configure for $tool failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
}
- } else {
- & $GuardianCliLocation run --working-directory $WorkingDirectory --tool $tool --baseline mainbaseline --update-baseline $UpdateBaseline --logger-level $GuardianLoggerLevel
- if ($LASTEXITCODE -ne 0) {
- Write-Host "Guardian run for $tool failed with exit code $LASTEXITCODE."
- exit $LASTEXITCODE
+ if ($tool -eq 'policheck') {
+ Write-Host "$GuardianCliLocation configure --working-directory $WorkingDirectory --tool $tool --output-path $gdnConfigFile --logger-level $GuardianLoggerLevel --noninteractive --force --args `" Target < $TargetDirectory `" $(If ($PoliCheckAdditionalRunConfigParams) {$PoliCheckAdditionalRunConfigParams})"
+ & $GuardianCliLocation configure --working-directory $WorkingDirectory --tool $tool --output-path $gdnConfigFile --logger-level $GuardianLoggerLevel --noninteractive --force --args " Target < $TargetDirectory " $(If ($PoliCheckAdditionalRunConfigParams) {$PoliCheckAdditionalRunConfigParams})
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Guardian configure for $tool failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
}
+
+ $configParam+=$gdnConfigFile
}
-}
+ Write-Host "$GuardianCliLocation run --working-directory $WorkingDirectory --baseline mainbaseline --update-baseline $UpdateBaseline --logger-level $GuardianLoggerLevel $configParam"
+ & $GuardianCliLocation run --working-directory $WorkingDirectory --tool $tool --baseline mainbaseline --update-baseline $UpdateBaseline --logger-level $GuardianLoggerLevel $configParam
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Guardian run for $ToolsList using $configParam failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
+ ExitWithExitCode 1
+}
diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml
index f657a4dc91d..c64c4f5686c 100644
--- a/eng/common/templates/job/execute-sdl.yml
+++ b/eng/common/templates/job/execute-sdl.yml
@@ -1,35 +1,72 @@
parameters:
+ enable: 'false' # Whether the SDL validation job should execute or not
overrideParameters: '' # Optional: to override values for parameters.
additionalParameters: '' # Optional: parameters that need user specific values eg: '-SourceToolsList @("abc","def") -ArtifactToolsList @("ghi","jkl")'
- continueOnError: false # optional: determines whether to continue the build if the step errors;
+ # There is some sort of bug (has been reported) in Azure DevOps where if this parameter is named
+ # 'continueOnError', the parameter value is not correctly picked up.
+ # This can also be remedied by the caller (post-build.yml) if it does not use a nested parameter
+ sdlContinueOnError: false # optional: determines whether to continue the build if the step errors;
+ downloadArtifacts: true # optional: determines if the artifacts should be dowloaded
dependsOn: '' # Optional: dependencies of the job
+ artifactNames: '' # Optional: patterns supplied to DownloadBuildArtifacts
+ # Usage:
+ # artifactNames:
+ # - 'BlobArtifacts'
+ # - 'Artifacts_Windows_NT_Release'
jobs:
- job: Run_SDL
dependsOn: ${{ parameters.dependsOn }}
displayName: Run SDL tool
+ condition: eq( ${{ parameters.enable }}, 'true')
variables:
- group: DotNet-VSTS-Bot
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ pool:
+ name: Hosted VS2017
steps:
- checkout: self
clean: true
- - task: DownloadBuildArtifacts@0
- displayName: Download Build Artifacts
- inputs:
- buildType: current
- downloadType: specific files
- matchingPattern: "**"
- downloadPath: $(Build.SourcesDirectory)\artifacts
+ - ${{ if ne(parameters.downloadArtifacts, 'false')}}:
+ - ${{ if ne(parameters.artifactNames, '') }}:
+ - ${{ each artifactName in parameters.artifactNames }}:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ artifactName: ${{ artifactName }}
+ downloadPath: $(Build.ArtifactStagingDirectory)\artifacts
+ - ${{ if eq(parameters.artifactNames, '') }}:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ downloadType: specific files
+ itemPattern: "**"
+ downloadPath: $(Build.ArtifactStagingDirectory)\artifacts
- powershell: eng/common/sdl/extract-artifact-packages.ps1
- -InputPath $(Build.SourcesDirectory)\artifacts\BlobArtifacts
- -ExtractPath $(Build.SourcesDirectory)\artifacts\BlobArtifacts
+ -InputPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts
+ -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts
displayName: Extract Blob Artifacts
- continueOnError: ${{ parameters.continueOnError }}
+ continueOnError: ${{ parameters.sdlContinueOnError }}
- powershell: eng/common/sdl/extract-artifact-packages.ps1
- -InputPath $(Build.SourcesDirectory)\artifacts\PackageArtifacts
- -ExtractPath $(Build.SourcesDirectory)\artifacts\PackageArtifacts
+ -InputPath $(Build.ArtifactStagingDirectory)\artifacts\PackageArtifacts
+ -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\PackageArtifacts
displayName: Extract Package Artifacts
- continueOnError: ${{ parameters.continueOnError }}
+ continueOnError: ${{ parameters.sdlContinueOnError }}
- task: NuGetToolInstaller@1
displayName: 'Install NuGet.exe'
- task: NuGetCommand@2
@@ -43,12 +80,12 @@ jobs:
- ${{ if ne(parameters.overrideParameters, '') }}:
- powershell: eng/common/sdl/execute-all-sdl-tools.ps1 ${{ parameters.overrideParameters }}
displayName: Execute SDL
- continueOnError: ${{ parameters.continueOnError }}
+ continueOnError: ${{ parameters.sdlContinueOnError }}
- ${{ if eq(parameters.overrideParameters, '') }}:
- powershell: eng/common/sdl/execute-all-sdl-tools.ps1
- -GuardianPackageName Microsoft.Guardian.Cli.0.7.1
+ -GuardianPackageName Microsoft.Guardian.Cli.win10-x64.0.20.1
-NugetPackageDirectory $(Build.SourcesDirectory)\.packages
-AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw)
${{ parameters.additionalParameters }}
displayName: Execute SDL
- continueOnError: ${{ parameters.continueOnError }}
+ continueOnError: ${{ parameters.sdlContinueOnError }}
diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml
index 1814e0ab612..86696793480 100644
--- a/eng/common/templates/job/job.yml
+++ b/eng/common/templates/job/job.yml
@@ -1,64 +1,36 @@
+# Internal resources (telemetry, microbuild) can only be accessed from non-public projects,
+# and some (Microbuild) should only be applied to non-PR cases for internal builds.
+
parameters:
# Job schema parameters - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job
cancelTimeoutInMinutes: ''
-
condition: ''
-
- continueOnError: false
-
container: ''
-
+ continueOnError: false
dependsOn: ''
-
displayName: ''
-
- steps: []
-
pool: ''
-
+ steps: []
strategy: ''
-
timeoutInMinutes: ''
-
variables: []
-
workspace: ''
# Job base template specific parameters
- # Optional: Enable installing Microbuild plugin
- # if 'true', these "variables" must be specified in the variables object or as part of the queue matrix
- # _TeamName - the name of your team
- # _SignType - 'test' or 'real'
+ # See schema documentation - https://github.com/dotnet/arcade/blob/master/Documentation/AzureDevOps/TemplateSchema.md
+ artifacts: ''
enableMicrobuild: false
-
- # Optional: Include PublishBuildArtifacts task
enablePublishBuildArtifacts: false
-
- # Optional: Enable publishing to the build asset registry
enablePublishBuildAssets: false
-
- # Optional: Include PublishTestResults task
enablePublishTestResults: false
-
- # Optional: enable sending telemetry
- enableTelemetry: false
-
- # Optional: define the helix repo for telemetry (example: 'dotnet/arcade')
- helixRepo: ''
-
- # Optional: define the helix type for telemetry (example: 'build/product/')
- helixType: ''
-
- # Required: name of the job
+ enablePublishUsingPipelines: false
+ mergeTestResults: false
+ testRunTitle: ''
+ testResultsFormat: ''
name: ''
-
- # Optional: should run as a public build even in the internal project
- # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects.
+ preSteps: []
runAsPublic: false
-# Internal resources (telemetry, microbuild) can only be accessed from non-public projects,
-# and some (Microbuild) should only be applied to non-PR cases for internal builds.
-
jobs:
- job: ${{ parameters.name }}
@@ -90,9 +62,12 @@ jobs:
timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
variables:
- - ${{ if eq(parameters.enableTelemetry, 'true') }}:
+ - ${{ if ne(parameters.enableTelemetry, 'false') }}:
- name: DOTNET_CLI_TELEMETRY_PROFILE
value: '$(Build.Repository.Uri)'
+ - ${{ if eq(parameters.enableRichCodeNavigation, 'true') }}:
+ - name: EnableRichCodeNavigation
+ value: 'true'
- ${{ each variable in parameters.variables }}:
# handle name-value variable syntax
# example:
@@ -122,21 +97,12 @@ jobs:
workspace: ${{ parameters.workspace }}
steps:
- - ${{ if eq(parameters.enableTelemetry, 'true') }}:
- # Telemetry tasks are built from https://github.com/dotnet/arcade-extensions
- - task: sendStartTelemetry@0
- displayName: 'Send Helix Start Telemetry'
- inputs:
- helixRepo: ${{ parameters.helixRepo }}
- ${{ if ne(parameters.helixType, '') }}:
- helixType: ${{ parameters.helixType }}
- buildConfig: $(_BuildConfig)
- runAsPublic: ${{ parameters.runAsPublic }}
- continueOnError: ${{ parameters.continueOnError }}
- condition: always()
+ - ${{ if ne(parameters.preSteps, '') }}:
+ - ${{ each preStep in parameters.preSteps }}:
+ - ${{ preStep }}
- - ${{ if eq(parameters.enableMicrobuild, 'true') }}:
- - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - ${{ if eq(parameters.enableMicrobuild, 'true') }}:
- task: MicroBuildSigningPlugin@2
displayName: Install MicroBuild plugin
inputs:
@@ -148,9 +114,28 @@ jobs:
continueOnError: ${{ parameters.continueOnError }}
condition: and(succeeded(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT'))
+ - task: NuGetAuthenticate@0
+
+ - ${{ if or(eq(parameters.artifacts.download, 'true'), ne(parameters.artifacts.download, '')) }}:
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ buildType: current
+ artifactName: ${{ coalesce(parameters.artifacts.download.name, 'Artifacts_$(Agent.OS)_$(_BuildConfig)') }}
+ targetPath: ${{ coalesce(parameters.artifacts.download.path, 'artifacts') }}
+ itemPattern: ${{ coalesce(parameters.artifacts.download.pattern, '**') }}
+
- ${{ each step in parameters.steps }}:
- ${{ step }}
+ - ${{ if eq(parameters.enableRichCodeNavigation, true) }}:
+ - task: RichCodeNavIndexer@0
+ displayName: RichCodeNav Upload
+ inputs:
+ languages: ${{ coalesce(parameters.richCodeNavigationLanguage, 'csharp') }}
+ environment: ${{ coalesce(parameters.richCodeNavigationEnvironment, 'production') }}
+ richNavLogOutputDirectory: $(Build.SourcesDirectory)/artifacts/bin
+ continueOnError: true
+
- ${{ if eq(parameters.enableMicrobuild, 'true') }}:
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- task: MicroBuildCleanup@1
@@ -160,34 +145,87 @@ jobs:
env:
TeamName: $(_TeamName)
- - ${{ if eq(parameters.enableTelemetry, 'true') }}:
- # Telemetry tasks are built from https://github.com/dotnet/arcade-extensions
- - task: sendEndTelemetry@0
- displayName: 'Send Helix End Telemetry'
- continueOnError: ${{ parameters.continueOnError }}
- condition: always()
-
- - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}:
+ - ${{ if ne(parameters.artifacts.publish, '') }}:
+ - ${{ if or(eq(parameters.artifacts.publish.artifacts, 'true'), ne(parameters.artifacts.publish.artifacts, '')) }}:
+ - task: CopyFiles@2
+ displayName: Gather binaries for publish to artifacts
+ inputs:
+ SourceFolder: 'artifacts/bin'
+ Contents: '**'
+ TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/bin'
+ - task: CopyFiles@2
+ displayName: Gather packages for publish to artifacts
+ inputs:
+ SourceFolder: 'artifacts/packages'
+ Contents: '**'
+ TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/packages'
+ - task: PublishBuildArtifacts@1
+ displayName: Publish pipeline artifacts
+ inputs:
+ PathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts'
+ PublishLocation: Container
+ ArtifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }}
+ continueOnError: true
+ condition: always()
+ - ${{ if or(eq(parameters.artifacts.publish.logs, 'true'), ne(parameters.artifacts.publish.logs, '')) }}:
+ - publish: artifacts/log
+ artifact: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)') }}
+ displayName: Publish logs
+ continueOnError: true
+ condition: always()
+ - ${{ if or(eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}:
+ - ${{ if and(ne(parameters.enablePublishUsingPipelines, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: CopyFiles@2
+ displayName: Gather Asset Manifests
+ inputs:
+ SourceFolder: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/AssetManifest'
+ TargetFolder: '$(Build.ArtifactStagingDirectory)/AssetManifests'
+ continueOnError: ${{ parameters.continueOnError }}
+ condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
+
+ - task: PublishBuildArtifacts@1
+ displayName: Push Asset Manifests
+ inputs:
+ PathtoPublish: '$(Build.ArtifactStagingDirectory)/AssetManifests'
+ PublishLocation: Container
+ ArtifactName: AssetManifests
+ continueOnError: ${{ parameters.continueOnError }}
+ condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
+
+ - ${{ if ne(parameters.enablePublishBuildArtifacts, 'false') }}:
- task: PublishBuildArtifacts@1
displayName: Publish Logs
inputs:
PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)'
PublishLocation: Container
- ArtifactName: $(Agent.Os)_$(Agent.JobName)
+ ArtifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)' ) }}
continueOnError: true
condition: always()
- - ${{ if eq(parameters.enablePublishTestResults, 'true') }}:
+ - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'xunit')) }}:
- task: PublishTestResults@2
- displayName: Publish Test Results
+ displayName: Publish XUnit Test Results
inputs:
testResultsFormat: 'xUnit'
testResultsFiles: '*.xml'
searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
+ testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-xunit
+ mergeTestResults: ${{ parameters.mergeTestResults }}
+ continueOnError: true
+ condition: always()
+ - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'vstest')) }}:
+ - task: PublishTestResults@2
+ displayName: Publish TRX Test Results
+ inputs:
+ testResultsFormat: 'VSTest'
+ testResultsFiles: '*.trx'
+ searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
+ testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-trx
+ mergeTestResults: ${{ parameters.mergeTestResults }}
continueOnError: true
condition: always()
- - ${{ if and(eq(parameters.enablePublishBuildAssets, true), ne(variables['_PublishUsingPipelines'], 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - ${{ if and(eq(parameters.enablePublishBuildAssets, true), ne(parameters.enablePublishUsingPipelines, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- task: CopyFiles@2
displayName: Gather Asset Manifests
inputs:
@@ -195,6 +233,7 @@ jobs:
TargetFolder: '$(Build.StagingDirectory)/AssetManifests'
continueOnError: ${{ parameters.continueOnError }}
condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
+
- task: PublishBuildArtifacts@1
displayName: Push Asset Manifests
inputs:
diff --git a/eng/common/templates/job/performance.yml b/eng/common/templates/job/performance.yml
index ef809253d1a..f877fd7a898 100644
--- a/eng/common/templates/job/performance.yml
+++ b/eng/common/templates/job/performance.yml
@@ -5,6 +5,7 @@ parameters:
displayName: '' # optional -- display name for the job. Will use jobName if not passed
pool: '' # required -- name of the Build pool
container: '' # required -- name of the container
+ osGroup: '' # required -- operating system for the job
extraSetupParameters: '' # optional -- extra arguments to pass to the setup script
frameworks: ['netcoreapp3.0'] # optional -- list of frameworks to run against
continueOnError: 'false' # optional -- determines whether to continue the build if the step errors
@@ -44,12 +45,13 @@ jobs:
- HelixPreCommand: ''
- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - ${{ if eq(variables['Agent.Os'], 'Windows_NT') }}:
+ - ${{ if eq( parameters.osGroup, 'Windows_NT') }}:
- HelixPreCommand: 'set "PERFLAB_UPLOAD_TOKEN=$(PerfCommandUploadToken)"'
- IsInternal: -Internal
- - ${{ if ne(variables['Agent.Os'], 'Windows_NT') }}:
+ - ${{ if ne(parameters.osGroup, 'Windows_NT') }}:
- HelixPreCommand: 'export PERFLAB_UPLOAD_TOKEN="$(PerfCommandUploadTokenLinux)"'
- IsInternal: --internal
+
- group: DotNet-HelixApi-Access
- group: dotnet-benchview
diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml
index 4a06190dd3e..d0c3cc2b3ba 100644
--- a/eng/common/templates/job/publish-build-assets.yml
+++ b/eng/common/templates/job/publish-build-assets.yml
@@ -37,6 +37,12 @@ jobs:
- name: _BuildConfig
value: ${{ parameters.configuration }}
- group: Publish-Build-Assets
+ # Skip component governance and codesign validation for SDL. These jobs
+ # create no content.
+ - name: skipComponentGovernanceDetection
+ value: true
+ - name: runCodesignValidationInjection
+ value: false
steps:
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
@@ -47,6 +53,10 @@ jobs:
downloadPath: '$(Build.StagingDirectory)/Download'
condition: ${{ parameters.condition }}
continueOnError: ${{ parameters.continueOnError }}
+
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: NuGetAuthenticate@0
+
- task: PowerShell@2
displayName: Publish Build Assets
inputs:
@@ -57,9 +67,10 @@ jobs:
/p:MaestroApiEndpoint=https://maestro-prod.westus2.cloudapp.azure.com
/p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }}
/p:Configuration=$(_BuildConfig)
- /v:detailed
+ /p:OfficialBuildId=$(Build.BuildNumber)
condition: ${{ parameters.condition }}
continueOnError: ${{ parameters.continueOnError }}
+
- task: powershell@2
displayName: Create ReleaseConfigs Artifact
inputs:
@@ -68,18 +79,15 @@ jobs:
Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(BARBuildId)
Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value "$(DefaultChannels)"
Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(IsStableBuild)
+
- task: PublishBuildArtifacts@1
displayName: Publish ReleaseConfigs Artifact
inputs:
PathtoPublish: '$(Build.StagingDirectory)/ReleaseConfigs.txt'
PublishLocation: Container
ArtifactName: ReleaseConfigs
+
- ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}:
- - task: PublishBuildArtifacts@1
- displayName: Publish Logs to VSTS
- inputs:
- PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)'
- PublishLocation: Container
- ArtifactName: $(Agent.Os)_PublishBuildAssets
- continueOnError: true
- condition: always()
+ - template: /eng/common/templates/steps/publish-logs.yml
+ parameters:
+ JobLabel: 'Publish_Artifacts_Logs'
diff --git a/eng/common/templates/job/source-build.yml b/eng/common/templates/job/source-build.yml
new file mode 100644
index 00000000000..9332f5ecc38
--- /dev/null
+++ b/eng/common/templates/job/source-build.yml
@@ -0,0 +1,49 @@
+parameters:
+ # This template adds arcade-powered source-build to CI. The template produces a server job with a
+ # default ID 'Source_Build_Complete' to put in a dependency list if necessary.
+
+ # Specifies the prefix for source-build jobs added to pipeline. Use this if disambiguation needed.
+ jobNamePrefix: 'Source_Build'
+
+ # Defines the platform on which to run the job. By default, a linux-x64 machine, suitable for
+ # managed-only repositories. This is an object with these properties:
+ #
+ # name: ''
+ # The name of the job. This is included in the job ID.
+ # targetRID: ''
+ # The name of the target RID to use, instead of the one auto-detected by Arcade.
+ # nonPortable: false
+ # Enables non-portable mode. This means a more specific RID (e.g. fedora.32-x64 rather than
+ # linux-x64), and compiling against distro-provided packages rather than portable ones.
+ # container: ''
+ # A container to use. Runs in docker.
+ # pool: {}
+ # A pool to use. Runs directly on an agent.
+ # buildScript: ''
+ # Specifies the build script to invoke to perform the build in the repo. The default
+ # './build.sh' should work for typical Arcade repositories, but this is customizable for
+ # difficult situations.
+ # jobProperties: {}
+ # A list of job properties to inject at the top level, for potential extensibility beyond
+ # container and pool.
+ platform: {}
+
+jobs:
+- job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }}
+ displayName: Source-Build (${{ parameters.platform.name }})
+
+ ${{ each property in parameters.platform.jobProperties }}:
+ ${{ property.key }}: ${{ property.value }}
+
+ ${{ if ne(parameters.platform.container, '') }}:
+ container: ${{ parameters.platform.container }}
+ ${{ if ne(parameters.platform.pool, '') }}:
+ pool: ${{ parameters.platform.pool }}
+
+ workspace:
+ clean: all
+
+ steps:
+ - template: /eng/common/templates/steps/source-build.yml
+ parameters:
+ platform: ${{ parameters.platform }}
diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml
index 6a2f98c036f..08845950f44 100644
--- a/eng/common/templates/jobs/jobs.yml
+++ b/eng/common/templates/jobs/jobs.yml
@@ -1,19 +1,10 @@
parameters:
- # Optional: 'true' if failures in job.yml job should not fail the job
+ # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md
continueOnError: false
- # Optional: Enable installing Microbuild plugin
- # if 'true', these "variables" must be specified in the variables object or as part of the queue matrix
- # _TeamName - the name of your team
- # _SignType - 'test' or 'real'
- enableMicrobuild: false
-
# Optional: Include PublishBuildArtifacts task
enablePublishBuildArtifacts: false
- # Optional: Enable publishing to the build asset registry
- enablePublishBuildAssets: false
-
# Optional: Enable publishing using release pipelines
enablePublishUsingPipelines: false
@@ -23,19 +14,9 @@ parameters:
# Optional: Include toolset dependencies in the generated graph files
includeToolset: false
- # Optional: Include PublishTestResults task
- enablePublishTestResults: false
-
- # Optional: enable sending telemetry
- # if enabled then the 'helixRepo' parameter should also be specified
- enableTelemetry: false
-
# Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job
jobs: []
- # Optional: define the helix repo for telemetry (example: 'dotnet/arcade')
- helixRepo: ''
-
# Optional: Override automatically derived dependsOn value for "publish build assets" job
publishBuildAssetsDependsOn: ''
@@ -43,6 +24,13 @@ parameters:
# if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects.
runAsPublic: false
+ # Optional: Enable running the source-build jobs to build repo from source
+ runSourceBuild: false
+
+ # Optional: Parameters for source-build template.
+ # See /eng/common/templates/jobs/source-build.yml for options
+ sourceBuildParameters: []
+
# Internal resources (telemetry, microbuild) can only be accessed from non-public projects,
# and some (Microbuild) should only be applied to non-PR cases for internal builds.
@@ -62,29 +50,39 @@ jobs:
name: ${{ job.job }}
-- ${{ if and(eq(parameters.enablePublishBuildAssets, true), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - template: ../job/publish-build-assets.yml
- parameters:
- continueOnError: ${{ parameters.continueOnError }}
- dependsOn:
- - ${{ if ne(parameters.publishBuildAssetsDependsOn, '') }}:
- - ${{ each job in parameters.publishBuildAssetsDependsOn }}:
- - ${{ job.job }}
- - ${{ if eq(parameters.publishBuildAssetsDependsOn, '') }}:
- - ${{ each job in parameters.jobs }}:
- - ${{ job.job }}
- pool:
- vmImage: vs2017-win2016
- runAsPublic: ${{ parameters.runAsPublic }}
- publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }}
- enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }}
-
-- ${{ if and(eq(parameters.graphFileGeneration.enabled, true), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - template: ../job/generate-graph-files.yml
+- ${{ if eq(parameters.runSourceBuild, true) }}:
+ - template: /eng/common/templates/jobs/source-build.yml
parameters:
- continueOnError: ${{ parameters.continueOnError }}
- includeToolset: ${{ parameters.graphFileGeneration.includeToolset }}
- dependsOn:
- - Asset_Registry_Publish
- pool:
- vmImage: vs2017-win2016
+ allCompletedJobId: Source_Build_Complete
+ ${{ each parameter in parameters.sourceBuildParameters }}:
+ ${{ parameter.key }}: ${{ parameter.value }}
+
+- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}:
+ - template: ../job/publish-build-assets.yml
+ parameters:
+ continueOnError: ${{ parameters.continueOnError }}
+ dependsOn:
+ - ${{ if ne(parameters.publishBuildAssetsDependsOn, '') }}:
+ - ${{ each job in parameters.publishBuildAssetsDependsOn }}:
+ - ${{ job.job }}
+ - ${{ if eq(parameters.publishBuildAssetsDependsOn, '') }}:
+ - ${{ each job in parameters.jobs }}:
+ - ${{ job.job }}
+ - ${{ if eq(parameters.runSourceBuild, true) }}:
+ - Source_Build_Complete
+ pool:
+ vmImage: vs2017-win2016
+ runAsPublic: ${{ parameters.runAsPublic }}
+ publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }}
+ enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }}
+
+ - ${{ if eq(parameters.graphFileGeneration.enabled, true) }}:
+ - template: ../job/generate-graph-files.yml
+ parameters:
+ continueOnError: ${{ parameters.continueOnError }}
+ includeToolset: ${{ parameters.graphFileGeneration.includeToolset }}
+ dependsOn:
+ - Asset_Registry_Publish
+ pool:
+ vmImage: vs2017-win2016
diff --git a/eng/common/templates/jobs/source-build.yml b/eng/common/templates/jobs/source-build.yml
new file mode 100644
index 00000000000..f463011e793
--- /dev/null
+++ b/eng/common/templates/jobs/source-build.yml
@@ -0,0 +1,48 @@
+parameters:
+ # This template adds arcade-powered source-build to CI. A job is created for each platform, as
+ # well as an optional server job that completes when all platform jobs complete.
+
+ # The name of the "join" job for all source-build platforms. If set to empty string, the job is
+ # not included. Existing repo pipelines can use this job depend on all source-build jobs
+ # completing without maintaining a separate list of every single job ID: just depend on this one
+ # server job. By default, not included. Recommended name if used: 'Source_Build_Complete'.
+ allCompletedJobId: ''
+
+ # See /eng/common/templates/job/source-build.yml
+ jobNamePrefix: 'Source_Build'
+
+ # If changed to true, causes this template to include the default platform for a managed-only
+ # repo. The exact Docker image used for this build will be provided by Arcade. This has some risk,
+ # but since the repo is supposed to be managed-only, the risk should be very low.
+ includeDefaultManagedPlatform: false
+ defaultManagedPlatform:
+ name: 'Managed'
+ container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-3e800f1-20190501005343'
+
+ # Defines the platforms on which to run build jobs. One job is created for each platform, and the
+ # object in this array is sent to the job template as 'platform'.
+ platforms: []
+
+jobs:
+
+- ${{ if ne(parameters.allCompletedJobId, '') }}:
+ - job: ${{ parameters.allCompletedJobId }}
+ displayName: Source-Build Complete
+ pool: server
+ dependsOn:
+ - ${{ each platform in parameters.platforms }}:
+ - ${{ parameters.jobNamePrefix }}_${{ platform.name }}
+ - ${{ if eq(parameters.includeDefaultManagedPlatform, true) }}:
+ - ${{ parameters.jobNamePrefix }}_${{ parameters.defaultManagedPlatform.name }}
+
+- ${{ each platform in parameters.platforms }}:
+ - template: /eng/common/templates/job/source-build.yml
+ parameters:
+ jobNamePrefix: ${{ parameters.jobNamePrefix }}
+ platform: ${{ platform }}
+
+- ${{ if eq(parameters.includeDefaultManagedPlatform, true) }}:
+ - template: /eng/common/templates/job/source-build.yml
+ parameters:
+ jobNamePrefix: ${{ parameters.jobNamePrefix }}
+ platform: ${{ parameters.defaultManagedPlatform }}
diff --git a/eng/common/templates/post-build/channels/generic-internal-channel.yml b/eng/common/templates/post-build/channels/generic-internal-channel.yml
new file mode 100644
index 00000000000..7ae5255921a
--- /dev/null
+++ b/eng/common/templates/post-build/channels/generic-internal-channel.yml
@@ -0,0 +1,182 @@
+parameters:
+ BARBuildId: ''
+ PromoteToChannelIds: ''
+ artifactsPublishingAdditionalParameters: ''
+ dependsOn:
+ - Validate
+ publishInstallersAndChecksums: true
+ symbolPublishingAdditionalParameters: ''
+ stageName: ''
+ channelName: ''
+ channelId: ''
+ transportFeed: ''
+ shippingFeed: ''
+ symbolsFeed: ''
+
+stages:
+- stage: ${{ parameters.stageName }}
+ dependsOn: ${{ parameters.dependsOn }}
+ variables:
+ - template: ../common-variables.yml
+ displayName: ${{ parameters.channelName }} Publishing
+ jobs:
+ - template: ../setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - job: publish_symbols
+ displayName: Symbol Publishing
+ dependsOn: setupMaestroVars
+ condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} ))
+ variables:
+ - group: DotNet-Symbol-Server-Pats
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Assets
+ continueOnError: true
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ downloadType: 'specific'
+ itemPattern: |
+ PdbArtifacts/**
+ BlobArtifacts/**
+ downloadPath: '$(Build.ArtifactStagingDirectory)'
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ # Since sdk-task.ps1 tries to restore packages we need to do this authentication here
+ # otherwise it'll complain about accessing a private feed.
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: eng\common\enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ - task: PowerShell@2
+ displayName: Publish
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task PublishToSymbolServers -restore -msbuildEngine dotnet
+ /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
+ /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
+ /p:PDBArtifactsDirectory='$(Build.ArtifactStagingDirectory)/PDBArtifacts/'
+ /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
+ /p:SymbolPublishingExclusionsFile='$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt'
+ /p:Configuration=Release
+ /p:PublishToMSDL=false
+ ${{ parameters.symbolPublishingAdditionalParameters }}
+
+ - template: ../../steps/publish-logs.yml
+ parameters:
+ StageLabel: '${{ parameters.stageName }}'
+ JobLabel: 'SymbolPublishing'
+
+ - job: publish_assets
+ displayName: Publish Assets
+ dependsOn: setupMaestroVars
+ timeoutInMinutes: 120
+ variables:
+ - name: BARBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
+ - name: IsStableBuild
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ]
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} ))
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Assets
+ continueOnError: true
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ downloadType: 'specific'
+ itemPattern: |
+ PackageArtifacts/**
+ BlobArtifacts/**
+ AssetManifests/**
+ downloadPath: '$(Build.ArtifactStagingDirectory)'
+
+ - task: NuGetToolInstaller@1
+ displayName: 'Install NuGet.exe'
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: eng\common\enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ - task: PowerShell@2
+ displayName: Publish Assets
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
+ /p:PublishingInfraVersion=2
+ /p:IsStableBuild=$(IsStableBuild)
+ /p:IsInternalBuild=$(IsInternalBuild)
+ /p:RepositoryName=$(Build.Repository.Name)
+ /p:CommitSha=$(Build.SourceVersion)
+ /p:NugetPath=$(NuGetExeToolPath)
+ /p:AzdoTargetFeedPAT='$(dn-bot-dnceng-universal-packages-rw)'
+ /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)'
+ /p:BARBuildId=$(BARBuildId)
+ /p:MaestroApiEndpoint='$(MaestroApiEndPoint)'
+ /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)'
+ /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/'
+ /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
+ /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/'
+ /p:Configuration=Release
+ /p:PublishInstallersAndChecksums=${{ parameters.publishInstallersAndChecksums }}
+ /p:ChecksumsTargetStaticFeed=$(InternalChecksumsBlobFeedUrl)
+ /p:ChecksumsAzureAccountKey=$(InternalChecksumsBlobFeedKey)
+ /p:InstallersTargetStaticFeed=$(InternalInstallersBlobFeedUrl)
+ /p:InstallersAzureAccountKey=$(InternalInstallersBlobFeedKey)
+ /p:AzureDevOpsStaticShippingFeed='${{ parameters.shippingFeed }}'
+ /p:AzureDevOpsStaticShippingFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:AzureDevOpsStaticTransportFeed='${{ parameters.transportFeed }}'
+ /p:AzureDevOpsStaticTransportFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:AzureDevOpsStaticSymbolsFeed='${{ parameters.symbolsFeed }}'
+ /p:AzureDevOpsStaticSymbolsFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:PublishToMSDL=false
+ ${{ parameters.artifactsPublishingAdditionalParameters }}
+
+ - template: ../../steps/publish-logs.yml
+ parameters:
+ StageLabel: '${{ parameters.stageName }}'
+ JobLabel: 'AssetsPublishing'
+
+ - template: ../../steps/add-build-to-channel.yml
+ parameters:
+ ChannelId: ${{ parameters.channelId }}
diff --git a/eng/common/templates/post-build/channels/generic-public-channel.yml b/eng/common/templates/post-build/channels/generic-public-channel.yml
new file mode 100644
index 00000000000..6cf39dbb290
--- /dev/null
+++ b/eng/common/templates/post-build/channels/generic-public-channel.yml
@@ -0,0 +1,184 @@
+parameters:
+ BARBuildId: ''
+ PromoteToChannelIds: ''
+ artifactsPublishingAdditionalParameters: ''
+ dependsOn:
+ - Validate
+ publishInstallersAndChecksums: true
+ symbolPublishingAdditionalParameters: ''
+ stageName: ''
+ channelName: ''
+ channelId: ''
+ transportFeed: ''
+ shippingFeed: ''
+ symbolsFeed: ''
+ # If the channel name is empty, no links will be generated
+ akaMSChannelName: ''
+
+stages:
+- stage: ${{ parameters.stageName }}
+ dependsOn: ${{ parameters.dependsOn }}
+ variables:
+ - template: ../common-variables.yml
+ displayName: ${{ parameters.channelName }} Publishing
+ jobs:
+ - template: ../setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - job: publish_symbols
+ displayName: Symbol Publishing
+ dependsOn: setupMaestroVars
+ condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} ))
+ variables:
+ - group: DotNet-Symbol-Server-Pats
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Assets
+ continueOnError: true
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ downloadType: 'specific'
+ itemPattern: |
+ PdbArtifacts/**
+ BlobArtifacts/**
+ downloadPath: '$(Build.ArtifactStagingDirectory)'
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ # Since sdk-task.ps1 tries to restore packages we need to do this authentication here
+ # otherwise it'll complain about accessing a private feed.
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: eng\common\enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ - task: PowerShell@2
+ displayName: Publish
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task PublishToSymbolServers -restore -msbuildEngine dotnet
+ /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
+ /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
+ /p:PDBArtifactsDirectory='$(Build.ArtifactStagingDirectory)/PDBArtifacts/'
+ /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
+ /p:SymbolPublishingExclusionsFile='$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt'
+ /p:Configuration=Release
+ ${{ parameters.symbolPublishingAdditionalParameters }}
+
+ - template: ../../steps/publish-logs.yml
+ parameters:
+ StageLabel: '${{ parameters.stageName }}'
+ JobLabel: 'SymbolPublishing'
+
+ - job: publish_assets
+ displayName: Publish Assets
+ dependsOn: setupMaestroVars
+ timeoutInMinutes: 120
+ variables:
+ - name: BARBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
+ - name: IsStableBuild
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ]
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ - name: ArtifactsCategory
+ value: ${{ coalesce(variables._DotNetArtifactsCategory, '.NETCore') }}
+ condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} ))
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Assets
+ continueOnError: true
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ downloadType: 'specific'
+ itemPattern: |
+ PackageArtifacts/**
+ BlobArtifacts/**
+ AssetManifests/**
+ downloadPath: '$(Build.ArtifactStagingDirectory)'
+
+ - task: NuGetToolInstaller@1
+ displayName: 'Install NuGet.exe'
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: eng\common\enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ - task: PowerShell@2
+ displayName: Publish Assets
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
+ /p:PublishingInfraVersion=2
+ /p:ArtifactsCategory=$(ArtifactsCategory)
+ /p:IsStableBuild=$(IsStableBuild)
+ /p:IsInternalBuild=$(IsInternalBuild)
+ /p:RepositoryName=$(Build.Repository.Name)
+ /p:CommitSha=$(Build.SourceVersion)
+ /p:NugetPath=$(NuGetExeToolPath)
+ /p:AzdoTargetFeedPAT='$(dn-bot-dnceng-universal-packages-rw)'
+ /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)'
+ /p:BARBuildId=$(BARBuildId)
+ /p:MaestroApiEndpoint='$(MaestroApiEndPoint)'
+ /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)'
+ /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/'
+ /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
+ /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/'
+ /p:Configuration=Release
+ /p:PublishInstallersAndChecksums=${{ parameters.publishInstallersAndChecksums }}
+ /p:InstallersTargetStaticFeed=$(InstallersBlobFeedUrl)
+ /p:InstallersAzureAccountKey=$(dotnetcli-storage-key)
+ /p:ChecksumsTargetStaticFeed=$(ChecksumsBlobFeedUrl)
+ /p:ChecksumsAzureAccountKey=$(dotnetclichecksums-storage-key)
+ /p:AzureDevOpsStaticShippingFeed='${{ parameters.shippingFeed }}'
+ /p:AzureDevOpsStaticShippingFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:AzureDevOpsStaticTransportFeed='${{ parameters.transportFeed }}'
+ /p:AzureDevOpsStaticTransportFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:AzureDevOpsStaticSymbolsFeed='${{ parameters.symbolsFeed }}'
+ /p:AzureDevOpsStaticSymbolsFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:LatestLinkShortUrlPrefix=dotnet/'${{ parameters.akaMSChannelName }}'
+ /p:AkaMSClientId=$(akams-client-id)
+ /p:AkaMSClientSecret=$(akams-client-secret)
+ ${{ parameters.artifactsPublishingAdditionalParameters }}
+
+ - template: ../../steps/publish-logs.yml
+ parameters:
+ StageLabel: '${{ parameters.stageName }}'
+ JobLabel: 'AssetsPublishing'
+
+ - template: ../../steps/add-build-to-channel.yml
+ parameters:
+ ChannelId: ${{ parameters.channelId }}
diff --git a/eng/common/templates/post-build/channels/internal-servicing.yml b/eng/common/templates/post-build/channels/internal-servicing.yml
deleted file mode 100644
index 12fd2b4653d..00000000000
--- a/eng/common/templates/post-build/channels/internal-servicing.yml
+++ /dev/null
@@ -1,147 +0,0 @@
-parameters:
- enableSymbolValidation: true
-
-stages:
-- stage: IS_Publish
- dependsOn: validate
- variables:
- - template: ../common-variables.yml
- displayName: Internal Servicing
- jobs:
- - template: ../setup-maestro-vars.yml
-
- - job:
- displayName: Symbol Publishing
- dependsOn: setupMaestroVars
- condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.InternalServicing_30_Channel_Id)
- variables:
- - group: DotNet-Symbol-Server-Pats
- pool:
- vmImage: 'windows-2019'
- steps:
- - task: DownloadBuildArtifacts@0
- displayName: Download Artifacts
- inputs:
- downloadType: specific files
- matchingPattern: "*Artifacts*"
-
- - task: PowerShell@2
- displayName: Publish
- inputs:
- filePath: eng\common\sdk-task.ps1
- arguments: -task PublishToSymbolServers -restore -msbuildEngine dotnet
- /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
- /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
- /p:PDBArtifactsDirectory='$(Build.ArtifactStagingDirectory)/PDBArtifacts/'
- /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
- /p:Configuration=Release
-
- - job: publish_assets
- displayName: Publish Assets
- dependsOn: setupMaestroVars
- variables:
- - group: DotNet-Blob-Feed
- - group: AzureDevOps-Artifact-Feeds-Pats
- - name: BARBuildId
- value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
- - name: IsStableBuild
- value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ]
- condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.InternalServicing_30_Channel_Id)
- pool:
- vmImage: 'windows-2019'
- steps:
- - task: DownloadBuildArtifacts@0
- displayName: Download Package Artifacts
- inputs:
- buildType: current
- artifactName: PackageArtifacts
-
- - task: DownloadBuildArtifacts@0
- displayName: Download Blob Artifacts
- inputs:
- buildType: current
- artifactName: BlobArtifacts
-
- - task: DownloadBuildArtifacts@0
- displayName: Download Asset Manifests
- inputs:
- buildType: current
- artifactName: AssetManifests
-
- - task: PowerShell@2
- displayName: Add Assets Location
- env:
- AZURE_DEVOPS_EXT_PAT: $(dn-bot-dnceng-unviersal-packages-rw)
- inputs:
- filePath: eng\common\sdk-task.ps1
- arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
- /p:ChannelId=$(InternalServicing_30_Channel_Id)
- /p:IsStableBuild=$(IsStableBuild)
- /p:IsInternalBuild=$(IsInternalBuild)
- /p:RepositoryName=$(Build.Repository.Name)
- /p:CommitSha=$(Build.SourceVersion)
- /p:AzureStorageAccountName=$(ProxyBackedFeedsAccountName)
- /p:AzureStorageAccountKey=$(dotnetfeed-storage-access-key-1)
- /p:AzureDevOpsFeedsBaseUrl=$(dotnetfeed-internal-private-feed-url)
- /p:StaticInternalFeed=$(dotnetfeed-internal-nonstable-feed-url)
- /p:NugetPath=$(Agent.BuildDirectory)\Nuget\NuGet.exe
- /p:BARBuildId=$(BARBuildId)
- /p:MaestroApiEndpoint='$(MaestroApiEndPoint)'
- /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)'
- /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/'
- /p:BlobBasePath='$(Build.ArtifactStagingDirectory)\BlobArtifacts'
- /p:PackageBasePath='$(Build.ArtifactStagingDirectory)\PackageArtifacts'
- /p:Configuration=Release
-
- - task: NuGetCommand@2
- displayName: Publish Packages to AzDO Feed
- condition: contains(variables['TargetAzDOFeed'], 'pkgs.visualstudio.com')
- inputs:
- command: push
- vstsFeed: $(AzDoFeedName)
- packagesToPush: $(Build.ArtifactStagingDirectory)\PackageArtifacts\*.nupkg
- publishVstsFeed: $(AzDoFeedName)
-
- - task: PowerShell@2
- displayName: Publish Blobs to AzDO Feed
- inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-blobs-to-azdo.ps1
- arguments: -FeedName $(AzDoFeedName)
- -SourceFolderCollection $(Build.ArtifactStagingDirectory)/BlobArtifacts/
- -PersonalAccessToken $(dn-bot-dnceng-unviersal-packages-rw)
- enabled: false
-
- - template: ../trigger-subscription.yml
- parameters:
- ChannelId: ${{ variables.InternalServicing_30_Channel_Id }}
-
-- stage: IS_PublishValidation
- displayName: Publish Validation
- variables:
- - template: ../common-variables.yml
- jobs:
- - template: ../setup-maestro-vars.yml
-
- - ${{ if eq(parameters.enableSymbolValidation, 'true') }}:
- - job:
- displayName: Symbol Availability
- dependsOn: setupMaestroVars
- condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.InternalServicing_30_Channel_Id)
- pool:
- vmImage: 'windows-2019'
- steps:
- - task: DownloadBuildArtifacts@0
- displayName: Download Package Artifacts
- inputs:
- buildType: current
- artifactName: PackageArtifacts
-
- - task: PowerShell@2
- displayName: Check Symbol Availability
- inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/symbols-validation.ps1
- arguments: -InputPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ -ExtractPath $(Agent.BuildDirectory)/Temp/ -DotnetSymbolVersion $(SymbolToolVersion)
-
- - template: ../promote-build.yml
- parameters:
- ChannelId: ${{ variables.InternalServicing_30_Channel_Id }}
diff --git a/eng/common/templates/post-build/channels/public-dev-release.yml b/eng/common/templates/post-build/channels/public-dev-release.yml
deleted file mode 100644
index afc5d364234..00000000000
--- a/eng/common/templates/post-build/channels/public-dev-release.yml
+++ /dev/null
@@ -1,147 +0,0 @@
-parameters:
- enableSymbolValidation: true
-
-stages:
-- stage: Publish
- dependsOn: validate
- variables:
- - template: ../common-variables.yml
- displayName: Developer Channel
- jobs:
- - template: ../setup-maestro-vars.yml
-
- - job:
- displayName: Symbol Publishing
- dependsOn: setupMaestroVars
- condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.PublicDevRelease_30_Channel_Id)
- variables:
- - group: DotNet-Symbol-Server-Pats
- pool:
- vmImage: 'windows-2019'
- steps:
- - task: DownloadBuildArtifacts@0
- displayName: Download Artifacts
- inputs:
- downloadType: specific files
- matchingPattern: "*Artifacts*"
-
- - task: PowerShell@2
- displayName: Publish
- inputs:
- filePath: eng\common\sdk-task.ps1
- arguments: -task PublishToSymbolServers -restore -msbuildEngine dotnet
- /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
- /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
- /p:PDBArtifactsDirectory='$(Build.ArtifactStagingDirectory)/PDBArtifacts/'
- /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
- /p:Configuration=Release
-
- - job:
- displayName: Publish Assets
- dependsOn: setupMaestroVars
- variables:
- - group: DotNet-Blob-Feed
- - group: AzureDevOps-Artifact-Feeds-Pats
- - name: BARBuildId
- value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
- - name: IsStableBuild
- value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ]
- condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.PublicDevRelease_30_Channel_Id)
- pool:
- vmImage: 'windows-2019'
- steps:
- - task: DownloadBuildArtifacts@0
- displayName: Download Package Artifacts
- inputs:
- buildType: current
- artifactName: PackageArtifacts
-
- - task: DownloadBuildArtifacts@0
- displayName: Download Blob Artifacts
- inputs:
- buildType: current
- artifactName: BlobArtifacts
-
- - task: DownloadBuildArtifacts@0
- displayName: Download Asset Manifests
- inputs:
- buildType: current
- artifactName: AssetManifests
-
- - task: PowerShell@2
- displayName: Add Assets Location
- env:
- AZURE_DEVOPS_EXT_PAT: $(dn-bot-dnceng-unviersal-packages-rw)
- inputs:
- filePath: eng\common\sdk-task.ps1
- arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
- /p:ChannelId=$(PublicDevRelease_30_Channel_Id)
- /p:ArtifactsCategory=$(_DotNetArtifactsCategory)
- /p:IsStableBuild=$(IsStableBuild)
- /p:IsInternalBuild=$(IsInternalBuild)
- /p:RepositoryName=$(Build.Repository.Name)
- /p:CommitSha=$(Build.SourceVersion)
- /p:NugetPath=$(Agent.BuildDirectory)\Nuget\NuGet.exe
- /p:AzdoTargetFeedPAT='$(dn-bot-dnceng-unviersal-packages-rw)'
- /p:TargetFeedPAT='$(dn-bot-dnceng-unviersal-packages-rw)'
- /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)'
- /p:BARBuildId=$(BARBuildId)
- /p:MaestroApiEndpoint='$(MaestroApiEndPoint)'
- /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)'
- /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/'
- /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
- /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/'
- /p:Configuration=Release
-
- - task: NuGetCommand@2
- displayName: Publish Packages to AzDO Feed
- condition: contains(variables['TargetAzDOFeed'], 'pkgs.visualstudio.com')
- inputs:
- command: push
- vstsFeed: $(AzDoFeedName)
- packagesToPush: $(Build.ArtifactStagingDirectory)\PackageArtifacts\*.nupkg
- publishVstsFeed: $(AzDoFeedName)
-
- - task: PowerShell@2
- displayName: Publish Blobs to AzDO Feed
- inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-blobs-to-azdo.ps1
- arguments: -FeedName $(AzDoFeedName)
- -SourceFolderCollection $(Build.ArtifactStagingDirectory)/BlobArtifacts/
- -PersonalAccessToken $(dn-bot-dnceng-unviersal-packages-rw)
- enabled: false
-
-- stage: PublishValidation
- displayName: Publish Validation
- variables:
- - template: ../common-variables.yml
- jobs:
- - template: ../setup-maestro-vars.yml
-
- - ${{ if eq(parameters.enableSymbolValidation, 'true') }}:
- - job:
- displayName: Symbol Availability
- dependsOn: setupMaestroVars
- condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.PublicDevRelease_30_Channel_Id)
- pool:
- vmImage: 'windows-2019'
- steps:
- - task: DownloadBuildArtifacts@0
- displayName: Download Package Artifacts
- inputs:
- buildType: current
- artifactName: PackageArtifacts
-
- - task: PowerShell@2
- displayName: Check Symbol Availability
- inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/symbols-validation.ps1
- arguments: -InputPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ -ExtractPath $(Agent.BuildDirectory)/Temp/ -DotnetSymbolVersion $(SymbolToolVersion)
-
- - template: ../darc-gather-drop.yml
- parameters:
- ChannelId: ${{ variables.PublicDevRelease_30_Channel_Id }}
-
- - template: ../promote-build.yml
- parameters:
- ChannelId: ${{ variables.PublicDevRelease_30_Channel_Id }}
diff --git a/eng/common/templates/post-build/channels/public-release.yml b/eng/common/templates/post-build/channels/public-release.yml
deleted file mode 100644
index 4c63fb43f0c..00000000000
--- a/eng/common/templates/post-build/channels/public-release.yml
+++ /dev/null
@@ -1,147 +0,0 @@
-parameters:
- enableSymbolValidation: true
-
-stages:
-- stage: PubRel_Publish
- dependsOn: validate
- variables:
- - template: ../common-variables.yml
- displayName: Public Release
- jobs:
- - template: ../setup-maestro-vars.yml
-
- - job:
- displayName: Symbol Publishing
- dependsOn: setupMaestroVars
- condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.PublicRelease_30_Channel_Id)
- variables:
- - group: DotNet-Symbol-Server-Pats
- pool:
- vmImage: 'windows-2019'
- steps:
- - task: DownloadBuildArtifacts@0
- displayName: Download Artifacts
- inputs:
- downloadType: specific files
- matchingPattern: "*Artifacts*"
-
- - task: PowerShell@2
- displayName: Publish
- inputs:
- filePath: eng\common\sdk-task.ps1
- arguments: -task PublishToSymbolServers -restore -msbuildEngine dotnet
- /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
- /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
- /p:PDBArtifactsDirectory='$(Build.ArtifactStagingDirectory)/PDBArtifacts/'
- /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
- /p:Configuration=Release
-
- - job: publish_assets
- displayName: Publish Assets
- dependsOn: setupMaestroVars
- variables:
- - group: DotNet-Blob-Feed
- - group: AzureDevOps-Artifact-Feeds-Pats
- - name: BARBuildId
- value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
- - name: IsStableBuild
- value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ]
- condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.PublicRelease_30_Channel_Id)
- pool:
- vmImage: 'windows-2019'
- steps:
- - task: DownloadBuildArtifacts@0
- displayName: Download Package Artifacts
- inputs:
- buildType: current
- artifactName: PackageArtifacts
-
- - task: DownloadBuildArtifacts@0
- displayName: Download Blob Artifacts
- inputs:
- buildType: current
- artifactName: BlobArtifacts
-
- - task: DownloadBuildArtifacts@0
- displayName: Download Asset Manifests
- inputs:
- buildType: current
- artifactName: AssetManifests
-
- - task: PowerShell@2
- displayName: Publish
- env:
- AZURE_DEVOPS_EXT_PAT: $(dn-bot-dnceng-unviersal-packages-rw)
- inputs:
- filePath: eng\common\sdk-task.ps1
- arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
- /p:ChannelId=$(PublicRelease_30_Channel_Id)
- /p:IsStableBuild=$(IsStableBuild)
- /p:IsInternalBuild=$(IsInternalBuild)
- /p:RepositoryName=$(Build.Repository.Name)
- /p:CommitSha=$(Build.SourceVersion)
- /p:AzureStorageAccountName=$(ProxyBackedFeedsAccountName)
- /p:AzureStorageAccountKey=$(dotnetfeed-storage-access-key-1)
- /p:AzureDevOpsFeedsBaseUrl=$(dotnetfeed-internal-private-feed-url)
- /p:StaticInternalFeed=$(dotnetfeed-internal-nonstable-feed-url)
- /p:NugetPath=$(Agent.BuildDirectory)\Nuget\NuGet.exe
- /p:BARBuildId=$(BARBuildId)
- /p:MaestroApiEndpoint='$(MaestroApiEndPoint)'
- /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)'
- /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/'
- /p:BlobBasePath='$(Build.ArtifactStagingDirectory)\BlobArtifacts'
- /p:PackageBasePath='$(Build.ArtifactStagingDirectory)\PackageArtifacts'
- /p:Configuration=Release
-
- - task: NuGetCommand@2
- displayName: Publish Packages to AzDO Feed
- condition: contains(variables['TargetAzDOFeed'], 'pkgs.visualstudio.com')
- inputs:
- command: push
- vstsFeed: $(AzDoFeedName)
- packagesToPush: $(Build.ArtifactStagingDirectory)\PackageArtifacts\*.nupkg
- publishVstsFeed: $(AzDoFeedName)
-
- - task: PowerShell@2
- displayName: Publish Blobs to AzDO Feed
- inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-blobs-to-azdo.ps1
- arguments: -FeedName $(AzDoFeedName)
- -SourceFolderCollection $(Build.ArtifactStagingDirectory)/BlobArtifacts/
- -PersonalAccessToken $(dn-bot-dnceng-unviersal-packages-rw)
- enabled: false
-
- - template: ../trigger-subscription.yml
- parameters:
- ChannelId: ${{ variables.PublicRelease_30_Channel_Id }}
-
-- stage: PubRel_PublishValidation
- displayName: Publish Validation
- variables:
- - template: ../common-variables.yml
- jobs:
- - template: ../setup-maestro-vars.yml
-
- - ${{ if eq(parameters.enableSymbolValidation, 'true') }}:
- - job:
- displayName: Symbol Availability
- dependsOn: setupMaestroVars
- condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.PublicRelease_30_Channel_Id)
- pool:
- vmImage: 'windows-2019'
- steps:
- - task: DownloadBuildArtifacts@0
- displayName: Download Package Artifacts
- inputs:
- buildType: current
- artifactName: PackageArtifacts
-
- - task: PowerShell@2
- displayName: Check Symbol Availability
- inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/symbols-validation.ps1
- arguments: -InputPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/ -ExtractPath $(Agent.BuildDirectory)/Temp/ -DotnetSymbolVersion $(SymbolToolVersion)
-
- - template: ../promote-build.yml
- parameters:
- ChannelId: ${{ variables.PublicRelease_30_Channel_Id }}
diff --git a/eng/common/templates/post-build/channels/public-validation-release.yml b/eng/common/templates/post-build/channels/public-validation-release.yml
deleted file mode 100644
index 1089ac5fa6b..00000000000
--- a/eng/common/templates/post-build/channels/public-validation-release.yml
+++ /dev/null
@@ -1,99 +0,0 @@
-stages:
-- stage: PVR_Publish
- dependsOn: validate
- variables:
- - template: ../common-variables.yml
- displayName: Validation Channel
- jobs:
- - template: ../setup-maestro-vars.yml
-
- - job:
- displayName: Publish Assets
- dependsOn: setupMaestroVars
- variables:
- - group: DotNet-Blob-Feed
- - group: AzureDevOps-Artifact-Feeds-Pats
- - name: BARBuildId
- value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
- - name: IsStableBuild
- value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ]
- condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], variables.PublicValidationRelease_30_Channel_Id)
- pool:
- vmImage: 'windows-2019'
- steps:
- - task: DownloadBuildArtifacts@0
- displayName: Download Package Artifacts
- inputs:
- buildType: current
- artifactName: PackageArtifacts
-
- - task: DownloadBuildArtifacts@0
- displayName: Download Blob Artifacts
- inputs:
- buildType: current
- artifactName: BlobArtifacts
-
- - task: DownloadBuildArtifacts@0
- displayName: Download Asset Manifests
- inputs:
- buildType: current
- artifactName: AssetManifests
-
- - task: PowerShell@2
- displayName: Add Assets Location
- env:
- AZURE_DEVOPS_EXT_PAT: $(dn-bot-dnceng-unviersal-packages-rw)
- inputs:
- filePath: eng\common\sdk-task.ps1
- arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
- /p:ChannelId=$(PublicValidationRelease_30_Channel_Id)
- /p:ArtifactsCategory=$(_DotNetValidationArtifactsCategory)
- /p:IsStableBuild=$(IsStableBuild)
- /p:IsInternalBuild=$(IsInternalBuild)
- /p:RepositoryName=$(Build.Repository.Name)
- /p:CommitSha=$(Build.SourceVersion)
- /p:NugetPath=$(Agent.BuildDirectory)\Nuget\NuGet.exe
- /p:AzdoTargetFeedPAT='$(dn-bot-dnceng-unviersal-packages-rw)'
- /p:TargetFeedPAT='$(dn-bot-dnceng-unviersal-packages-rw)'
- /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)'
- /p:BARBuildId=$(BARBuildId)
- /p:MaestroApiEndpoint='$(MaestroApiEndPoint)'
- /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)'
- /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/'
- /p:BlobBasePath='$(Build.ArtifactStagingDirectory)\BlobArtifacts'
- /p:PackageBasePath='$(Build.ArtifactStagingDirectory)\PackageArtifacts'
- /p:Configuration=Release
-
- - task: NuGetCommand@2
- displayName: Publish Packages to AzDO Feed
- condition: contains(variables['TargetAzDOFeed'], 'pkgs.visualstudio.com')
- inputs:
- command: push
- vstsFeed: $(AzDoFeedName)
- packagesToPush: $(Build.ArtifactStagingDirectory)\PackageArtifacts\*.nupkg
- publishVstsFeed: $(AzDoFeedName)
-
- - task: PowerShell@2
- displayName: Publish Blobs to AzDO Feed
- inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-blobs-to-azdo.ps1
- arguments: -FeedName $(AzDoFeedName)
- -SourceFolderCollection $(Build.ArtifactStagingDirectory)/BlobArtifacts/
- -PersonalAccessToken $(dn-bot-dnceng-unviersal-packages-rw)
- enabled: false
-
-
-- stage: PVR_PublishValidation
- displayName: Publish Validation
- variables:
- - template: ../common-variables.yml
- jobs:
- - template: ../setup-maestro-vars.yml
-
- - template: ../darc-gather-drop.yml
- parameters:
- ChannelId: ${{ variables.PublicValidationRelease_30_Channel_Id }}
-
- - template: ../promote-build.yml
- parameters:
- ChannelId: ${{ variables.PublicValidationRelease_30_Channel_Id }}
diff --git a/eng/common/templates/post-build/common-variables.yml b/eng/common/templates/post-build/common-variables.yml
index bd0bc5e4daa..c99fd750376 100644
--- a/eng/common/templates/post-build/common-variables.yml
+++ b/eng/common/templates/post-build/common-variables.yml
@@ -1,14 +1,34 @@
variables:
+ - group: AzureDevOps-Artifact-Feeds-Pats
+ - group: DotNet-Blob-Feed
+ - group: DotNet-DotNetCli-Storage
+ - group: DotNet-MSRC-Storage
- group: Publish-Build-Assets
+
+ # .NET Core 3.1 Dev
+ - name: PublicDevRelease_31_Channel_Id
+ value: 128
- # .NET Core 3 Dev
- - name: PublicDevRelease_30_Channel_Id
- value: 3
+ # .NET 5 Dev
+ - name: Net_5_Dev_Channel_Id
+ value: 131
- # .NET Tools - Validation
- - name: PublicValidationRelease_30_Channel_Id
+ # .NET Eng - Validation
+ - name: Net_Eng_Validation_Channel_Id
value: 9
+ # .NET Eng - Latest
+ - name: Net_Eng_Latest_Channel_Id
+ value: 2
+
+ # .NET 3 Eng - Validation
+ - name: NET_3_Eng_Validation_Channel_Id
+ value: 390
+
+ # .NET 3 Eng
+ - name: NetCore_3_Tools_Channel_Id
+ value: 344
+
# .NET Core 3.0 Internal Servicing
- name: InternalServicing_30_Channel_Id
value: 184
@@ -17,23 +37,63 @@ variables:
- name: PublicRelease_30_Channel_Id
value: 19
+ # .NET Core 3.1 Release
+ - name: PublicRelease_31_Channel_Id
+ value: 129
+
+ # General Testing
+ - name: GeneralTesting_Channel_Id
+ value: 529
+
+ # .NET Core 3.1 Blazor Features
+ - name: NetCore_31_Blazor_Features_Channel_Id
+ value: 531
+
+ # .NET Core Experimental
+ - name: NetCore_Experimental_Channel_Id
+ value: 562
+
# Whether the build is internal or not
- name: IsInternalBuild
value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }}
- # Storage account name for proxy-backed feeds
- - name: ProxyBackedFeedsAccountName
- value: dotnetfeed
-
# Default Maestro++ API Endpoint and API Version
- name: MaestroApiEndPoint
value: "https://maestro-prod.westus2.cloudapp.azure.com"
- name: MaestroApiAccessToken
value: $(MaestroAccessToken)
- name: MaestroApiVersion
- value: "2019-01-16"
+ value: "2020-02-20"
- name: SourceLinkCLIVersion
value: 3.0.0
- name: SymbolToolVersion
value: 1.0.1
+
+ # Feed Configurations
+ # These should include the suffix "/index.json"
+
+ # Default locations for Installers and checksums
+ # Public Locations
+ - name: ChecksumsBlobFeedUrl
+ value: https://dotnetclichecksums.blob.core.windows.net/dotnet/index.json
+ - name: InstallersBlobFeedUrl
+ value: https://dotnetcli.blob.core.windows.net/dotnet/index.json
+
+ # Private Locations
+ - name: InternalChecksumsBlobFeedUrl
+ value: https://dotnetclichecksumsmsrc.blob.core.windows.net/dotnet/index.json
+ - name: InternalChecksumsBlobFeedKey
+ value: $(dotnetclichecksumsmsrc-storage-key)
+
+ - name: InternalInstallersBlobFeedUrl
+ value: https://dotnetclimsrc.blob.core.windows.net/dotnet/index.json
+ - name: InternalInstallersBlobFeedKey
+ value: $(dotnetclimsrc-access-key)
+
+ # Skip component governance and codesign validation for SDL. These jobs
+ # create no content.
+ - name: skipComponentGovernanceDetection
+ value: true
+ - name: runCodesignValidationInjection
+ value: false
diff --git a/eng/common/templates/post-build/darc-gather-drop.yml b/eng/common/templates/post-build/darc-gather-drop.yml
deleted file mode 100644
index f4e3bfcf5cd..00000000000
--- a/eng/common/templates/post-build/darc-gather-drop.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-parameters:
- ChannelId: 0
-
-jobs:
-- job: gatherDrop
- displayName: Gather Drop
- dependsOn: setupMaestroVars
- condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], ${{ parameters.ChannelId }})
- variables:
- - name: BARBuildId
- value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
- pool:
- vmImage: 'windows-2019'
- steps:
- - task: PowerShell@2
- displayName: Darc gather-drop
- inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/darc-gather-drop.ps1
- arguments: -BarBuildId $(BARBuildId)
- -DropLocation $(Agent.BuildDirectory)/Temp/Drop/
- -MaestroApiAccessToken $(MaestroApiAccessToken)
- -MaestroApiEndPoint $(MaestroApiEndPoint)
- -MaestroApiVersion $(MaestroApiVersion)
diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml
index 0872db4ed94..41f2d96a608 100644
--- a/eng/common/templates/post-build/post-build.yml
+++ b/eng/common/templates/post-build/post-build.yml
@@ -1,30 +1,119 @@
parameters:
- enableSourceLinkValidation: true
+ # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST.
+ # Publishing V2 accepts optionally outlining the publishing stages - default is inline.
+ # Publishing V3 DOES NOT accept inlining the publishing stages.
+ publishingInfraVersion: 2
+ # When set to true the publishing templates from the repo will be used
+ # otherwise Darc add-build-to-channel will be used to trigger the promotion pipeline
+ inline: true
+
+ # Only used if inline==false. When set to true will stall the current build until
+ # the Promotion Pipeline build finishes. Otherwise, the current build will continue
+ # execution concurrently with the promotion build.
+ waitPublishingFinish: true
+
+ BARBuildId: ''
+ PromoteToChannelIds: ''
+
+ enableSourceLinkValidation: false
enableSigningValidation: true
- enableSymbolValidation: true
+ enableSymbolValidation: false
enableNugetValidation: true
+ publishInstallersAndChecksums: true
SDLValidationParameters:
enable: false
+ continueOnError: false
params: ''
+ artifactNames: ''
+ downloadArtifacts: true
+
+ # These parameters let the user customize the call to sdk-task.ps1 for publishing
+ # symbols & general artifacts as well as for signing validation
+ symbolPublishingAdditionalParameters: ''
+ artifactsPublishingAdditionalParameters: ''
+ signingValidationAdditionalParameters: ''
# Which stages should finish execution before post-build stages start
- dependsOn: [build]
+ validateDependsOn:
+ - build
+ publishDependsOn:
+ - Validate
+ # Channel ID's instantiated in this file.
+ # When adding a new channel implementation the call to `check-channel-consistency.ps1`
+ # needs to be updated with the new channel ID
+ NetEngLatestChannelId: 2
+ NetEngValidationChannelId: 9
+ NetDev5ChannelId: 131
+ NetDev6ChannelId: 1296
+ GeneralTestingChannelId: 529
+ NETCoreToolingDevChannelId: 548
+ NETCoreToolingReleaseChannelId: 549
+ NETInternalToolingChannelId: 551
+ NETCoreExperimentalChannelId: 562
+ NetEngServicesIntChannelId: 678
+ NetEngServicesProdChannelId: 679
+ NetCoreSDK313xxChannelId: 759
+ NetCoreSDK313xxInternalChannelId: 760
+ NetCoreSDK314xxChannelId: 921
+ NetCoreSDK314xxInternalChannelId: 922
+ VS166ChannelId: 1010
+ VS167ChannelId: 1011
+ VS168ChannelId: 1154
+ VSMasterChannelId: 1012
+
stages:
-- stage: validate
- dependsOn: ${{ parameters.dependsOn }}
- displayName: Validate
- jobs:
- - ${{ if eq(parameters.enableNugetValidation, 'true') }}:
+- ${{ if or(and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')), eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:
+ - stage: Validate
+ dependsOn: ${{ parameters.validateDependsOn }}
+ displayName: Validate Build Assets
+ variables:
+ - template: common-variables.yml
+ jobs:
+ - template: setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - ${{ if and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')) }}:
+ - job:
+ displayName: Post-build Checks
+ dependsOn: setupMaestroVars
+ variables:
+ - name: TargetChannels
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: PowerShell@2
+ displayName: Maestro Channels Consistency
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/check-channel-consistency.ps1
+ arguments: -PromoteToChannels "$(TargetChannels)"
+ -AvailableChannelIds ${{parameters.NetEngLatestChannelId}},${{parameters.NetEngValidationChannelId}},${{parameters.NetDev5ChannelId}},${{parameters.NetDev6ChannelId}},${{parameters.GeneralTestingChannelId}},${{parameters.NETCoreToolingDevChannelId}},${{parameters.NETCoreToolingReleaseChannelId}},${{parameters.NETInternalToolingChannelId}},${{parameters.NETCoreExperimentalChannelId}},${{parameters.NetEngServicesIntChannelId}},${{parameters.NetEngServicesProdChannelId}},${{parameters.NetCoreSDK313xxChannelId}},${{parameters.NetCoreSDK313xxInternalChannelId}},${{parameters.NetCoreSDK314xxChannelId}},${{parameters.NetCoreSDK314xxInternalChannelId}},${{parameters.VS166ChannelId}},${{parameters.VS167ChannelId}},${{parameters.VS168ChannelId}},${{parameters.VSMasterChannelId}}
+
- job:
displayName: NuGet Validation
+ dependsOn: setupMaestroVars
+ condition: eq( ${{ parameters.enableNugetValidation }}, 'true')
pool:
vmImage: 'windows-2019'
+ variables:
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
steps:
- task: DownloadBuildArtifacts@0
displayName: Download Package Artifacts
inputs:
- buildType: current
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
artifactName: PackageArtifacts
- task: PowerShell@2
@@ -34,38 +123,82 @@ stages:
arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/
-ToolDestinationPath $(Agent.BuildDirectory)/Extract/
- - ${{ if eq(parameters.enableSigningValidation, 'true') }}:
- job:
displayName: Signing Validation
+ dependsOn: setupMaestroVars
+ condition: eq( ${{ parameters.enableSigningValidation }}, 'true')
+ variables:
+ - template: common-variables.yml
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
pool:
vmImage: 'windows-2019'
steps:
- task: DownloadBuildArtifacts@0
displayName: Download Package Artifacts
inputs:
- buildType: current
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
artifactName: PackageArtifacts
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ # Since sdk-task.ps1 tries to restore packages we need to do this authentication here
+ # otherwise it'll complain about accessing a private feed.
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: eng\common\enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ # Signing validation will optionally work with the buildmanifest file which is downloaded from
+ # Azure DevOps above.
- task: PowerShell@2
displayName: Validate
inputs:
filePath: eng\common\sdk-task.ps1
- arguments: -task SigningValidation -restore -msbuildEngine dotnet
+ arguments: -task SigningValidation -restore -msbuildEngine vs
/p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts'
- /p:Configuration=Release
+ /p:SignCheckExclusionsFile='$(Build.SourcesDirectory)/eng/SignCheckExclusionsFile.txt'
+ ${{ parameters.signingValidationAdditionalParameters }}
+
+ - template: ../steps/publish-logs.yml
+ parameters:
+ StageLabel: 'Validation'
+ JobLabel: 'Signing'
- - ${{ if eq(parameters.enableSourceLinkValidation, 'true') }}:
- job:
displayName: SourceLink Validation
+ dependsOn: setupMaestroVars
+ condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true')
variables:
- template: common-variables.yml
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
pool:
vmImage: 'windows-2019'
steps:
- task: DownloadBuildArtifacts@0
displayName: Download Blob Artifacts
inputs:
- buildType: current
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
artifactName: BlobArtifacts
- task: PowerShell@2
@@ -77,18 +210,342 @@ stages:
-GHRepoName $(Build.Repository.Name)
-GHCommit $(Build.SourceVersion)
-SourcelinkCliVersion $(SourceLinkCLIVersion)
+ continueOnError: true
- - ${{ if eq(parameters.SDLValidationParameters.enable, 'true') }}:
- template: /eng/common/templates/job/execute-sdl.yml
parameters:
+ enable: ${{ parameters.SDLValidationParameters.enable }}
+ dependsOn: setupMaestroVars
additionalParameters: ${{ parameters.SDLValidationParameters.params }}
+ continueOnError: ${{ parameters.SDLValidationParameters.continueOnError }}
+ artifactNames: ${{ parameters.SDLValidationParameters.artifactNames }}
+ downloadArtifacts: ${{ parameters.SDLValidationParameters.downloadArtifacts }}
+
+- ${{ if or(ge(parameters.publishingInfraVersion, 3), eq(parameters.inline, 'false')) }}:
+ - stage: publish_using_darc
+ ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:
+ dependsOn: Validate
+ ${{ if and(ne(parameters.enableNugetValidation, 'true'), ne(parameters.enableSigningValidation, 'true'), ne(parameters.enableSourceLinkValidation, 'true'), ne(parameters.SDLValidationParameters.enable, 'true')) }}:
+ dependsOn: ${{ parameters.validateDependsOn }}
+ displayName: Publish using Darc
+ variables:
+ - template: common-variables.yml
+ jobs:
+ - template: setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - job:
+ displayName: Publish Using Darc
+ dependsOn: setupMaestroVars
+ timeoutInMinutes: 120
+ variables:
+ - name: BARBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: PowerShell@2
+ displayName: Publish Using Darc
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
+ arguments: -BuildId $(BARBuildId)
+ -PublishingInfraVersion ${{ parameters.PublishingInfraVersion }}
+ -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
+ -MaestroToken '$(MaestroApiAccessToken)'
+ -WaitPublishingFinish ${{ parameters.waitPublishingFinish }}
+ -PublishInstallersAndChecksums ${{ parameters.publishInstallersAndChecksums }}
+ -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
+ -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
+
+- ${{ if and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')) }}:
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NetCore_Dev5_Publish'
+ channelName: '.NET 5 Dev'
+ akaMSChannelName: 'net5/dev'
+ channelId: ${{ parameters.NetDev5ChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NetCore_Dev6_Publish'
+ channelName: '.NET 6 Dev'
+ akaMSChannelName: 'net6/dev'
+ channelId: ${{ parameters.NetDev6ChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'Net_Eng_Latest_Publish'
+ channelName: '.NET Eng - Latest'
+ akaMSChannelName: 'eng/daily'
+ channelId: ${{ parameters.NetEngLatestChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'Net_Eng_Validation_Publish'
+ channelName: '.NET Eng - Validation'
+ akaMSChannelName: 'eng/validation'
+ channelId: ${{ parameters.NetEngValidationChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'General_Testing_Publish'
+ channelName: 'General Testing'
+ akaMSChannelName: 'generaltesting'
+ channelId: ${{ parameters.GeneralTestingChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_Tooling_Dev_Publishing'
+ channelName: '.NET Core Tooling Dev'
+ channelId: ${{ parameters.NETCoreToolingDevChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_Tooling_Release_Publishing'
+ channelName: '.NET Core Tooling Release'
+ channelId: ${{ parameters.NETCoreToolingReleaseChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NET_Internal_Tooling_Publishing'
+ channelName: '.NET Internal Tooling'
+ channelId: ${{ parameters.NETInternalToolingChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_Experimental_Publishing'
+ channelName: '.NET Core Experimental'
+ channelId: ${{ parameters.NETCoreExperimentalChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'Net_Eng_Services_Int_Publish'
+ channelName: '.NET Eng Services - Int'
+ channelId: ${{ parameters.NetEngServicesIntChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'Net_Eng_Services_Prod_Publish'
+ channelName: '.NET Eng Services - Prod'
+ channelId: ${{ parameters.NetEngServicesProdChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_SDK_314xx_Publishing'
+ channelName: '.NET Core SDK 3.1.4xx'
+ channelId: ${{ parameters.NetCoreSDK314xxChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_SDK_314xx_Internal_Publishing'
+ channelName: '.NET Core SDK 3.1.4xx Internal'
+ channelId: ${{ parameters.NetCoreSDK314xxInternalChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_SDK_313xx_Publishing'
+ channelName: '.NET Core SDK 3.1.3xx'
+ channelId: ${{ parameters.NetCoreSDK313xxChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-symbols/nuget/v3/index.json'
-- template: \eng\common\templates\post-build\channels\public-dev-release.yml
- parameters:
- enableSymbolValidation: ${{ parameters.enableSymbolValidation }}
+ - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_SDK_313xx_Internal_Publishing'
+ channelName: '.NET Core SDK 3.1.3xx Internal'
+ channelId: ${{ parameters.NetCoreSDK313xxInternalChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-symbols/nuget/v3/index.json'
-- template: \eng\common\templates\post-build\channels\public-validation-release.yml
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'VS16_6_Publishing'
+ channelName: 'VS 16.6'
+ channelId: ${{ parameters.VS166ChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
-- template: \eng\common\templates\post-build\channels\public-release.yml
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'VS16_7_Publishing'
+ channelName: 'VS 16.7'
+ channelId: ${{ parameters.VS167ChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'VS16_8_Publishing'
+ channelName: 'VS 16.8'
+ channelId: ${{ parameters.VS168ChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
-- template: \eng\common\templates\post-build\channels\internal-servicing.yml
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'VS_Master_Publishing'
+ channelName: 'VS Master'
+ channelId: ${{ parameters.VSMasterChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
diff --git a/eng/common/templates/post-build/promote-build.yml b/eng/common/templates/post-build/promote-build.yml
deleted file mode 100644
index 9387c583b31..00000000000
--- a/eng/common/templates/post-build/promote-build.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-parameters:
- ChannelId: 0
-
-jobs:
-- job:
- displayName: Promote Build
- dependsOn: setupMaestroVars
- condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], ${{ parameters.ChannelId }})
- variables:
- - name: BARBuildId
- value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
- - name: ChannelId
- value: ${{ parameters.ChannelId }}
- pool:
- vmImage: 'windows-2019'
- steps:
- - task: PowerShell@2
- displayName: Add Build to Channel
- inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/promote-build.ps1
- arguments: -BuildId $(BARBuildId)
- -ChannelId $(ChannelId)
- -MaestroApiAccessToken $(MaestroApiAccessToken)
- -MaestroApiEndPoint $(MaestroApiEndPoint)
- -MaestroApiVersion $(MaestroApiVersion)
diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml
index 56242b068e1..d0cbfb6c6ff 100644
--- a/eng/common/templates/post-build/setup-maestro-vars.yml
+++ b/eng/common/templates/post-build/setup-maestro-vars.yml
@@ -1,18 +1,77 @@
+parameters:
+ BARBuildId: ''
+ PromoteToChannelIds: ''
+
jobs:
- job: setupMaestroVars
displayName: Setup Maestro Vars
+ variables:
+ - template: common-variables.yml
pool:
vmImage: 'windows-2019'
steps:
- - task: DownloadBuildArtifacts@0
- displayName: Download Release Configs
- inputs:
- buildType: current
- artifactName: ReleaseConfigs
+ - checkout: none
+
+ - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Release Configs
+ inputs:
+ buildType: current
+ artifactName: ReleaseConfigs
- task: PowerShell@2
name: setReleaseVars
displayName: Set Release Configs Vars
inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/setup-maestro-vars.ps1
- arguments: -ReleaseConfigsPath '$(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt'
+ targetType: inline
+ script: |
+ try {
+ if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') {
+ $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt
+
+ $BarId = $Content | Select -Index 0
+ $Channels = $Content | Select -Index 1
+ $IsStableBuild = $Content | Select -Index 2
+
+ $AzureDevOpsProject = $Env:System_TeamProject
+ $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId
+ $AzureDevOpsBuildId = $Env:Build_BuildId
+ }
+ else {
+ $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}"
+
+ $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]'
+ $apiHeaders.Add('Accept', 'application/json')
+ $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}")
+
+ $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" }
+
+ $BarId = $Env:BARBuildId
+ $Channels = $Env:PromoteToMaestroChannels -split ","
+ $Channels = $Channels -join "]["
+ $Channels = "[$Channels]"
+
+ $IsStableBuild = $buildInfo.stable
+ $AzureDevOpsProject = $buildInfo.azureDevOpsProject
+ $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId
+ $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId
+ }
+
+ Write-Host "##vso[task.setvariable variable=BARBuildId;isOutput=true]$BarId"
+ Write-Host "##vso[task.setvariable variable=TargetChannels;isOutput=true]$Channels"
+ Write-Host "##vso[task.setvariable variable=IsStableBuild;isOutput=true]$IsStableBuild"
+
+ Write-Host "##vso[task.setvariable variable=AzDOProjectName;isOutput=true]$AzureDevOpsProject"
+ Write-Host "##vso[task.setvariable variable=AzDOPipelineId;isOutput=true]$AzureDevOpsBuildDefinitionId"
+ Write-Host "##vso[task.setvariable variable=AzDOBuildId;isOutput=true]$AzureDevOpsBuildId"
+ }
+ catch {
+ Write-Host $_
+ Write-Host $_.Exception
+ Write-Host $_.ScriptStackTrace
+ exit 1
+ }
+ env:
+ MAESTRO_API_TOKEN: $(MaestroApiAccessToken)
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }}
diff --git a/eng/common/templates/steps/add-build-to-channel.yml b/eng/common/templates/steps/add-build-to-channel.yml
new file mode 100644
index 00000000000..f67a210d62f
--- /dev/null
+++ b/eng/common/templates/steps/add-build-to-channel.yml
@@ -0,0 +1,13 @@
+parameters:
+ ChannelId: 0
+
+steps:
+- task: PowerShell@2
+ displayName: Add Build to Channel
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/add-build-to-channel.ps1
+ arguments: -BuildId $(BARBuildId)
+ -ChannelId ${{ parameters.ChannelId }}
+ -MaestroApiAccessToken $(MaestroApiAccessToken)
+ -MaestroApiEndPoint $(MaestroApiEndPoint)
+ -MaestroApiVersion $(MaestroApiVersion)
diff --git a/eng/common/templates/steps/perf-send-to-helix.yml b/eng/common/templates/steps/perf-send-to-helix.yml
index b3ea9acf1f1..a468e92ce44 100644
--- a/eng/common/templates/steps/perf-send-to-helix.yml
+++ b/eng/common/templates/steps/perf-send-to-helix.yml
@@ -1,5 +1,6 @@
# Please remember to update the documentation if you make changes to these parameters!
parameters:
+ ProjectFile: '' # required -- project file that specifies the helix workitems
HelixSource: 'pr/default' # required -- sources must start with pr/, official/, prodcon/, or agent/
HelixType: 'tests/default/' # required -- Helix telemetry which identifies what type of data this is; should include "test" for clarity and must end in '/'
HelixBuild: $(Build.BuildNumber) # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number
@@ -10,7 +11,7 @@ parameters:
WorkItemDirectory: '' # optional -- a payload directory to zip up and send to Helix; requires WorkItemCommand; incompatible with XUnitProjects
CorrelationPayloadDirectory: '' # optional -- a directory to zip up and send to Helix as a correlation payload
IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion
- DotNetCliPackageType: '' # optional -- either 'sdk' or 'runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases.json
+ DotNetCliPackageType: '' # optional -- either 'sdk', 'runtime' or 'aspnetcore-runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases.json
DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases.json
EnableXUnitReporter: false # optional -- true enables XUnit result reporting to Mission Control
WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget."
@@ -18,33 +19,18 @@ parameters:
DisplayNamePrefix: 'Send job to Helix' # optional -- rename the beginning of the displayName of the steps in AzDO
condition: succeeded() # optional -- condition for step to execute; defaults to succeeded()
continueOnError: false # optional -- determines whether to continue the build if the step errors; defaults to false
+ osGroup: '' # required -- operating system for the job
+
steps:
- - powershell: $(Build.SourcesDirectory)\eng\common\msbuild.ps1 $(Build.SourcesDirectory)\eng\common\performance\perfhelixpublish.proj /restore /t:Test /bl:$(Build.SourcesDirectory)\artifacts\log\$env:BuildConfig\SendToHelix.binlog
- displayName: ${{ parameters.DisplayNamePrefix }} (Windows)
- env:
- BuildConfig: $(_BuildConfig)
- HelixSource: ${{ parameters.HelixSource }}
- HelixType: ${{ parameters.HelixType }}
- HelixBuild: ${{ parameters.HelixBuild }}
- HelixTargetQueues: ${{ parameters.HelixTargetQueues }}
- HelixAccessToken: ${{ parameters.HelixAccessToken }}
- HelixPreCommands: ${{ parameters.HelixPreCommands }}
- HelixPostCommands: ${{ parameters.HelixPostCommands }}
- WorkItemDirectory: ${{ parameters.WorkItemDirectory }}
- CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }}
- IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }}
- DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }}
- DotNetCliVersion: ${{ parameters.DotNetCliVersion }}
- EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }}
- WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}
- Creator: ${{ parameters.Creator }}
- SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT'))
+- template: /eng/pipelines/common/templates/runtimes/send-to-helix-inner-step.yml
+ parameters:
+ osGroup: ${{ parameters.osGroup }}
+ sendParams: $(Build.SourcesDirectory)/eng/common/performance/${{ parameters.ProjectFile }} /restore /t:Test /bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog
+ displayName: ${{ parameters.DisplayNamePrefix }}
+ condition: ${{ parameters.condition }}
continueOnError: ${{ parameters.continueOnError }}
- - script: $BUILD_SOURCESDIRECTORY/eng/common/msbuild.sh $BUILD_SOURCESDIRECTORY/eng/common/performance/perfhelixpublish.proj /restore /t:Test /bl:$BUILD_SOURCESDIRECTORY/artifacts/log/$BuildConfig/SendToHelix.binlog
- displayName: ${{ parameters.DisplayNamePrefix }} (Unix)
- env:
+ environment:
BuildConfig: $(_BuildConfig)
HelixSource: ${{ parameters.HelixSource }}
HelixType: ${{ parameters.HelixType }}
@@ -62,5 +48,3 @@ steps:
WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}
Creator: ${{ parameters.Creator }}
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT'))
- continueOnError: ${{ parameters.continueOnError }}
diff --git a/eng/common/templates/steps/publish-logs.yml b/eng/common/templates/steps/publish-logs.yml
new file mode 100644
index 00000000000..88f238f36bf
--- /dev/null
+++ b/eng/common/templates/steps/publish-logs.yml
@@ -0,0 +1,23 @@
+parameters:
+ StageLabel: ''
+ JobLabel: ''
+
+steps:
+- task: Powershell@2
+ displayName: Prepare Binlogs to Upload
+ inputs:
+ targetType: inline
+ script: |
+ New-Item -ItemType Directory $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/
+ Move-Item -Path $(Build.SourcesDirectory)/artifacts/log/Debug/* $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/
+ continueOnError: true
+ condition: always()
+
+- task: PublishBuildArtifacts@1
+ displayName: Publish Logs
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/PostBuildLogs'
+ PublishLocation: Container
+ ArtifactName: PostBuildLogs
+ continueOnError: true
+ condition: always()
diff --git a/eng/common/templates/steps/send-to-helix.yml b/eng/common/templates/steps/send-to-helix.yml
index 05df886f55f..bb5f1a92938 100644
--- a/eng/common/templates/steps/send-to-helix.yml
+++ b/eng/common/templates/steps/send-to-helix.yml
@@ -10,7 +10,7 @@ parameters:
HelixPostCommands: '' # optional -- commands to run after Helix work item execution
WorkItemDirectory: '' # optional -- a payload directory to zip up and send to Helix; requires WorkItemCommand; incompatible with XUnitProjects
WorkItemCommand: '' # optional -- a command to execute on the payload; requires WorkItemDirectory; incompatible with XUnitProjects
- WorkItemTimeout: '' # optional -- a timeout in seconds for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects
+ WorkItemTimeout: '' # optional -- a timeout in TimeSpan.Parse-ready value (e.g. 00:02:00) for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects
CorrelationPayloadDirectory: '' # optional -- a directory to zip up and send to Helix as a correlation payload
XUnitProjects: '' # optional -- semicolon delimited list of XUnitProjects to parse and send to Helix; requires XUnitRuntimeTargetFramework, XUnitPublishTargetFramework, XUnitRunnerVersion, and IncludeDotNetCli=true
XUnitWorkItemTimeout: '' # optional -- the workitem timeout in seconds for all workitems created from the xUnit projects specified by XUnitProjects
@@ -18,11 +18,12 @@ parameters:
XUnitRuntimeTargetFramework: '' # optional -- framework to use for the xUnit console runner
XUnitRunnerVersion: '' # optional -- version of the xUnit nuget package you wish to use on Helix; required for XUnitProjects
IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion
- DotNetCliPackageType: '' # optional -- either 'sdk' or 'runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases.json
- DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases.json
+ DotNetCliPackageType: '' # optional -- either 'sdk', 'runtime' or 'aspnetcore-runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases-index.json
+ DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases-index.json
EnableXUnitReporter: false # optional -- true enables XUnit result reporting to Mission Control
WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget."
IsExternal: false # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set
+ HelixBaseUri: 'https://helix.dot.net/' # optional -- sets the Helix API base URI (allows targeting int)
Creator: '' # optional -- if the build is external, use this to specify who is sending the job
DisplayNamePrefix: 'Run Tests' # optional -- rename the beginning of the displayName of the steps in AzDO
condition: succeeded() # optional -- condition for step to execute; defaults to succeeded()
@@ -55,6 +56,7 @@ steps:
DotNetCliVersion: ${{ parameters.DotNetCliVersion }}
EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }}
WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}
+ HelixBaseUri: ${{ parameters.HelixBaseUri }}
Creator: ${{ parameters.Creator }}
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT'))
@@ -85,6 +87,7 @@ steps:
DotNetCliVersion: ${{ parameters.DotNetCliVersion }}
EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }}
WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}
+ HelixBaseUri: ${{ parameters.HelixBaseUri }}
Creator: ${{ parameters.Creator }}
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT'))
diff --git a/eng/common/templates/steps/source-build.yml b/eng/common/templates/steps/source-build.yml
new file mode 100644
index 00000000000..8e336b7d16b
--- /dev/null
+++ b/eng/common/templates/steps/source-build.yml
@@ -0,0 +1,66 @@
+parameters:
+ # This template adds arcade-powered source-build to CI.
+
+ # This is a 'steps' template, and is intended for advanced scenarios where the existing build
+ # infra has a careful build methodology that must be followed. For example, a repo
+ # (dotnet/runtime) might choose to clone the GitHub repo only once and store it as a pipeline
+ # artifact for all subsequent jobs to use, to reduce dependence on a strong network connection to
+ # GitHub. Using this steps template leaves room for that infra to be included.
+
+ # Defines the platform on which to run the steps. See 'eng/common/templates/job/source-build.yml'
+ # for details. The entire object is described in the 'job' template for simplicity, even though
+ # the usage of the properties on this object is split between the 'job' and 'steps' templates.
+ platform: {}
+
+steps:
+# Build. Keep it self-contained for simple reusability. (No source-build-specific job variables.)
+- script: |
+ set -x
+ df -h
+
+ buildConfig=Release
+ # Check if AzDO substitutes in a build config from a variable, and use it if so.
+ if [ '$(_BuildConfig)' != '$''(_BuildConfig)' ]; then
+ buildConfig='$(_BuildConfig)'
+ fi
+
+ officialBuildArgs=
+ if [ '${{ and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}' = 'True' ]; then
+ officialBuildArgs='/p:DotNetPublishUsingPipelines=true /p:OfficialBuildId=$(BUILD.BUILDNUMBER)'
+ fi
+
+ targetRidArgs=
+ if [ '${{ parameters.platform.targetRID }}' != '' ]; then
+ targetRidArgs='/p:TargetRid=${{ parameters.platform.targetRID }}'
+ fi
+
+ ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \
+ --configuration $buildConfig \
+ --restore --build --pack --publish \
+ $officialBuildArgs \
+ $targetRidArgs \
+ /p:SourceBuildNonPortable=${{ parameters.platform.nonPortable }} \
+ /p:ArcadeBuildFromSource=true
+ displayName: Build
+
+# Upload build logs for diagnosis.
+- task: CopyFiles@2
+ displayName: Prepare BuildLogs staging directory
+ inputs:
+ SourceFolder: '$(Build.SourcesDirectory)'
+ Contents: |
+ **/*.log
+ **/*.binlog
+ artifacts/source-build/self/prebuilt-report/**
+ TargetFolder: '$(Build.StagingDirectory)/BuildLogs'
+ CleanTargetFolder: true
+ continueOnError: true
+ condition: succeededOrFailed()
+
+- task: PublishPipelineArtifact@1
+ displayName: Publish BuildLogs
+ inputs:
+ targetPath: '$(Build.StagingDirectory)/BuildLogs'
+ artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt)
+ continueOnError: true
+ condition: succeededOrFailed()
diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1
index 8fe2b11ad21..ce280eb95b1 100644
--- a/eng/common/tools.ps1
+++ b/eng/common/tools.ps1
@@ -5,11 +5,13 @@
[bool]$ci = if (Test-Path variable:ci) { $ci } else { $false }
# Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names.
-[string]$configuration = if (Test-Path variable:configuration) { $configuration } else { "Debug" }
+[string]$configuration = if (Test-Path variable:configuration) { $configuration } else { 'Debug' }
+
+# Set to true to opt out of outputting binary log while running in CI
+[bool]$excludeCIBinarylog = if (Test-Path variable:excludeCIBinarylog) { $excludeCIBinarylog } else { $false }
# Set to true to output binary log from msbuild. Note that emitting binary log slows down the build.
-# Binary log must be enabled on CI.
-[bool]$binaryLog = if (Test-Path variable:binaryLog) { $binaryLog } else { $ci }
+[bool]$binaryLog = if (Test-Path variable:binaryLog) { $binaryLog } else { $ci -and !$excludeCIBinarylog }
# Set to true to use the pipelines logger which will enable Azure logging output.
# https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md
@@ -24,7 +26,7 @@
[bool]$restore = if (Test-Path variable:restore) { $restore } else { $true }
# Adjusts msbuild verbosity level.
-[string]$verbosity = if (Test-Path variable:verbosity) { $verbosity } else { "minimal" }
+[string]$verbosity = if (Test-Path variable:verbosity) { $verbosity } else { 'minimal' }
# Set to true to reuse msbuild nodes. Recommended to not reuse on CI.
[bool]$nodeReuse = if (Test-Path variable:nodeReuse) { $nodeReuse } else { !$ci }
@@ -39,20 +41,29 @@
# installed on the machine instead of downloading one.
[bool]$useInstalledDotNetCli = if (Test-Path variable:useInstalledDotNetCli) { $useInstalledDotNetCli } else { $true }
+# Enable repos to use a particular version of the on-line dotnet-install scripts.
+# default URL: https://dot.net/v1/dotnet-install.ps1
+[string]$dotnetInstallScriptVersion = if (Test-Path variable:dotnetInstallScriptVersion) { $dotnetInstallScriptVersion } else { 'v1' }
+
# True to use global NuGet cache instead of restoring packages to repository-local directory.
[bool]$useGlobalNuGetCache = if (Test-Path variable:useGlobalNuGetCache) { $useGlobalNuGetCache } else { !$ci }
# An array of names of processes to stop on script exit if prepareMachine is true.
-$processesToStopOnExit = if (Test-Path variable:processesToStopOnExit) { $processesToStopOnExit } else { @("msbuild", "dotnet", "vbcscompiler") }
+$processesToStopOnExit = if (Test-Path variable:processesToStopOnExit) { $processesToStopOnExit } else { @('msbuild', 'dotnet', 'vbcscompiler') }
+
+$disableConfigureToolsetImport = if (Test-Path variable:disableConfigureToolsetImport) { $disableConfigureToolsetImport } else { $null }
set-strictmode -version 2.0
-$ErrorActionPreference = "Stop"
+$ErrorActionPreference = 'Stop'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
-function Create-Directory([string[]] $path) {
- if (!(Test-Path $path)) {
- New-Item -path $path -force -itemType "Directory" | Out-Null
- }
+# If specifies, provides an alternate path for getting .NET Core SDKs and Runtimes. This script will still try public sources first.
+[string]$runtimeSourceFeed = if (Test-Path variable:runtimeSourceFeed) { $runtimeSourceFeed } else { $null }
+# Base-64 encoded SAS token that has permission to storage container described by $runtimeSourceFeed
+[string]$runtimeSourceFeedKey = if (Test-Path variable:runtimeSourceFeedKey) { $runtimeSourceFeedKey } else { $null }
+
+function Create-Directory ([string[]] $path) {
+ New-Item -Path $path -Force -ItemType 'Directory' | Out-Null
}
function Unzip([string]$zipfile, [string]$outpath) {
@@ -92,7 +103,10 @@ function Exec-Process([string]$command, [string]$commandArgs) {
}
}
-function InitializeDotNetCli([bool]$install) {
+# createSdkLocationFile parameter enables a file being generated under the toolset directory
+# which writes the sdk's location into. This is only necessary for cmd --> powershell invocations
+# as dot sourcing isn't possible.
+function InitializeDotNetCli([bool]$install, [bool]$createSdkLocationFile) {
if (Test-Path variable:global:_DotNetInstallDir) {
return $global:_DotNetInstallDir
}
@@ -115,7 +129,9 @@ function InitializeDotNetCli([bool]$install) {
# Find the first path on %PATH% that contains the dotnet.exe
if ($useInstalledDotNetCli -and (-not $globalJsonHasRuntimes) -and ($env:DOTNET_INSTALL_DIR -eq $null)) {
- $dotnetCmd = Get-Command "dotnet.exe" -ErrorAction SilentlyContinue
+ $dotnetExecutable = GetExecutableFileName 'dotnet'
+ $dotnetCmd = Get-Command $dotnetExecutable -ErrorAction SilentlyContinue
+
if ($dotnetCmd -ne $null) {
$env:DOTNET_INSTALL_DIR = Split-Path $dotnetCmd.Path -Parent
}
@@ -128,13 +144,13 @@ function InitializeDotNetCli([bool]$install) {
if ((-not $globalJsonHasRuntimes) -and ($env:DOTNET_INSTALL_DIR -ne $null) -and (Test-Path(Join-Path $env:DOTNET_INSTALL_DIR "sdk\$dotnetSdkVersion"))) {
$dotnetRoot = $env:DOTNET_INSTALL_DIR
} else {
- $dotnetRoot = Join-Path $RepoRoot ".dotnet"
+ $dotnetRoot = Join-Path $RepoRoot '.dotnet'
if (-not (Test-Path(Join-Path $dotnetRoot "sdk\$dotnetSdkVersion"))) {
if ($install) {
InstallDotNetSdk $dotnetRoot $dotnetSdkVersion
} else {
- Write-PipelineTelemetryError -Category "InitializeToolset" -Message "Unable to find dotnet with SDK version '$dotnetSdkVersion'"
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unable to find dotnet with SDK version '$dotnetSdkVersion'"
ExitWithExitCode 1
}
}
@@ -142,6 +158,24 @@ function InitializeDotNetCli([bool]$install) {
$env:DOTNET_INSTALL_DIR = $dotnetRoot
}
+ # Creates a temporary file under the toolset dir.
+ # The following code block is protecting against concurrent access so that this function can
+ # be called in parallel.
+ if ($createSdkLocationFile) {
+ do {
+ $sdkCacheFileTemp = Join-Path $ToolsetDir $([System.IO.Path]::GetRandomFileName())
+ }
+ until (!(Test-Path $sdkCacheFileTemp))
+ Set-Content -Path $sdkCacheFileTemp -Value $dotnetRoot
+
+ try {
+ Rename-Item -Force -Path $sdkCacheFileTemp 'sdk.txt'
+ } catch {
+ # Somebody beat us
+ Remove-Item -Path $sdkCacheFileTemp
+ }
+ }
+
# Add dotnet to PATH. This prevents any bare invocation of dotnet in custom
# build steps from using anything other than what we've downloaded.
# It also ensures that VS msbuild will use the downloaded sdk targets.
@@ -149,6 +183,7 @@ function InitializeDotNetCli([bool]$install) {
# Make Sure that our bootstrapped dotnet cli is available in future steps of the Azure Pipelines build
Write-PipelinePrependPath -Path $dotnetRoot
+
Write-PipelineSetVariable -Name 'DOTNET_MULTILEVEL_LOOKUP' -Value '0'
Write-PipelineSetVariable -Name 'DOTNET_SKIP_FIRST_TIME_EXPERIENCE' -Value '1'
@@ -156,20 +191,55 @@ function InitializeDotNetCli([bool]$install) {
}
function GetDotNetInstallScript([string] $dotnetRoot) {
- $installScript = Join-Path $dotnetRoot "dotnet-install.ps1"
+ $installScript = Join-Path $dotnetRoot 'dotnet-install.ps1'
if (!(Test-Path $installScript)) {
Create-Directory $dotnetRoot
- Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile $installScript
+ $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit
+
+ $maxRetries = 5
+ $retries = 1
+
+ $uri = "https://dot.net/$dotnetInstallScriptVersion/dotnet-install.ps1"
+
+ while($true) {
+ try {
+ Write-Host "GET $uri"
+ Invoke-WebRequest $uri -OutFile $installScript
+ break
+ }
+ catch {
+ Write-Host "Failed to download '$uri'"
+ Write-Error $_.Exception.Message -ErrorAction Continue
+ }
+
+ if (++$retries -le $maxRetries) {
+ $delayInSeconds = [math]::Pow(2, $retries) - 1 # Exponential backoff
+ Write-Host "Retrying. Waiting for $delayInSeconds seconds before next attempt ($retries of $maxRetries)."
+ Start-Sleep -Seconds $delayInSeconds
+ }
+ else {
+ throw "Unable to download file in $maxRetries attempts."
+ }
+
+ }
}
return $installScript
}
-function InstallDotNetSdk([string] $dotnetRoot, [string] $version, [string] $architecture = "") {
- InstallDotNet $dotnetRoot $version $architecture
+function InstallDotNetSdk([string] $dotnetRoot, [string] $version, [string] $architecture = '', [switch] $noPath) {
+ InstallDotNet $dotnetRoot $version $architecture '' $false $runtimeSourceFeed $runtimeSourceFeedKey -noPath:$noPath
}
-function InstallDotNet([string] $dotnetRoot, [string] $version, [string] $architecture = "", [string] $runtime = "", [bool] $skipNonVersionedFiles = $false) {
+function InstallDotNet([string] $dotnetRoot,
+ [string] $version,
+ [string] $architecture = '',
+ [string] $runtime = '',
+ [bool] $skipNonVersionedFiles = $false,
+ [string] $runtimeSourceFeed = '',
+ [string] $runtimeSourceFeedKey = '',
+ [switch] $noPath) {
+
$installScript = GetDotNetInstallScript $dotnetRoot
$installParameters = @{
Version = $version
@@ -179,11 +249,33 @@ function InstallDotNet([string] $dotnetRoot, [string] $version, [string] $archit
if ($architecture) { $installParameters.Architecture = $architecture }
if ($runtime) { $installParameters.Runtime = $runtime }
if ($skipNonVersionedFiles) { $installParameters.SkipNonVersionedFiles = $skipNonVersionedFiles }
+ if ($noPath) { $installParameters.NoPath = $True }
- & $installScript @installParameters
- if ($lastExitCode -ne 0) {
- Write-PipelineTelemetryError -Category "InitializeToolset" -Message "Failed to install dotnet cli (exit code '$lastExitCode')."
- ExitWithExitCode $lastExitCode
+ try {
+ & $installScript @installParameters
+ }
+ catch {
+ if ($runtimeSourceFeed -or $runtimeSourceFeedKey) {
+ Write-Host "Failed to install dotnet from public location. Trying from '$runtimeSourceFeed'"
+ if ($runtimeSourceFeed) { $installParameters.AzureFeed = $runtimeSourceFeed }
+
+ if ($runtimeSourceFeedKey) {
+ $decodedBytes = [System.Convert]::FromBase64String($runtimeSourceFeedKey)
+ $decodedString = [System.Text.Encoding]::UTF8.GetString($decodedBytes)
+ $installParameters.FeedCredential = $decodedString
+ }
+
+ try {
+ & $installScript @installParameters
+ }
+ catch {
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Failed to install dotnet from custom location '$runtimeSourceFeed'."
+ ExitWithExitCode 1
+ }
+ } else {
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Failed to install dotnet from public location."
+ ExitWithExitCode 1
+ }
}
}
@@ -199,21 +291,34 @@ function InstallDotNet([string] $dotnetRoot, [string] $version, [string] $archit
# Throws on failure.
#
function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = $null) {
+ if (-not (IsWindowsPlatform)) {
+ throw "Cannot initialize Visual Studio on non-Windows"
+ }
+
if (Test-Path variable:global:_MSBuildExe) {
return $global:_MSBuildExe
}
+ # Minimum VS version to require.
+ $vsMinVersionReqdStr = '16.8'
+ $vsMinVersionReqd = [Version]::new($vsMinVersionReqdStr)
+
+ # If the version of msbuild is going to be xcopied,
+ # use this version. Version matches a package here:
+ # https://dev.azure.com/dnceng/public/_packaging?_a=package&feed=dotnet-eng&package=RoslynTools.MSBuild&protocolType=NuGet&version=16.8.0-preview3&view=overview
+ $defaultXCopyMSBuildVersion = '16.8.0-preview3'
+
if (!$vsRequirements) { $vsRequirements = $GlobalJson.tools.vs }
- $vsMinVersionStr = if ($vsRequirements.version) { $vsRequirements.version } else { "15.9" }
+ $vsMinVersionStr = if ($vsRequirements.version) { $vsRequirements.version } else { $vsMinVersionReqdStr }
$vsMinVersion = [Version]::new($vsMinVersionStr)
# Try msbuild command available in the environment.
if ($env:VSINSTALLDIR -ne $null) {
- $msbuildCmd = Get-Command "msbuild.exe" -ErrorAction SilentlyContinue
+ $msbuildCmd = Get-Command 'msbuild.exe' -ErrorAction SilentlyContinue
if ($msbuildCmd -ne $null) {
# Workaround for https://github.com/dotnet/roslyn/issues/35793
# Due to this issue $msbuildCmd.Version returns 0.0.0.0 for msbuild.exe 16.2+
- $msbuildVersion = [Version]::new((Get-Item $msbuildCmd.Path).VersionInfo.ProductVersion.Split(@('-', '+'))[0])
+ $msbuildVersion = [Version]::new((Get-Item $msbuildCmd.Path).VersionInfo.ProductVersion.Split([char[]]@('-', '+'))[0])
if ($msbuildVersion -ge $vsMinVersion) {
return $global:_MSBuildExe = $msbuildCmd.Path
@@ -233,17 +338,35 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements =
InitializeVisualStudioEnvironmentVariables $vsInstallDir $vsMajorVersion
} else {
- if (Get-Member -InputObject $GlobalJson.tools -Name "xcopy-msbuild") {
+ if (Get-Member -InputObject $GlobalJson.tools -Name 'xcopy-msbuild') {
$xcopyMSBuildVersion = $GlobalJson.tools.'xcopy-msbuild'
$vsMajorVersion = $xcopyMSBuildVersion.Split('.')[0]
} else {
- $vsMajorVersion = $vsMinVersion.Major
- $xcopyMSBuildVersion = "$vsMajorVersion.$($vsMinVersion.Minor).0-alpha"
+ #if vs version provided in global.json is incompatible (too low) then use the default version for xcopy msbuild download
+ if($vsMinVersion -lt $vsMinVersionReqd){
+ Write-Host "Using xcopy-msbuild version of $defaultXCopyMSBuildVersion since VS version $vsMinVersionStr provided in global.json is not compatible"
+ $xcopyMSBuildVersion = $defaultXCopyMSBuildVersion
+ }
+ else{
+ # If the VS version IS compatible, look for an xcopy msbuild package
+ # with a version matching VS.
+ # Note: If this version does not exist, then an explicit version of xcopy msbuild
+ # can be specified in global.json. This will be required for pre-release versions of msbuild.
+ $vsMajorVersion = $vsMinVersion.Major
+ $vsMinorVersion = $vsMinVersion.Minor
+ $xcopyMSBuildVersion = "$vsMajorVersion.$vsMinorVersion.0"
+ }
}
- $vsInstallDir = InitializeXCopyMSBuild $xcopyMSBuildVersion $install
+ $vsInstallDir = $null
+ if ($xcopyMSBuildVersion.Trim() -ine "none") {
+ $vsInstallDir = InitializeXCopyMSBuild $xcopyMSBuildVersion $install
+ if ($vsInstallDir -eq $null) {
+ throw "Could not xcopy msbuild. Please check that package 'RoslynTools.MSBuild @ $xcopyMSBuildVersion' exists on feed 'dotnet-eng'."
+ }
+ }
if ($vsInstallDir -eq $null) {
- throw "Unable to find Visual Studio that has required version and components installed"
+ throw 'Unable to find Visual Studio that has required version and components installed'
}
}
@@ -267,7 +390,7 @@ function InstallXCopyMSBuild([string]$packageVersion) {
}
function InitializeXCopyMSBuild([string]$packageVersion, [bool]$install) {
- $packageName = "RoslynTools.MSBuild"
+ $packageName = 'RoslynTools.MSBuild'
$packageDir = Join-Path $ToolsDir "msbuild\$packageVersion"
$packagePath = Join-Path $packageDir "$packageName.$packageVersion.nupkg"
@@ -278,11 +401,12 @@ function InitializeXCopyMSBuild([string]$packageVersion, [bool]$install) {
Create-Directory $packageDir
Write-Host "Downloading $packageName $packageVersion"
- Invoke-WebRequest "https://dotnet.myget.org/F/roslyn-tools/api/v2/package/$packageName/$packageVersion/" -OutFile $packagePath
+ $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit
+ Invoke-WebRequest "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/flat2/$packageName/$packageVersion/$packageName.$packageVersion.nupkg" -OutFile $packagePath
Unzip $packagePath $packageDir
}
- return Join-Path $packageDir "tools"
+ return Join-Path $packageDir 'tools'
}
#
@@ -299,32 +423,56 @@ function InitializeXCopyMSBuild([string]$packageVersion, [bool]$install) {
# or $null if no instance meeting the requirements is found on the machine.
#
function LocateVisualStudio([object]$vsRequirements = $null){
- if (Get-Member -InputObject $GlobalJson.tools -Name "vswhere") {
+ if (-not (IsWindowsPlatform)) {
+ throw "Cannot run vswhere on non-Windows platforms."
+ }
+
+ if (Get-Member -InputObject $GlobalJson.tools -Name 'vswhere') {
$vswhereVersion = $GlobalJson.tools.vswhere
} else {
- $vswhereVersion = "2.5.2"
+ $vswhereVersion = '2.5.2'
}
$vsWhereDir = Join-Path $ToolsDir "vswhere\$vswhereVersion"
- $vsWhereExe = Join-Path $vsWhereDir "vswhere.exe"
+ $vsWhereExe = Join-Path $vsWhereDir 'vswhere.exe'
if (!(Test-Path $vsWhereExe)) {
Create-Directory $vsWhereDir
- Write-Host "Downloading vswhere"
- Invoke-WebRequest "https://github.com/Microsoft/vswhere/releases/download/$vswhereVersion/vswhere.exe" -OutFile $vswhereExe
+ Write-Host 'Downloading vswhere'
+ $maxRetries = 5
+ $retries = 1
+
+ while($true) {
+ try {
+ Invoke-WebRequest "https://netcorenativeassets.blob.core.windows.net/resource-packages/external/windows/vswhere/$vswhereVersion/vswhere.exe" -OutFile $vswhereExe
+ break
+ }
+ catch{
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_
+ }
+
+ if (++$retries -le $maxRetries) {
+ $delayInSeconds = [math]::Pow(2, $retries) - 1 # Exponential backoff
+ Write-Host "Retrying. Waiting for $delayInSeconds seconds before next attempt ($retries of $maxRetries)."
+ Start-Sleep -Seconds $delayInSeconds
+ }
+ else {
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unable to download file in $maxRetries attempts."
+ }
+ }
}
if (!$vsRequirements) { $vsRequirements = $GlobalJson.tools.vs }
- $args = @("-latest", "-prerelease", "-format", "json", "-requires", "Microsoft.Component.MSBuild", "-products", "*")
+ $args = @('-latest', '-prerelease', '-format', 'json', '-requires', 'Microsoft.Component.MSBuild', '-products', '*')
- if (Get-Member -InputObject $vsRequirements -Name "version") {
- $args += "-version"
+ if (Get-Member -InputObject $vsRequirements -Name 'version') {
+ $args += '-version'
$args += $vsRequirements.version
}
- if (Get-Member -InputObject $vsRequirements -Name "components") {
+ if (Get-Member -InputObject $vsRequirements -Name 'components') {
foreach ($component in $vsRequirements.components) {
- $args += "-requires"
+ $args += '-requires'
$args += $component
}
}
@@ -350,28 +498,28 @@ function InitializeBuildTool() {
# Initialize dotnet cli if listed in 'tools'
$dotnetRoot = $null
- if (Get-Member -InputObject $GlobalJson.tools -Name "dotnet") {
+ if (Get-Member -InputObject $GlobalJson.tools -Name 'dotnet') {
$dotnetRoot = InitializeDotNetCli -install:$restore
}
- if ($msbuildEngine -eq "dotnet") {
+ if ($msbuildEngine -eq 'dotnet') {
if (!$dotnetRoot) {
- Write-PipelineTelemetryError -Category "InitializeToolset" -Message "/global.json must specify 'tools.dotnet'."
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "/global.json must specify 'tools.dotnet'."
ExitWithExitCode 1
}
-
- $buildTool = @{ Path = Join-Path $dotnetRoot "dotnet.exe"; Command = "msbuild"; Tool = "dotnet"; Framework = "netcoreapp2.1" }
+ $dotnetPath = Join-Path $dotnetRoot (GetExecutableFileName 'dotnet')
+ $buildTool = @{ Path = $dotnetPath; Command = 'msbuild'; Tool = 'dotnet'; Framework = 'netcoreapp2.1' }
} elseif ($msbuildEngine -eq "vs") {
try {
$msbuildPath = InitializeVisualStudioMSBuild -install:$restore
} catch {
- Write-PipelineTelemetryError -Category "InitializeToolset" -Message $_
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_
ExitWithExitCode 1
}
$buildTool = @{ Path = $msbuildPath; Command = ""; Tool = "vs"; Framework = "net472" }
} else {
- Write-PipelineTelemetryError -Category "InitializeToolset" -Message "Unexpected value of -msbuildEngine: '$msbuildEngine'."
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unexpected value of -msbuildEngine: '$msbuildEngine'."
ExitWithExitCode 1
}
@@ -380,26 +528,29 @@ function InitializeBuildTool() {
function GetDefaultMSBuildEngine() {
# Presence of tools.vs indicates the repo needs to build using VS msbuild on Windows.
- if (Get-Member -InputObject $GlobalJson.tools -Name "vs") {
- return "vs"
+ if (Get-Member -InputObject $GlobalJson.tools -Name 'vs') {
+ return 'vs'
}
- if (Get-Member -InputObject $GlobalJson.tools -Name "dotnet") {
- return "dotnet"
+ if (Get-Member -InputObject $GlobalJson.tools -Name 'dotnet') {
+ return 'dotnet'
}
- Write-PipelineTelemetryError -Category "InitializeToolset" -Message "-msbuildEngine must be specified, or /global.json must specify 'tools.dotnet' or 'tools.vs'."
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "-msbuildEngine must be specified, or /global.json must specify 'tools.dotnet' or 'tools.vs'."
ExitWithExitCode 1
}
function GetNuGetPackageCachePath() {
if ($env:NUGET_PACKAGES -eq $null) {
- # Use local cache on CI to ensure deterministic build,
+ # Use local cache on CI to ensure deterministic build.
+ # Avoid using the http cache as workaround for https://github.com/NuGet/Home/issues/3116
# use global cache in dev builds to avoid cost of downloading packages.
+ # For directory normalization, see also: https://github.com/NuGet/Home/issues/7968
if ($useGlobalNuGetCache) {
- $env:NUGET_PACKAGES = Join-Path $env:UserProfile ".nuget\packages"
+ $env:NUGET_PACKAGES = Join-Path $env:UserProfile '.nuget\packages\'
} else {
- $env:NUGET_PACKAGES = Join-Path $RepoRoot ".packages"
+ $env:NUGET_PACKAGES = Join-Path $RepoRoot '.packages\'
+ $env:RESTORENOCACHE = $true
}
}
@@ -412,7 +563,7 @@ function GetSdkTaskProject([string]$taskName) {
}
function InitializeNativeTools() {
- if (Get-Member -InputObject $GlobalJson -Name "native-tools") {
+ if (-Not (Test-Path variable:DisableNativeToolsetInstalls) -And (Get-Member -InputObject $GlobalJson -Name "native-tools")) {
$nativeArgs= @{}
if ($ci) {
$nativeArgs = @{
@@ -441,20 +592,20 @@ function InitializeToolset() {
}
if (-not $restore) {
- Write-PipelineTelemetryError -Category "InitializeToolset" -Message "Toolset version $toolsetVersion has not been restored."
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Toolset version $toolsetVersion has not been restored."
ExitWithExitCode 1
}
$buildTool = InitializeBuildTool
- $proj = Join-Path $ToolsetDir "restore.proj"
- $bl = if ($binaryLog) { "/bl:" + (Join-Path $LogDir "ToolsetRestore.binlog") } else { "" }
+ $proj = Join-Path $ToolsetDir 'restore.proj'
+ $bl = if ($binaryLog) { '/bl:' + (Join-Path $LogDir 'ToolsetRestore.binlog') } else { '' }
'' | Set-Content $proj
MSBuild-Core $proj $bl /t:__WriteToolsetLocation /clp:ErrorsOnly`;NoSummary /p:__ToolsetLocationOutputFile=$toolsetLocationFile
- $path = Get-Content $toolsetLocationFile -TotalCount 1
+ $path = Get-Content $toolsetLocationFile -Encoding UTF8 -TotalCount 1
if (!(Test-Path $path)) {
throw "Invalid toolset path: $path"
}
@@ -470,7 +621,7 @@ function ExitWithExitCode([int] $exitCode) {
}
function Stop-Processes() {
- Write-Host "Killing running build processes..."
+ Write-Host 'Killing running build processes...'
foreach ($processName in $processesToStopOnExit) {
Get-Process -Name $processName -ErrorAction SilentlyContinue | Stop-Process
}
@@ -484,9 +635,17 @@ function Stop-Processes() {
function MSBuild() {
if ($pipelinesLog) {
$buildTool = InitializeBuildTool
+
+ if ($ci -and $buildTool.Tool -eq 'dotnet') {
+ $env:NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS = 20
+ $env:NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS = 20
+ Write-PipelineSetVariable -Name 'NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS' -Value '20'
+ Write-PipelineSetVariable -Name 'NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS' -Value '20'
+ }
+
$toolsetBuildProject = InitializeToolset
$path = Split-Path -parent $toolsetBuildProject
- $path = Join-Path $path (Join-Path $buildTool.Framework "Microsoft.DotNet.Arcade.Sdk.dll")
+ $path = Join-Path $path (Join-Path $buildTool.Framework 'Microsoft.DotNet.Arcade.Sdk.dll')
$args += "/logger:$path"
}
@@ -500,13 +659,13 @@ function MSBuild() {
#
function MSBuild-Core() {
if ($ci) {
- if (!$binaryLog) {
- Write-PipelineTaskError -Message "Binary log must be enabled in CI build."
+ if (!$binaryLog -and !$excludeCIBinarylog) {
+ Write-PipelineTelemetryError -Category 'Build' -Message 'Binary log must be enabled in CI build, or explicitly opted-out from with the -excludeCIBinarylog switch.'
ExitWithExitCode 1
}
if ($nodeReuse) {
- Write-PipelineTaskError -Message "Node reuse must be disabled in CI build."
+ Write-PipelineTelemetryError -Category 'Build' -Message 'Node reuse must be disabled in CI build.'
ExitWithExitCode 1
}
}
@@ -516,7 +675,10 @@ function MSBuild-Core() {
$cmdArgs = "$($buildTool.Command) /m /nologo /clp:Summary /v:$verbosity /nr:$nodeReuse /p:ContinuousIntegrationBuild=$ci"
if ($warnAsError) {
- $cmdArgs += " /warnaserror /p:TreatWarningsAsErrors=true"
+ $cmdArgs += ' /warnaserror /p:TreatWarningsAsErrors=true'
+ }
+ else {
+ $cmdArgs += ' /p:TreatWarningsAsErrors=false'
}
foreach ($arg in $args) {
@@ -525,17 +687,28 @@ function MSBuild-Core() {
}
}
+ $env:ARCADE_BUILD_TOOL_COMMAND = "$($buildTool.Path) $cmdArgs"
+
$exitCode = Exec-Process $buildTool.Path $cmdArgs
if ($exitCode -ne 0) {
- Write-PipelineTaskError -Message "Build failed."
+ # We should not Write-PipelineTaskError here because that message shows up in the build summary
+ # The build already logged an error, that's the reason it failed. Producing an error here only adds noise.
+ Write-Host "Build failed with exit code $exitCode. Check errors above." -ForegroundColor Red
$buildLog = GetMSBuildBinaryLogCommandLineArgument $args
- if ($buildLog -ne $null) {
+ if ($null -ne $buildLog) {
Write-Host "See log: $buildLog" -ForegroundColor DarkGray
}
- ExitWithExitCode $exitCode
+ if ($ci) {
+ Write-PipelineSetResult -Result "Failed" -Message "msbuild execution failed."
+ # Exiting with an exit code causes the azure pipelines task to log yet another "noise" error
+ # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error
+ ExitWithExitCode 0
+ } else {
+ ExitWithExitCode $exitCode
+ }
}
}
@@ -543,12 +716,12 @@ function GetMSBuildBinaryLogCommandLineArgument($arguments) {
foreach ($argument in $arguments) {
if ($argument -ne $null) {
$arg = $argument.Trim()
- if ($arg.StartsWith("/bl:", "OrdinalIgnoreCase")) {
- return $arg.Substring("/bl:".Length)
+ if ($arg.StartsWith('/bl:', "OrdinalIgnoreCase")) {
+ return $arg.Substring('/bl:'.Length)
}
- if ($arg.StartsWith("/binaryLogger:", "OrdinalIgnoreCase")) {
- return $arg.Substring("/binaryLogger:".Length)
+ if ($arg.StartsWith('/binaryLogger:', 'OrdinalIgnoreCase')) {
+ return $arg.Substring('/binaryLogger:'.Length)
}
}
}
@@ -556,16 +729,39 @@ function GetMSBuildBinaryLogCommandLineArgument($arguments) {
return $null
}
+function GetExecutableFileName($baseName) {
+ if (IsWindowsPlatform) {
+ return "$baseName.exe"
+ }
+ else {
+ return $baseName
+ }
+}
+
+function IsWindowsPlatform() {
+ return [environment]::OSVersion.Platform -eq [PlatformID]::Win32NT
+}
+
+function Get-Darc($version) {
+ $darcPath = "$TempDir\darc\$(New-Guid)"
+ if ($version -ne $null) {
+ & $PSScriptRoot\darc-init.ps1 -toolpath $darcPath -darcVersion $version | Out-Host
+ } else {
+ & $PSScriptRoot\darc-init.ps1 -toolpath $darcPath | Out-Host
+ }
+ return "$darcPath\darc.exe"
+}
+
. $PSScriptRoot\pipeline-logging-functions.ps1
-$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot "..\..")
-$EngRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
-$ArtifactsDir = Join-Path $RepoRoot "artifacts"
-$ToolsetDir = Join-Path $ArtifactsDir "toolset"
-$ToolsDir = Join-Path $RepoRoot ".tools"
-$LogDir = Join-Path (Join-Path $ArtifactsDir "log") $configuration
-$TempDir = Join-Path (Join-Path $ArtifactsDir "tmp") $configuration
-$GlobalJson = Get-Content -Raw -Path (Join-Path $RepoRoot "global.json") | ConvertFrom-Json
+$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\..')
+$EngRoot = Resolve-Path (Join-Path $PSScriptRoot '..')
+$ArtifactsDir = Join-Path $RepoRoot 'artifacts'
+$ToolsetDir = Join-Path $ArtifactsDir 'toolset'
+$ToolsDir = Join-Path $RepoRoot '.tools'
+$LogDir = Join-Path (Join-Path $ArtifactsDir 'log') $configuration
+$TempDir = Join-Path (Join-Path $ArtifactsDir 'tmp') $configuration
+$GlobalJson = Get-Content -Raw -Path (Join-Path $RepoRoot 'global.json') | ConvertFrom-Json
# true if global.json contains a "runtimes" section
$globalJsonHasRuntimes = if ($GlobalJson.tools.PSObject.Properties.Name -Match 'runtimes') { $true } else { $false }
@@ -578,3 +774,18 @@ Write-PipelineSetVariable -Name 'Artifacts.Toolset' -Value $ToolsetDir
Write-PipelineSetVariable -Name 'Artifacts.Log' -Value $LogDir
Write-PipelineSetVariable -Name 'TEMP' -Value $TempDir
Write-PipelineSetVariable -Name 'TMP' -Value $TempDir
+
+# Import custom tools configuration, if present in the repo.
+# Note: Import in global scope so that the script set top-level variables without qualification.
+if (!$disableConfigureToolsetImport) {
+ $configureToolsetScript = Join-Path $EngRoot 'configure-toolset.ps1'
+ if (Test-Path $configureToolsetScript) {
+ . $configureToolsetScript
+ if ((Test-Path variable:failOnConfigureToolsetError) -And $failOnConfigureToolsetError) {
+ if ((Test-Path variable:LastExitCode) -And ($LastExitCode -ne 0)) {
+ Write-PipelineTelemetryError -Category 'Build' -Message 'configure-toolset.ps1 returned a non-zero exit code'
+ ExitWithExitCode $LastExitCode
+ }
+ }
+ }
+}
diff --git a/eng/common/tools.sh b/eng/common/tools.sh
index 913b048420d..b160c370f84 100755
--- a/eng/common/tools.sh
+++ b/eng/common/tools.sh
@@ -18,9 +18,17 @@ fi
# Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names.
configuration=${configuration:-'Debug'}
+# Set to true to opt out of outputting binary log while running in CI
+exclude_ci_binary_log=${exclude_ci_binary_log:-false}
+
+if [[ "$ci" == true && "$exclude_ci_binary_log" == false ]]; then
+ binary_log_default=true
+else
+ binary_log_default=false
+fi
+
# Set to true to output binary log from msbuild. Note that emitting binary log slows down the build.
-# Binary log must be enabled on CI.
-binary_log=${binary_log:-$ci}
+binary_log=${binary_log:-$binary_log_default}
# Turns on machine preparation/clean up code that changes the machine state (e.g. kills build processes).
prepare_machine=${prepare_machine:-false}
@@ -41,10 +49,14 @@ fi
# Configures warning treatment in msbuild.
warn_as_error=${warn_as_error:-true}
-# True to attempt using .NET Core already that meets requirements specified in global.json
+# True to attempt using .NET Core already that meets requirements specified in global.json
# installed on the machine instead of downloading one.
use_installed_dotnet_cli=${use_installed_dotnet_cli:-true}
+# Enable repos to use a particular version of the on-line dotnet-install scripts.
+# default URL: https://dot.net/v1/dotnet-install.sh
+dotnetInstallScriptVersion=${dotnetInstallScriptVersion:-'v1'}
+
# True to use global NuGet cache instead of restoring packages to repository-local directory.
if [[ "$ci" == true ]]; then
use_global_nuget_cache=${use_global_nuget_cache:-false}
@@ -52,6 +64,10 @@ else
use_global_nuget_cache=${use_global_nuget_cache:-true}
fi
+# Used when restoring .NET SDK from alternative feeds
+runtime_source_feed=${runtime_source_feed:-''}
+runtime_source_feed_key=${runtime_source_feed_key:-''}
+
# Resolve any symlinks in the given path.
function ResolvePath {
local path=$1
@@ -73,11 +89,11 @@ function ResolvePath {
function ReadGlobalVersion {
local key=$1
- local line=`grep -m 1 "$key" "$global_json_file"`
+ local line=$(awk "/$key/ {print; exit}" "$global_json_file")
local pattern="\"$key\" *: *\"(.*)\""
if [[ ! $line =~ $pattern ]]; then
- Write-PipelineTelemetryError -category 'InitializeToolset' "Error: Cannot find \"$key\" in $global_json_file"
+ Write-PipelineTelemetryError -category 'Build' "Error: Cannot find \"$key\" in $global_json_file"
ExitWithExitCode 1
fi
@@ -158,44 +174,95 @@ function InitializeDotNetCli {
function InstallDotNetSdk {
local root=$1
local version=$2
- local architecture=""
- if [[ $# == 3 ]]; then
+ local architecture="unset"
+ if [[ $# -ge 3 ]]; then
architecture=$3
fi
- InstallDotNet "$root" "$version" $architecture
+ InstallDotNet "$root" "$version" $architecture 'sdk' 'false' $runtime_source_feed $runtime_source_feed_key
}
function InstallDotNet {
local root=$1
local version=$2
-
+
GetDotNetInstallScript "$root"
local install_script=$_GetDotNetInstallScript
local archArg=''
- if [[ -n "${3:-}" ]]; then
+ if [[ -n "${3:-}" ]] && [ "$3" != 'unset' ]; then
archArg="--architecture $3"
fi
local runtimeArg=''
- if [[ -n "${4:-}" ]]; then
+ if [[ -n "${4:-}" ]] && [ "$4" != 'sdk' ]; then
runtimeArg="--runtime $4"
fi
-
local skipNonVersionedFilesArg=""
- if [[ "$#" -ge "5" ]]; then
+ if [[ "$#" -ge "5" ]] && [[ "$5" != 'false' ]]; then
skipNonVersionedFilesArg="--skip-non-versioned-files"
fi
bash "$install_script" --version $version --install-dir "$root" $archArg $runtimeArg $skipNonVersionedFilesArg || {
local exit_code=$?
- Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to install dotnet SDK (exit code '$exit_code')."
- ExitWithExitCode $exit_code
+ echo "Failed to install dotnet SDK from public location (exit code '$exit_code')."
+
+ local runtimeSourceFeed=''
+ if [[ -n "${6:-}" ]]; then
+ runtimeSourceFeed="--azure-feed $6"
+ fi
+
+ local runtimeSourceFeedKey=''
+ if [[ -n "${7:-}" ]]; then
+ # The 'base64' binary on alpine uses '-d' and doesn't support '--decode'
+ # '-d'. To work around this, do a simple detection and switch the parameter
+ # accordingly.
+ decodeArg="--decode"
+ if base64 --help 2>&1 | grep -q "BusyBox"; then
+ decodeArg="-d"
+ fi
+ decodedFeedKey=`echo $7 | base64 $decodeArg`
+ runtimeSourceFeedKey="--feed-credential $decodedFeedKey"
+ fi
+
+ if [[ -n "$runtimeSourceFeed" || -n "$runtimeSourceFeedKey" ]]; then
+ bash "$install_script" --version $version --install-dir "$root" $archArg $runtimeArg $skipNonVersionedFilesArg $runtimeSourceFeed $runtimeSourceFeedKey || {
+ local exit_code=$?
+ Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to install dotnet SDK from custom location '$runtimeSourceFeed' (exit code '$exit_code')."
+ ExitWithExitCode $exit_code
+ }
+ else
+ if [[ $exit_code != 0 ]]; then
+ Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to install dotnet SDK from public location (exit code '$exit_code')."
+ fi
+ ExitWithExitCode $exit_code
+ fi
}
}
+function with_retries {
+ local maxRetries=5
+ local retries=1
+ echo "Trying to run '$@' for maximum of $maxRetries attempts."
+ while [[ $((retries++)) -le $maxRetries ]]; do
+ "$@"
+
+ if [[ $? == 0 ]]; then
+ echo "Ran '$@' successfully."
+ return 0
+ fi
+
+ timeout=$((3**$retries-1))
+ echo "Failed to execute '$@'. Waiting $timeout seconds before next attempt ($retries out of $maxRetries)." 1>&2
+ sleep $timeout
+ done
+
+ echo "Failed to execute '$@' for $maxRetries times." 1>&2
+
+ return 1
+}
+
function GetDotNetInstallScript {
local root=$1
local install_script="$root/dotnet-install.sh"
- local install_script_url="https://dot.net/v1/dotnet-install.sh"
+ local install_script_url="https://dot.net/$dotnetInstallScriptVersion/dotnet-install.sh"
if [[ ! -a "$install_script" ]]; then
mkdir -p "$root"
@@ -204,12 +271,25 @@ function GetDotNetInstallScript {
# Use curl if available, otherwise use wget
if command -v curl > /dev/null; then
- curl "$install_script_url" -sSL --retry 10 --create-dirs -o "$install_script"
+ # first, try directly, if this fails we will retry with verbose logging
+ curl "$install_script_url" -sSL --retry 10 --create-dirs -o "$install_script" || {
+ echo "Curl failed; dumping some information about dotnet.microsoft.com for later investigation"
+ echo | openssl s_client -showcerts -servername dotnet.microsoft.com -connect dotnet.microsoft.com:443
+ echo "Will now retry the same URL with verbose logging."
+ with_retries curl "$install_script_url" -sSL --verbose --retry 10 --create-dirs -o "$install_script" || {
+ local exit_code=$?
+ Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to acquire dotnet install script (exit code '$exit_code')."
+ ExitWithExitCode $exit_code
+ }
+ }
else
- wget -q -O "$install_script" "$install_script_url"
+ with_retries wget -v -O "$install_script" "$install_script_url" || {
+ local exit_code=$?
+ Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to acquire dotnet install script (exit code '$exit_code')."
+ ExitWithExitCode $exit_code
+ }
fi
fi
-
# return value
_GetDotNetInstallScript="$install_script"
}
@@ -218,21 +298,23 @@ function InitializeBuildTool {
if [[ -n "${_InitializeBuildTool:-}" ]]; then
return
fi
-
+
InitializeDotNetCli $restore
# return values
- _InitializeBuildTool="$_InitializeDotNetCli/dotnet"
+ _InitializeBuildTool="$_InitializeDotNetCli/dotnet"
_InitializeBuildToolCommand="msbuild"
_InitializeBuildToolFramework="netcoreapp2.1"
}
+# Set RestoreNoCache as a workaround for https://github.com/NuGet/Home/issues/3116
function GetNuGetPackageCachePath {
if [[ -z ${NUGET_PACKAGES:-} ]]; then
if [[ "$use_global_nuget_cache" == true ]]; then
export NUGET_PACKAGES="$HOME/.nuget/packages"
else
export NUGET_PACKAGES="$repo_root/.packages"
+ export RESTORENOCACHE=true
fi
fi
@@ -241,6 +323,9 @@ function GetNuGetPackageCachePath {
}
function InitializeNativeTools() {
+ if [[ -n "${DisableNativeToolsetInstalls:-}" ]]; then
+ return
+ fi
if grep -Fq "native-tools" $global_json_file
then
local nativeArgs=""
@@ -283,14 +368,14 @@ function InitializeToolset {
if [[ "$binary_log" == true ]]; then
bl="/bl:$log_dir/ToolsetRestore.binlog"
fi
-
+
echo '' > "$proj"
MSBuild-Core "$proj" $bl /t:__WriteToolsetLocation /clp:ErrorsOnly\;NoSummary /p:__ToolsetLocationOutputFile="$toolset_location_file"
local toolset_build_proj=`cat "$toolset_location_file"`
if [[ ! -a "$toolset_build_proj" ]]; then
- Write-PipelineTelemetryError -category 'InitializeToolset' "Invalid toolset path: $toolset_build_proj"
+ Write-PipelineTelemetryError -category 'Build' "Invalid toolset path: $toolset_build_proj"
ExitWithExitCode 3
fi
@@ -317,6 +402,14 @@ function MSBuild {
if [[ "$pipelines_log" == true ]]; then
InitializeBuildTool
InitializeToolset
+
+ if [[ "$ci" == true ]]; then
+ export NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS=20
+ export NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS=20
+ Write-PipelineSetVariable -name "NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS" -value "20"
+ Write-PipelineSetVariable -name "NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS" -value "20"
+ fi
+
local toolset_dir="${_InitializeToolset%/*}"
local logger_path="$toolset_dir/$_InitializeBuildToolFramework/Microsoft.DotNet.Arcade.Sdk.dll"
args=( "${args[@]}" "-logger:$logger_path" )
@@ -327,13 +420,13 @@ function MSBuild {
function MSBuild-Core {
if [[ "$ci" == true ]]; then
- if [[ "$binary_log" != true ]]; then
- Write-PipelineTaskError "Binary log must be enabled in CI build."
+ if [[ "$binary_log" != true && "$exclude_ci_binary_log" != true ]]; then
+ Write-PipelineTelemetryError -category 'Build' "Binary log must be enabled in CI build, or explicitly opted-out from with the -noBinaryLog switch."
ExitWithExitCode 1
fi
if [[ "$node_reuse" == true ]]; then
- Write-PipelineTaskError "Node reuse must be disabled in CI build."
+ Write-PipelineTelemetryError -category 'Build' "Node reuse must be disabled in CI build."
ExitWithExitCode 1
fi
fi
@@ -345,14 +438,27 @@ function MSBuild-Core {
warnaserror_switch="/warnaserror"
fi
- "$_InitializeBuildTool" "$_InitializeBuildToolCommand" /m /nologo /clp:Summary /v:$verbosity /nr:$node_reuse $warnaserror_switch /p:TreatWarningsAsErrors=$warn_as_error /p:ContinuousIntegrationBuild=$ci "$@" || {
- local exit_code=$?
- Write-PipelineTaskError "Build failed (exit code '$exit_code')."
- ExitWithExitCode $exit_code
+ function RunBuildTool {
+ export ARCADE_BUILD_TOOL_COMMAND="$_InitializeBuildTool $@"
+
+ "$_InitializeBuildTool" "$@" || {
+ local exit_code=$?
+ # We should not Write-PipelineTaskError here because that message shows up in the build summary
+ # The build already logged an error, that's the reason it failed. Producing an error here only adds noise.
+ echo "Build failed with exit code $exit_code. Check errors above."
+ if [[ "$ci" == "true" ]]; then
+ Write-PipelineSetResult -result "Failed" -message "msbuild execution failed."
+ # Exiting with an exit code causes the azure pipelines task to log yet another "noise" error
+ # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error
+ ExitWithExitCode 0
+ else
+ ExitWithExitCode $exit_code
+ fi
+ }
}
-}
-. "$scriptroot/pipeline-logging-functions.sh"
+ RunBuildTool "$_InitializeBuildToolCommand" /m /nologo /clp:Summary /v:$verbosity /nr:$node_reuse $warnaserror_switch /p:TreatWarningsAsErrors=$warn_as_error /p:ContinuousIntegrationBuild=$ci "$@"
+}
ResolvePath "${BASH_SOURCE[0]}"
_script_dir=`dirname "$_ResolvePath"`
@@ -370,7 +476,7 @@ temp_dir="$artifacts_dir/tmp/$configuration"
global_json_file="$repo_root/global.json"
# determine if global.json contains a "runtimes" entry
global_json_has_runtimes=false
-dotnetlocal_key=`grep -m 1 "runtimes" "$global_json_file"` || true
+dotnetlocal_key=$(awk "/runtimes/ {print; exit}" "$global_json_file") || true
if [[ -n "$dotnetlocal_key" ]]; then
global_json_has_runtimes=true
fi
@@ -390,3 +496,18 @@ Write-PipelineSetVariable -name "Artifacts.Toolset" -value "$toolset_dir"
Write-PipelineSetVariable -name "Artifacts.Log" -value "$log_dir"
Write-PipelineSetVariable -name "Temp" -value "$temp_dir"
Write-PipelineSetVariable -name "TMP" -value "$temp_dir"
+
+# Import custom tools configuration, if present in the repo.
+if [ -z "${disable_configure_toolset_import:-}" ]; then
+ configure_toolset_script="$eng_root/configure-toolset.sh"
+ if [[ -a "$configure_toolset_script" ]]; then
+ . "$configure_toolset_script"
+ fi
+fi
+
+# TODO: https://github.com/dotnet/arcade/issues/1468
+# Temporary workaround to avoid breaking change.
+# Remove once repos are updated.
+if [[ -n "${useInstalledDotNetCli:-}" ]]; then
+ use_installed_dotnet_cli="$useInstalledDotNetCli"
+fi
diff --git a/eng/release/insert-into-vs.yml b/eng/release/insert-into-vs.yml
new file mode 100644
index 00000000000..e61143ca239
--- /dev/null
+++ b/eng/release/insert-into-vs.yml
@@ -0,0 +1,58 @@
+parameters:
+ componentBranchName: ''
+ insertBuildPolicy: 'Request Perf DDRITs'
+ insertTargetBranch: ''
+ insertTeamEmail: ''
+ insertTeamName: ''
+ dependsOn: [build]
+
+stages:
+- stage: insert
+ dependsOn: build
+ displayName: Insert into VS
+ jobs:
+ - job: Insert_VS
+ pool:
+ vmImage: vs2017-win2016
+ variables:
+ - group: DotNet-VSTS-Infra-Access
+ - name: InsertAccessToken
+ value: $(dn-bot-devdiv-build-rw-code-rw-release-rw)
+ - name: InsertBuildPolicy
+ value: ${{ parameters.insertBuildPolicy }}
+ - name: InsertTargetBranch
+ value: ${{ parameters.insertTargetBranch }}
+ - name: InsertTeamEmail
+ value: ${{ parameters.insertTeamEmail }}
+ - name: InsertTeamName
+ value: ${{ parameters.insertTeamName }}
+ - name: InsertPayloadName
+ value: '${{ parameters.insertTeamName }} $(Build.SourceBranchName) $(Build.BuildNumber)'
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Insertion Artifacts
+ inputs:
+ buildType: current
+ artifactName: VSSetup
+ - task: PowerShell@2
+ displayName: Get Publish URLs
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/release/scripts/GetPublishUrls.ps1
+ arguments: -accessToken $(System.AccessToken) -buildId $(Build.BuildId) -insertionDir $(Build.ArtifactStagingDirectory)\VSSetup
+ - task: PowerShell@2
+ displayName: Get versions for default.config
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/release/scripts/GetDefaultConfigVersions.ps1
+ arguments: -packagesDir $(Build.ArtifactStagingDirectory)\VSSetup\DevDivPackages
+ - task: PowerShell@2
+ displayName: Get versions for AssemblyVersions.tt
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/release/scripts/GetAssemblyVersions.ps1
+ arguments: -assemblyVersionsPath $(Build.ArtifactStagingDirectory)\VSSetup\DevDivPackages\DependentAssemblyVersions.csv
+ - task: ms-vseng.MicroBuildShipTasks.55100717-a81d-45ea-a363-b8fe3ec375ad.MicroBuildInsertVsPayload@3
+ displayName: 'Insert VS Payload'
+ inputs:
+ # only auto-complete if the target branch is not `rel/*`
+ AutoCompletePR: ${{ not(contains(parameters.insertTargetBranch, 'rel/')) }}
+ LinkWorkItemsToPR: false
+ condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], '${{ parameters.componentBranchName }}'), eq(variables['Build.SourceBranch'], 'refs/heads/${{ parameters.componentBranchName }}')))
diff --git a/eng/release/scripts/GetAssemblyVersions.ps1 b/eng/release/scripts/GetAssemblyVersions.ps1
new file mode 100644
index 00000000000..2b75ac1dd51
--- /dev/null
+++ b/eng/release/scripts/GetAssemblyVersions.ps1
@@ -0,0 +1,28 @@
+[CmdletBinding(PositionalBinding=$false)]
+param (
+ [string]$assemblyVersionsPath
+)
+
+Set-StrictMode -version 2.0
+$ErrorActionPreference = "Stop"
+
+try {
+ [string[]]$lines = Get-Content -Path $assemblyVersionsPath | ForEach-Object {
+ $parts = $_ -Split ",",2
+ $asm = $parts[0]
+ $ver = $parts[1]
+ $asmConst = ($asm -Replace "\.","") + "Version"
+ $output = "$asmConst=$ver"
+ $output
+ }
+
+ $final = $lines -Join ","
+ Write-Host "Setting InsertVersionsValues to $final"
+ Write-Host "##vso[task.setvariable variable=InsertVersionsValues]$final"
+}
+catch {
+ Write-Host $_
+ Write-Host $_.Exception
+ Write-Host $_.ScriptStackTrace
+ exit 1
+}
diff --git a/eng/release/scripts/GetDefaultConfigVersions.ps1 b/eng/release/scripts/GetDefaultConfigVersions.ps1
new file mode 100644
index 00000000000..d0f1f67fc5d
--- /dev/null
+++ b/eng/release/scripts/GetDefaultConfigVersions.ps1
@@ -0,0 +1,29 @@
+[CmdletBinding(PositionalBinding=$false)]
+param (
+ [string]$packagesDir
+)
+
+Set-StrictMode -version 2.0
+$ErrorActionPreference = "Stop"
+
+try {
+ $packages = @()
+ $regex = "^(.*?)\.((?:\.?[0-9]+){3,}(?:[-a-z0-9]+)?)\.nupkg$"
+ Get-Item -Path "$packagesDir\*" -Filter "*.nupkg" | ForEach-Object {
+ $fileName = Split-Path $_ -Leaf
+ If ($fileName -Match $regex) {
+ $entry = $Matches[1] + "=" + $Matches[2]
+ $packages += $entry
+ }
+ }
+
+ $final = $packages -Join ","
+ Write-Host "Setting InsertConfigValues to $final"
+ Write-Host "##vso[task.setvariable variable=InsertConfigValues]$final"
+}
+catch {
+ Write-Host $_
+ Write-Host $_.Exception
+ Write-Host $_.ScriptStackTrace
+ exit 1
+}
diff --git a/eng/release/scripts/GetPublishUrls.ps1 b/eng/release/scripts/GetPublishUrls.ps1
new file mode 100644
index 00000000000..897ef398f52
--- /dev/null
+++ b/eng/release/scripts/GetPublishUrls.ps1
@@ -0,0 +1,123 @@
+[CmdletBinding(PositionalBinding=$false)]
+param (
+ [string]$accessToken,
+ [string]$buildId,
+ [string]$insertionDir
+)
+
+Set-StrictMode -version 2.0
+$ErrorActionPreference = "Stop"
+
+$dropUrlRegex = "(https://vsdrop\.corp\.microsoft\.com/[^\r\n;]+);([^\r\n]+)\r?\n"
+
+function Invoke-WebRequestWithAccessToken([string] $uri, [string] $accessToken, [int] $retryCount = 5) {
+ Write-Host "Fetching content from $uri"
+ $base64 = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$accessToken"))
+ $headers = @{
+ Authorization = "Basic $base64"
+ }
+
+ for ($i = 0; $i -lt $retryCount; $i++) {
+ try {
+ return Invoke-WebRequest -Method Get -Uri $uri -Headers $headers -UseBasicParsing
+ }
+ catch {
+ Write-Host "Invoke-WebRequest failed: $_"
+ Start-Sleep -Seconds 1
+ }
+ }
+
+ throw "Unable to fetch $uri after $retryCount tries."
+}
+
+# this function has to download ~500 individual logs and check each one; prone to timeouts
+function Get-ManifestsViaIndividualLogs([PSObject] $manifestVersionMap, [string] $buildId, [string] $accessToken) {
+ $manifests = @()
+ $seenManifests = @{}
+ $json = Invoke-WebRequestWithAccessToken -uri "https://dev.azure.com/dnceng/internal/_apis/build/builds/$buildId/logs?api-version=5.1" -accessToken $accessToken | ConvertFrom-Json
+ foreach ($l in $json.value) {
+ $logUrl = $l.url
+ $log = (Invoke-WebRequestWithAccessToken -uri $logUrl -accessToken $accessToken).Content
+ If ($log -Match $dropUrlRegex) {
+ $manifestShortUrl = $Matches[1]
+ $manifestName = $Matches[2]
+ $manifestUrl = "$manifestShortUrl;$manifestName"
+ If (-Not $seenManifests.Contains($manifestUrl)) {
+ $seenManifests.Add($manifestUrl, $true)
+ $buildVersion = $manifestVersionMap[$manifestName]
+ $manifestEntry = "$manifestName{$buildVersion}=$manifestUrl"
+ $manifests += $manifestEntry
+ }
+ }
+ }
+
+ return $manifests
+}
+
+# this function only has to download 1 file and look at a very specific file
+function Get-ManifestsViaZipLog([PSObject] $manifestVersionMap, [string] $buildId, [string] $accessToken) {
+ # create temporary location
+ $guid = [System.Guid]::NewGuid().ToString()
+ $tempDir = Join-Path ([System.IO.Path]::GetTempPath()) $guid
+ New-Item -ItemType Directory -Path $tempDir | Out-Null
+
+ # download the logs
+ $base64 = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$accessToken"))
+ $headers = @{
+ Authorization = "Basic $base64"
+ }
+ $uri = "https://dev.azure.com/dnceng/internal/_apis/build/builds/$buildId/logs?`$format=zip"
+ Invoke-WebRequest -Uri $uri -Method Get -Headers $headers -UseBasicParsing -OutFile "$tempDir/logs.zip"
+
+ # expand the logs
+ New-Item -ItemType Directory -Path "$tempDir/logs" | Out-Null
+ Expand-Archive -Path "$tempDir/logs.zip" -DestinationPath "$tempDir/logs"
+
+ # parse specific logs
+ $logDir = "$tempDir/logs"
+ $manifests = @()
+ $seenManifests = @{}
+ Get-ChildItem $logDir -r -inc "*Upload VSTS Drop*" | ForEach-Object {
+ $result = Select-String -Path $_ -Pattern "(https://vsdrop\.corp\.microsoft\.com[^;]+);(.*)" -AllMatches
+ $result.Matches | ForEach-Object {
+ $manifestShortUrl = $_.Groups[1].Value
+ $manifestName = $_.Groups[2].Value
+ $manifestUrl = "$manifestShortUrl;$manifestName"
+ If (-Not $seenManifests.Contains($manifestUrl)) {
+ $seenManifests.Add($manifestUrl, $true)
+ $buildVersion = $manifestVersionMap[$manifestName]
+ $manifestEntry = "$manifestName{$buildVersion}=$manifestUrl"
+ $manifests += $manifestEntry
+ }
+ }
+ }
+
+ Remove-Item -Path $tempDir -Recurse
+
+ return $manifests
+}
+
+try {
+ # build map of all *.vsman files to their `info.buildVersion` values
+ $manifestVersionMap = @{}
+ Get-ChildItem -Path "$insertionDir\*" -Filter "*.vsman" | ForEach-Object {
+ $manifestName = Split-Path $_ -Leaf
+ $vsmanContents = Get-Content $_ | ConvertFrom-Json
+ $buildVersion = $vsmanContents.info.buildVersion
+ $manifestVersionMap.Add($manifestName, $buildVersion)
+ }
+
+ # find all publish URLs
+ #$manifests = Get-ManifestsViaIndividualLogs -manifestVersionMap $manifestVersionMap -buildId $buildId -accessToken $accessToken
+ $manifests = Get-ManifestsViaZipLog -manifestVersionMap $manifestVersionMap -buildId $buildId -accessToken $accessToken
+
+ $final = $manifests -Join ","
+ Write-Host "Setting InsertJsonValues to $final"
+ Write-Host "##vso[task.setvariable variable=InsertJsonValues]$final"
+}
+catch {
+ Write-Host $_
+ Write-Host $_.Exception
+ Write-Host $_.ScriptStackTrace
+ exit 1
+}
diff --git a/eng/targets/NGenBinaries.targets b/eng/targets/NGenBinaries.targets
index 6e4ad9799f6..c084206d0a6 100644
--- a/eng/targets/NGenBinaries.targets
+++ b/eng/targets/NGenBinaries.targets
@@ -1,33 +1,70 @@
-
-
- true
- true
- false
-
+
+
+
+
+
+ false
+ true
+
+
+
+
+
+
+ true
+ false
+
+
+ AfterTargets="Build"
+ Condition="'$(OS)' != 'Unix' AND $(TargetFramework.StartsWith('net4')) AND '$(NGenBinary)' == 'true' AND '$(IsAdministrator)' == 'true' AND Exists('$(TargetPath)') ">
+
- $(windir)\Microsoft.NET\Framework64\v4.0.30319\ngen.exe
$(windir)\Microsoft.NET\Framework\v4.0.30319\ngen.exe
- $(WindowsSDK_ExecutablePath_x86)sn.exe
+ $(windir)\Microsoft.NET\Framework64\v4.0.30319\ngen.exe
-
-
+
+
+
+
+
+
+
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+ $(WindowsSDK_ExecutablePath_x86)\sn.exe
+ $(WindowsSDK_ExecutablePath_x64)\sn.exe
+
+
+
+
+
+
+
diff --git a/eng/targets/Settings.props b/eng/targets/Settings.props
index 6360088320f..44bf3f36686 100644
--- a/eng/targets/Settings.props
+++ b/eng/targets/Settings.props
@@ -2,14 +2,14 @@
MIT
- Microsoft and F# Software Foundation
+ $(MSBuildThisFileDirectory)..\..\src\fsharp\icon.png
Visual F# Compiler FSharp functional programming
$(ArtifactsBinDir)
-
- false
+
+ false
diff --git a/eng/tests/UpToDate.ps1 b/eng/tests/UpToDate.ps1
index a7e50a26d60..545e149069a 100644
--- a/eng/tests/UpToDate.ps1
+++ b/eng/tests/UpToDate.ps1
@@ -16,17 +16,26 @@ try {
# do first build
& $BuildScript -configuration $configuration @properties
if ($LASTEXITCODE -ne 0) {
- Write-Host "Error running first build."
+ Write-Host "##[error](NETCORE_ENGINEERING_TELEMETRY=Build) Error running first build."
exit 1
}
# gather assembly timestamps
$ArtifactsBinDir = Join-Path $RepoRoot "artifacts" | Join-Path -ChildPath "bin" -Resolve
$FSharpAssemblyDirs = Get-ChildItem -Path $ArtifactsBinDir -Filter "FSharp.*"
- $FSharpAssemblyPaths = $FSharpAssemblyDirs | ForEach-Object { Get-ChildItem -Path (Join-Path $ArtifactsBinDir $_) -Recurse -Filter "$_.dll" } | ForEach-Object { $_.FullName }
+ $FscAssemblyDir = Get-ChildItem -Path $ArtifactsBinDir -Filter "fsc"
+ $FsiAssemblyDir = Get-ChildItem -Path $ArtifactsBinDir -Filter "fsi"
+ $FsiAnyCpuAssemblyDir = Get-ChildItem -Path $ArtifactsBinDir -Filter "fsiAnyCpu"
+ $DmAssemblyDir = Get-ChildItem -Path $ArtifactsBinDir -Filter "Microsoft.DotNet.DependencyManager"
+ $ProjectSystemAssemblyDirs = Get-ChildItem -Path $ArtifactsBinDir -Filter "ProjectSystem*"
+ $FSharpDirs = @($FSharpAssemblyDirs) + @($FscAssemblyDir) + @($FsiAssemblyDir) + @($FsiAnyCpuAssemblyDir) + @($DmAssemblyDir) + @($ProjectSystemAssemblyDirs)
+ $FSharpDllPaths = $FSharpDirs | ForEach-Object { Get-ChildItem -Path (Join-Path $ArtifactsBinDir $_) -Recurse -Filter "*.dll" } | ForEach-Object { $_.FullName }
+ $FSharpExePaths = $FSharpDirs | ForEach-Object { Get-ChildItem -Path (Join-Path $ArtifactsBinDir $_) -Recurse -Filter "*.exe" } | ForEach-Object { $_.FullName }
+ $FSharpAssemblyPaths = @($FSharpDllPaths) + @($FSharpExePaths)
$InitialAssembliesAndTimes = @{}
foreach ($asm in $FSharpAssemblyPaths) {
+ Write-Host "Assembly : $asm"
$LastWriteTime = (Get-Item $asm).LastWriteTimeUtc
$InitialAssembliesAndTimes.Add($asm, $LastWriteTime)
}
@@ -36,7 +45,7 @@ try {
# build again
& $BuildScript -configuration $configuration @properties
if ($LASTEXITCODE -ne 0) {
- Write-Host "Error running second build."
+ Write-Host "##[error](NETCORE_ENGINEERING_TELEMETRY=Build) Error running second build."
exit 1
}
@@ -53,14 +62,20 @@ try {
$InitialTime = $InitialAssembliesAndTimes[$asm]
$FinalTime = $FinalAssembliesAndTimes[$asm]
if ($InitialTime -ne $FinalTime) {
+ Write-Host "Rebuilt assembly: $asm"
$RecompiledFiles += $asm
}
}
$RecompiledCount = $RecompiledFiles.Length
- Write-Host "$RecompiledCount of $InitialCompiledCount assemblies were re-compiled"
- $RecompiledFiles | ForEach-Object { Write-Host " $_" }
- exit $RecompiledCount
+ if ($RecompiledCount -ge 0) {
+ Write-Host "##[error](NETCORE_ENGINEERING_TELEMETRY=Test) $RecompiledCount of $InitialCompiledCount assemblies were re-compiled."
+ $RecompiledFiles | ForEach-Object { Write-Host " $_" }
+ exit $RecompiledCount
+ } else {
+ Write-Host "No assemblies rebuilt."
+ exit 0
+ }
}
catch {
Write-Host $_
diff --git a/fcs/samples/EditorService/App.config b/fcs-samples/EditorService/App.config
similarity index 100%
rename from fcs/samples/EditorService/App.config
rename to fcs-samples/EditorService/App.config
diff --git a/fcs/samples/EditorService/EditorService.fsproj b/fcs-samples/EditorService/EditorService.fsproj
similarity index 93%
rename from fcs/samples/EditorService/EditorService.fsproj
rename to fcs-samples/EditorService/EditorService.fsproj
index d71d6dc2913..5ce569ffaac 100644
--- a/fcs/samples/EditorService/EditorService.fsproj
+++ b/fcs-samples/EditorService/EditorService.fsproj
@@ -1,7 +1,7 @@
- $(FcsTargetNetFxFramework);netcoreapp2.0
+ $(FcsTargetNetFxFramework);netcoreapp3.1
true
Exe
false
diff --git a/fcs-samples/EditorService/Program.fs b/fcs-samples/EditorService/Program.fs
new file mode 100644
index 00000000000..d457bf17c91
--- /dev/null
+++ b/fcs-samples/EditorService/Program.fs
@@ -0,0 +1,47 @@
+// Open the namespace with InteractiveChecker type
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.QuickParse
+
+// Create an interactive checker instance (ignore notifications)
+let checker = FSharpChecker.Create()
+
+let parseWithTypeInfo (file, input) =
+ let input = FSharp.Compiler.Text.SourceText.ofString input
+ let checkOptions, _errors = checker.GetProjectOptionsFromScript(file, input) |> Async.RunSynchronously
+ let parsingOptions, _errors = checker.GetParsingOptionsFromProjectOptions(checkOptions)
+ let untypedRes = checker.ParseFile(file, input, parsingOptions) |> Async.RunSynchronously
+
+ match checker.CheckFileInProject(untypedRes, file, 0, input, checkOptions) |> Async.RunSynchronously with
+ | FSharpCheckFileAnswer.Succeeded(res) -> untypedRes, res
+ | res -> failwithf "Parsing did not finish... (%A)" res
+
+// ----------------------------------------------------------------------------
+// Example
+// ----------------------------------------------------------------------------
+
+let input =
+ """
+ let foo() =
+ let msg = "Hello world"
+ if true then
+ printfn "%s" msg.
+ """
+let inputLines = input.Split('\n')
+let file = "/home/user/Test.fsx"
+
+let identTokenTag = FSharpTokenTag.Identifier
+let untyped, parsed = parseWithTypeInfo (file, input)
+// Get tool tip at the specified location
+let tip = parsed.GetToolTipText(2, 7, inputLines.[1], [ "foo" ], identTokenTag)
+
+printfn "%A" tip
+
+let partialName = GetPartialLongNameEx(inputLines.[4], 23)
+
+// Get declarations (autocomplete) for a location
+let decls =
+ parsed.GetDeclarationListInfo(Some untyped, 5, inputLines.[4], partialName, (fun () -> []))
+ |> Async.RunSynchronously
+
+for item in decls.Items do
+ printfn " - %s" item.Name
diff --git a/fcs/samples/FscExe/App.config b/fcs-samples/FscExe/App.config
similarity index 100%
rename from fcs/samples/FscExe/App.config
rename to fcs-samples/FscExe/App.config
diff --git a/fcs/samples/FscExe/FscExe.fsproj b/fcs-samples/FscExe/FscExe.fsproj
similarity index 100%
rename from fcs/samples/FscExe/FscExe.fsproj
rename to fcs-samples/FscExe/FscExe.fsproj
diff --git a/fcs/samples/FscExe/FscMain.fs b/fcs-samples/FscExe/FscMain.fs
similarity index 98%
rename from fcs/samples/FscExe/FscMain.fs
rename to fcs-samples/FscExe/FscMain.fs
index 26f26be63d1..36b980cbbb3 100644
--- a/fcs/samples/FscExe/FscMain.fs
+++ b/fcs-samples/FscExe/FscMain.fs
@@ -7,12 +7,10 @@ open System.Diagnostics
open System.IO
open System.Reflection
open System.Runtime.CompilerServices
-open FSharp.Compiler
open FSharp.Compiler.SourceCodeServices
-open FSharp.Compiler.AbstractIL.IL // runningOnMono
+open FSharp.Compiler.AbstractIL.Internal.Utils // runningOnMono
open FSharp.Compiler.AbstractIL.Internal.Library
open FSharp.Compiler.ErrorLogger
-open FSharp.Compiler.Range
#if RESIDENT_COMPILER
type TypeInThisAssembly() = member x.Dummy = 1
@@ -266,10 +264,6 @@ module Driver =
if runningOnMono && hasArgument "resident" argv then
let argv = stripArgument "resident" argv
- //if not (hasArgument "nologo" argv) then
- // printfn "%s" (FSComp.SR.buildProductName(FSharpEnvironment.FSharpTeamVersionNumber))
- // printfn "%s" (FSComp.SR.optsCopyright())
-
let fscServerExe = typeof.Assembly.Location
let exitCodeOpt = FSharpResidentCompiler.FSharpCompilationServer.TryCompileUsingServer (fscServerExe, argv)
match exitCodeOpt with
diff --git a/fcs/samples/FsiExe/App.config b/fcs-samples/FsiExe/App.config
similarity index 100%
rename from fcs/samples/FsiExe/App.config
rename to fcs-samples/FsiExe/App.config
diff --git a/fcs/samples/FsiExe/FsiExe.fsproj b/fcs-samples/FsiExe/FsiExe.fsproj
similarity index 100%
rename from fcs/samples/FsiExe/FsiExe.fsproj
rename to fcs-samples/FsiExe/FsiExe.fsproj
diff --git a/fcs/samples/FsiExe/console.fs b/fcs-samples/FsiExe/console.fs
similarity index 100%
rename from fcs/samples/FsiExe/console.fs
rename to fcs-samples/FsiExe/console.fs
diff --git a/fcs/samples/FsiExe/fsimain.fs b/fcs-samples/FsiExe/fsimain.fs
similarity index 99%
rename from fcs/samples/FsiExe/fsimain.fs
rename to fcs-samples/FsiExe/fsimain.fs
index c59ef2fe50f..5fb34c3af17 100644
--- a/fcs/samples/FsiExe/fsimain.fs
+++ b/fcs-samples/FsiExe/fsimain.fs
@@ -17,13 +17,11 @@ module internal Sample.FSharp.Compiler.Interactive.Main
open System
open System.Globalization
-open System.IO
open System.Reflection
open System.Threading
open System.Windows.Forms
open FSharp.Compiler.Interactive.Shell
-open FSharp.Compiler.Interactive
open FSharp.Compiler
#nowarn "55"
diff --git a/fcs/samples/FsiExe/fsiserver.fs b/fcs-samples/FsiExe/fsiserver.fs
similarity index 91%
rename from fcs/samples/FsiExe/fsiserver.fs
rename to fcs-samples/FsiExe/fsiserver.fs
index 838c2593046..6fafe5d1bcb 100644
--- a/fcs/samples/FsiExe/fsiserver.fs
+++ b/fcs-samples/FsiExe/fsiserver.fs
@@ -33,10 +33,6 @@ open System.Runtime.Remoting.Lifetime
type internal FSharpInteractiveServer() =
inherit System.MarshalByRefObject()
abstract Interrupt : unit -> unit
-#if FSI_SERVER_INTELLISENSE
- abstract Completions : prefix:string -> string array
- abstract GetDeclarations : text:string * names:string array -> (string * string * string * int) array
-#endif
default x.Interrupt() = ()
[]
diff --git a/fcs/samples/InteractiveService/App.config b/fcs-samples/InteractiveService/App.config
similarity index 100%
rename from fcs/samples/InteractiveService/App.config
rename to fcs-samples/InteractiveService/App.config
diff --git a/fcs/samples/InteractiveService/InteractiveService.fsproj b/fcs-samples/InteractiveService/InteractiveService.fsproj
similarity index 100%
rename from fcs/samples/InteractiveService/InteractiveService.fsproj
rename to fcs-samples/InteractiveService/InteractiveService.fsproj
diff --git a/fcs/samples/InteractiveService/Program.fs b/fcs-samples/InteractiveService/Program.fs
similarity index 100%
rename from fcs/samples/InteractiveService/Program.fs
rename to fcs-samples/InteractiveService/Program.fs
diff --git a/fcs/samples/Tokenizer/App.config b/fcs-samples/Tokenizer/App.config
similarity index 100%
rename from fcs/samples/Tokenizer/App.config
rename to fcs-samples/Tokenizer/App.config
diff --git a/fcs/samples/Tokenizer/Program.fs b/fcs-samples/Tokenizer/Program.fs
similarity index 100%
rename from fcs/samples/Tokenizer/Program.fs
rename to fcs-samples/Tokenizer/Program.fs
diff --git a/fcs/samples/Tokenizer/Tokenizer.fsproj b/fcs-samples/Tokenizer/Tokenizer.fsproj
similarity index 100%
rename from fcs/samples/Tokenizer/Tokenizer.fsproj
rename to fcs-samples/Tokenizer/Tokenizer.fsproj
diff --git a/fcs/samples/UntypedTree/App.config b/fcs-samples/UntypedTree/App.config
similarity index 100%
rename from fcs/samples/UntypedTree/App.config
rename to fcs-samples/UntypedTree/App.config
diff --git a/fcs-samples/UntypedTree/Program.fs b/fcs-samples/UntypedTree/Program.fs
new file mode 100644
index 00000000000..c3c0ac538a1
--- /dev/null
+++ b/fcs-samples/UntypedTree/Program.fs
@@ -0,0 +1,91 @@
+// Open the namespace with InteractiveChecker type
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.SyntaxTree
+
+// Create a checker instance (ignore notifications)
+let checker = FSharpChecker.Create()
+
+// ------------------------------------------------------------------
+
+// Get untyped tree for a specified input
+let getUntypedTree (file, input) =
+ let parsingOptions = { FSharpParsingOptions.Default with SourceFiles = [| file |] }
+ let untypedRes = checker.ParseFile(file, FSharp.Compiler.Text.SourceText.ofString input, parsingOptions) |> Async.RunSynchronously
+ match untypedRes.ParseTree with
+ | Some tree -> tree
+ | None -> failwith "Something went wrong during parsing!"
+
+// ------------------------------------------------------------------
+
+/// Walk over all module or namespace declarations
+/// (basically 'module Foo =' or 'namespace Foo.Bar')
+/// Note that there is one implicitly, even if the file
+/// does not explicitly define it..
+let rec visitModulesAndNamespaces modulesOrNss =
+ for moduleOrNs in modulesOrNss do
+ let (SynModuleOrNamespace(lid, isRec, isModule, decls, xmlDoc, attribs, synAccess, m)) = moduleOrNs
+ printfn "Namespace or module: %A" lid
+ visitDeclarations decls
+
+/// Walk over a pattern - this is for example used in
+/// let = or in the 'match' expression
+and visitPattern = function
+ | SynPat.Wild(_) ->
+ printfn " .. underscore pattern"
+ | SynPat.Named(pat, name, _, _, _) ->
+ visitPattern pat
+ printfn " .. named as '%s'" name.idText
+ | SynPat.LongIdent(LongIdentWithDots(ident, _), _, _, _, _, _) ->
+ printfn " identifier: %s" (String.concat "." [ for i in ident -> i.idText ])
+ | pat -> printfn " - not supported pattern: %A" pat
+
+/// Walk over an expression - the most interesting part :-)
+and visitExpression = function
+ | SynExpr.IfThenElse(cond, trueBranch, falseBranchOpt, _, _, _, _) ->
+ printfn "Conditional:"
+ visitExpression cond
+ visitExpression trueBranch
+ falseBranchOpt |> Option.iter visitExpression
+
+ | SynExpr.LetOrUse(_, _, bindings, body, _) ->
+ printfn "LetOrUse with the following bindings:"
+ for binding in bindings do
+ let (Binding(access, kind, inlin, mutabl, attrs, xmlDoc, data, pat, retInfo, body, m, sp)) = binding
+ visitPattern pat
+ printfn "And the following body:"
+ visitExpression body
+ | expr -> printfn " - not supported expression: %A" expr
+
+/// Walk over a list of declarations in a module. This is anything
+/// that you can write as a top-level inside module (let bindings,
+/// nested modules, type declarations etc.)
+and visitDeclarations decls =
+ for declaration in decls do
+ match declaration with
+ | SynModuleDecl.Let(isRec, bindings, range) ->
+ for binding in bindings do
+ let (Binding(access, kind, inlin, mutabl, attrs, xmlDoc, data, pat, retInfo, body, m, sp)) = binding
+ visitPattern pat
+ visitExpression body
+ | _ -> printfn " - not supported declaration: %A" declaration
+
+
+// ------------------------------------------------------------------
+
+// Sample input for the compiler service
+let input = """
+ let foo() =
+ let msg = "Hello world"
+ if true then
+ printfn "%s" msg """
+let file = "/home/user/Test.fsx"
+
+let tree = getUntypedTree(file, input)
+
+// Testing: Print the AST to see what it looks like
+// tree |> printfn "%A"
+
+match tree with
+| ParsedInput.ImplFile(ParsedImplFileInput(file, isScript, qualName, pragmas, hashDirectives, modules, b)) ->
+ visitModulesAndNamespaces modules
+| _ -> failwith "F# Interface file (*.fsi) not supported."
\ No newline at end of file
diff --git a/fcs/samples/UntypedTree/UntypedTree.fsproj b/fcs-samples/UntypedTree/UntypedTree.fsproj
similarity index 100%
rename from fcs/samples/UntypedTree/UntypedTree.fsproj
rename to fcs-samples/UntypedTree/UntypedTree.fsproj
diff --git a/fcs/.gitignore b/fcs/.gitignore
deleted file mode 100644
index a21a02ee547..00000000000
--- a/fcs/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
-.paket/
-FSharp.Compiler.Service.Tests/TestResults/*
-FSharp.Compiler.Service.netstandard/illex.fs
-FSharp.Compiler.Service.netstandard/ilpars.fs
-FSharp.Compiler.Service.netstandard/ilpars.fsi
-FSharp.Compiler.Service.netstandard/lex.fs
-FSharp.Compiler.Service.netstandard/pars.fs
-FSharp.Compiler.Service.netstandard/pars.fsi
-FSharp.Compiler.Service.netstandard/pplex.fs
-FSharp.Compiler.Service.netstandard/pppars.fs
-FSharp.Compiler.Service.netstandard/pppars.fsi
-
diff --git a/fcs/Directory.Build.props b/fcs/Directory.Build.props
deleted file mode 100644
index 2841a5fb34f..00000000000
--- a/fcs/Directory.Build.props
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
- $(RestoreSources);
- https://api.nuget.org/v3/index.json;
- https://dotnet.myget.org/F/fsharp/api/v3/index.json;
-
-
-
-
- $(UserProfile)\.nuget\packages\
- $(HOME)/.nuget/packages/
- $(NuGetPackageRoot)\
- $(NuGetPackageRoot)/
- $(MSBuildThisFileDirectory)..\artifacts
- $(ArtifactsDir)\bin
- $(ArtifactsDir)\obj
- $(ArtifactsBinDir)\fcs\$(Configuration)
- $(ArtifactsObjDir)\fcs\$(Configuration)
- true
-
-
-
-
- $(MSBuildThisFileDirectory)..\src
- 22.0.3
- --version:$(VersionPrefix)
- false
-
-
- $(FSharpSourcesRoot)\..\packages\FSharp.Compiler.Tools.4.1.27\tools
- fsi.exe
- 4.6.2
- net461
-
-
diff --git a/fcs/Directory.Build.targets b/fcs/Directory.Build.targets
deleted file mode 100644
index 3c45a524874..00000000000
--- a/fcs/Directory.Build.targets
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
- <__TargetFilePath>@(NoneSubstituteText->'$(IntermediateOutputPath)%(Filename)%(Extension)')
- <__TargetFileName>@(NoneSubstituteText->'%(Filename)%(Extension)')
-
- <_ReplacementText>$([System.IO.File]::ReadAllText('%(NoneSubstituteText.FullPath)'))
- <_ReplacementText Condition="'%(NoneSubstituteText.Pattern1)' != ''">$(_ReplacementText.Replace('%(NoneSubstituteText.Pattern1)', '%(NoneSubstituteText.Replacement1)'))
- <_ReplacementText Condition="'%(NoneSubstituteText.Pattern2)' != ''">$(_ReplacementText.Replace('%(NoneSubstituteText.Pattern2)', '%(NoneSubstituteText.Replacement2)'))
-
- <_CopyToOutputDirectory Condition="'%(NoneSubstituteText.CopyToOutputDirectory)' != ''">%(NoneSubstituteText.CopyToOutputDirectory)
- <_CopyToOutputDirectory Condition="'%(NoneSubstituteText.CopyToOutputDirectory)' == ''">Never
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <_BuildPropertyLines Remove="@(_BuildPropertyLines)" />
- <_BuildPropertyLines Include="// <auto-generated >" />
- <_BuildPropertyLines Include="// <Generated by the FSharp WriteCodeFragment class./>" />
- <_BuildPropertyLines Include="// </auto-generated/>" />
- <_BuildPropertyLines Include="//" />
- <_BuildPropertyLines Include="module internal FSharp.BuildProperties" />
- <_BuildPropertyLines Include="let fsProductVersion = "$(FSPRODUCTVERSION)"" />
- <_BuildPropertyLines Include="let fsLanguageVersion = "$(FSLANGUAGEVERSION)"" />
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/fcs/FSharp.Compiler.Service.MSBuild.v12/FSharp.Compiler.Service.MSBuild.v12.fsproj b/fcs/FSharp.Compiler.Service.MSBuild.v12/FSharp.Compiler.Service.MSBuild.v12.fsproj
deleted file mode 100644
index 486401ae8be..00000000000
--- a/fcs/FSharp.Compiler.Service.MSBuild.v12/FSharp.Compiler.Service.MSBuild.v12.fsproj
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
- $(FcsTargetNetFxFramework)
- true
- $(DefineConstants);CROSS_PLATFORM_COMPILER
- $(DefineConstants);ENABLE_MONO_SUPPORT
-
-
- Additional DLL for legacy compat for the F# compiler service.
- Additional DLL for legacy compat for the F# compiler service.
- false
- Microsoft Corporation; F# community contributors
- https://github.com/fsharp/FSharp.Compiler.Service/blob/master/LICENSE
- https://github.com/fsharp/FSharp.Compiler.Service
- https://raw.github.com/fsharp/FSharp.Compiler.Service/master/misc/logo.png
- F#, compiler, msbuild
-
-
-
- Service/MSBuildReferenceResolver.fs
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/fcs/FSharp.Compiler.Service.ProjectCracker/FSharp.Compiler.Service.ProjectCracker.fsproj b/fcs/FSharp.Compiler.Service.ProjectCracker/FSharp.Compiler.Service.ProjectCracker.fsproj
deleted file mode 100644
index 1a4171e13a0..00000000000
--- a/fcs/FSharp.Compiler.Service.ProjectCracker/FSharp.Compiler.Service.ProjectCracker.fsproj
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
- $(FcsTargetNetFxFramework)
- true
-
-
- Legacy project file cracker for the F# compiler service.
- Legacy project file cracker for the F# compiler service.
- false
- Microsoft Corporation; F# community contributors
- https://github.com/fsharp/FSharp.Compiler.Service/blob/master/LICENSE
- https://github.com/fsharp/FSharp.Compiler.Service
- https://raw.github.com/fsharp/FSharp.Compiler.Service/master/misc/logo.png
- F#, compiler, msbuild
-
-
-
- ProjectCrackerOptions.fs
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/fcs/FSharp.Compiler.Service.ProjectCracker/ProjectCracker.fs b/fcs/FSharp.Compiler.Service.ProjectCracker/ProjectCracker.fs
deleted file mode 100644
index d5be2c7565f..00000000000
--- a/fcs/FSharp.Compiler.Service.ProjectCracker/ProjectCracker.fs
+++ /dev/null
@@ -1,130 +0,0 @@
-namespace FSharp.Compiler.SourceCodeServices
-
-#if !NETSTANDARD
-open System.Runtime.Serialization.Json
-open System.Runtime
-open System.Diagnostics
-#endif
-open System.Text
-open System.IO
-open System
-open System.Xml
-
-module Utils =
-
- let Convert loadedTimeStamp (originalOpts: ProjectCrackerTool.ProjectOptions) =
- let logMap = ref Map.empty
-
- let rec convertProject (opts: ProjectCrackerTool.ProjectOptions) =
- if not (isNull opts.Error) then failwith opts.Error
-
- let referencedProjects() = Array.map (fun (a, b) -> a,convertProject b) opts.ReferencedProjectOptions
-
- let sourceFiles, otherOptions =
- opts.Options
- |> Array.partition (fun x ->
- let extension = Path.GetExtension(x).ToLower()
- x.IndexOfAny(Path.GetInvalidPathChars()) = -1
- && (extension = ".fs" || extension = ".fsi"))
-
- let sepChar = Path.DirectorySeparatorChar
-
- let sourceFiles = sourceFiles |> Array.map (fun x ->
- match sepChar with
- | '\\' -> x.Replace('/', '\\')
- | '/' -> x.Replace('\\', '/')
- | _ -> x
- )
-
- logMap := Map.add opts.ProjectFile opts.LogOutput !logMap
- { ProjectFileName = opts.ProjectFile
- ProjectId = None
- SourceFiles = sourceFiles
- OtherOptions = otherOptions
- ReferencedProjects = referencedProjects()
- IsIncompleteTypeCheckEnvironment = false
- UseScriptResolutionRules = false
- LoadTime = loadedTimeStamp
- UnresolvedReferences = None
- OriginalLoadReferences = []
- ExtraProjectInfo = None
- Stamp = None }
-
- convertProject originalOpts, !logMap
-
-type ProjectCracker =
-
- static member GetProjectOptionsFromProjectFileLogged(projectFileName : string, ?properties : (string * string) list, ?loadedTimeStamp, ?enableLogging) =
- let loadedTimeStamp = defaultArg loadedTimeStamp DateTime.MaxValue // Not 'now', we don't want to force reloading
- let properties = defaultArg properties []
- let enableLogging = defaultArg enableLogging true
-
-
-#if NETSTANDARD
- let arguments = [|
- yield projectFileName
- yield enableLogging.ToString()
- for k, v in properties do
- yield k
- yield v
- |]
-
- let ret, opts = FSharp.Compiler.SourceCodeServices.ProjectCrackerTool.ProjectCrackerTool.crackOpen arguments
- ignore ret
-#else
- let arguments = new StringBuilder()
- arguments.Append('"').Append(projectFileName).Append('"') |> ignore
- arguments.Append(' ').Append(enableLogging.ToString()) |> ignore
- for k, v in properties do
- arguments.Append(' ').Append(k).Append(' ').Append(v) |> ignore
- let codebase = Path.GetDirectoryName(Uri(typeof.Assembly.CodeBase).LocalPath)
-
- let crackerFilename = Path.Combine(codebase,"FSharp.Compiler.Service.ProjectCrackerTool.exe")
- if not (File.Exists crackerFilename) then
- failwithf "ProjectCracker exe not found at: %s it must be next to the ProjectCracker dll." crackerFilename
-
- let p = new System.Diagnostics.Process()
-
- p.StartInfo.FileName <- crackerFilename
- p.StartInfo.Arguments <- arguments.ToString()
- p.StartInfo.UseShellExecute <- false
- p.StartInfo.CreateNoWindow <- true
- p.StartInfo.RedirectStandardOutput <- true
- p.StartInfo.RedirectStandardError <- true
-
- let sbOut = StringBuilder()
- let sbErr = StringBuilder()
-
- p.ErrorDataReceived.AddHandler(fun _ a -> sbErr.AppendLine a.Data |> ignore)
- p.OutputDataReceived.AddHandler(fun _ a -> sbOut.AppendLine a.Data |> ignore)
-
- ignore <| p.Start()
-
- p.EnableRaisingEvents <- true
- p.BeginOutputReadLine()
- p.BeginErrorReadLine()
-
- p.WaitForExit()
-
- let crackerOut = sbOut.ToString()
- let crackerErr = sbErr.ToString()
-
- let opts =
- try
- let ser = new DataContractJsonSerializer(typeof)
- let stringBytes = Encoding.Unicode.GetBytes crackerOut
- use ms = new MemoryStream(stringBytes)
- ser.ReadObject(ms) :?> ProjectCrackerTool.ProjectOptions
- with
- exn ->
- raise (Exception(sprintf "error parsing ProjectCrackerTool output, stdoutput was:\n%s\n\nstderr was:\n%s" crackerOut crackerErr, exn))
-#endif
-
- Utils.Convert loadedTimeStamp opts
-
- static member GetProjectOptionsFromProjectFile(projectFileName : string, ?properties : (string * string) list, ?loadedTimeStamp) =
- fst (ProjectCracker.GetProjectOptionsFromProjectFileLogged(
- projectFileName,
- ?properties=properties,
- ?loadedTimeStamp=loadedTimeStamp,
- enableLogging=false))
diff --git a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/App.config b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/App.config
deleted file mode 100644
index fdab151af22..00000000000
--- a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/App.config
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/FSharp.Compiler.Service.ProjectCracker.targets b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/FSharp.Compiler.Service.ProjectCracker.targets
deleted file mode 100644
index ed01293adaf..00000000000
--- a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/FSharp.Compiler.Service.ProjectCracker.targets
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/FSharp.Compiler.Service.ProjectCrackerTool.fsproj b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/FSharp.Compiler.Service.ProjectCrackerTool.fsproj
deleted file mode 100644
index 19789a96299..00000000000
--- a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/FSharp.Compiler.Service.ProjectCrackerTool.fsproj
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
- Exe
- $(FcsTargetNetFxFramework)
- true
- $(DefineConstants);CROSS_PLATFORM_COMPILER
- $(DefineConstants);ENABLE_MONO_SUPPORT
- $(OtherFlags) --staticlink:FSharp.Core
- true
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/Program.fs b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/Program.fs
deleted file mode 100644
index 8379737c939..00000000000
--- a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/Program.fs
+++ /dev/null
@@ -1,46 +0,0 @@
-namespace FSharp.Compiler.SourceCodeServices.ProjectCrackerTool
-
-open System
-open System.Reflection
-open System.Runtime.Serialization.Json
-
-module Program =
-
-#if !NETCOREAPP2_0
- let addMSBuildv14BackupResolution () =
- let onResolveEvent = new ResolveEventHandler(fun sender evArgs ->
- let requestedAssembly = AssemblyName(evArgs.Name)
- if requestedAssembly.Name.StartsWith("Microsoft.Build", StringComparison.Ordinal) &&
- not (requestedAssembly.Name.EndsWith(".resources", StringComparison.Ordinal)) &&
- not (requestedAssembly.Version.ToString().Contains("12.0.0.0"))
- then
- // If the version of MSBuild that we're using wasn't present on the machine, then
- // just revert back to 12.0.0.0 since that's normally installed as part of the .NET
- // Framework.
- requestedAssembly.Version <- Version("12.0.0.0")
- Assembly.Load requestedAssembly
- else
- null)
- AppDomain.CurrentDomain.add_AssemblyResolve(onResolveEvent)
-#endif
-
- let crackAndSendOutput asText argv =
- let ret, opts = ProjectCrackerTool.crackOpen argv
-
- if asText then
- printfn "%A" opts
- else
- let ser = new DataContractJsonSerializer(typeof)
- ser.WriteObject(Console.OpenStandardOutput(), opts)
- ret
-
-
- [][]
- let main argv =
- let asText = Array.exists (fun (s: string) -> s = "--text") argv
- let argv = Array.filter (fun (s: string) -> s <> "--text") argv
-
-#if !NETCOREAPP2_0
- addMSBuildv14BackupResolution ()
-#endif
- crackAndSendOutput asText argv
diff --git a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/ProjectCrackerOptions.fs b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/ProjectCrackerOptions.fs
deleted file mode 100644
index a48bdc25aa7..00000000000
--- a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/ProjectCrackerOptions.fs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace FSharp.Compiler.SourceCodeServices.ProjectCrackerTool
-
-[]
-type ProjectOptions =
- {
- ProjectFile: string
- Options: string[]
- ReferencedProjectOptions: (string * ProjectOptions)[]
- LogOutput: string
- Error: string
- }
diff --git a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/ProjectCrackerTool.fs b/fcs/FSharp.Compiler.Service.ProjectCrackerTool/ProjectCrackerTool.fs
deleted file mode 100644
index 7cf970f7a7f..00000000000
--- a/fcs/FSharp.Compiler.Service.ProjectCrackerTool/ProjectCrackerTool.fs
+++ /dev/null
@@ -1,472 +0,0 @@
-namespace FSharp.Compiler.SourceCodeServices.ProjectCrackerTool
-
-open System
-open System.IO
-open System.Text
-open Microsoft.Build.Framework
-open Microsoft.Build.Utilities
-
-module internal ProjectCrackerTool =
- open System.Collections.Generic
- open Microsoft.Build.Evaluation
-
- let runningOnMono =
-#if NETCOREAPP2_0
- false
-#else
- try match System.Type.GetType("Mono.Runtime") with null -> false | _ -> true
- with e -> false
-#endif
-
- type internal BasicStringLogger() =
- inherit Logger()
-
- let sb = new StringBuilder()
-
- let log (e: BuildEventArgs) =
- sb.Append(e.Message) |> ignore
- sb.AppendLine() |> ignore
-
- override x.Initialize(eventSource:IEventSource) =
- sb.Clear() |> ignore
- eventSource.AnyEventRaised.Add(log)
-
- member x.Log = sb.ToString()
-
- type internal HostCompile() =
- member th.Compile(_:obj, _:obj, _:obj) = 0
- interface ITaskHost
-
- let vs =
- let programFiles =
- let getEnv v =
- let result = System.Environment.GetEnvironmentVariable(v)
- match result with
- | null -> None
- | _ -> Some result
-
- match List.tryPick getEnv [ "ProgramFiles(x86)"; "ProgramFiles" ] with
- | Some r -> r
- | None -> "C:\\Program Files (x86)"
-
- let vsVersions = ["14.0"; "12.0"]
- let msbuildBin v = IO.Path.Combine(programFiles, "MSBuild", v, "Bin", "MSBuild.exe")
- List.tryFind (fun v -> IO.File.Exists(msbuildBin v)) vsVersions
-
- let mkAbsolute dir v =
- if Path.IsPathRooted v then v
- else Path.Combine(dir, v)
-
- let mkAbsoluteOpt dir v = Option.map (mkAbsolute dir) v
-
- let CrackProjectUsingNewBuildAPI fsprojFile properties logOpt =
- let fsprojFullPath = try Path.GetFullPath(fsprojFile) with _ -> fsprojFile
- let fsprojAbsDirectory = Path.GetDirectoryName fsprojFullPath
-
- use _pwd =
- let dir = Directory.GetCurrentDirectory()
- Directory.SetCurrentDirectory(fsprojAbsDirectory)
- { new System.IDisposable with
- member x.Dispose() = Directory.SetCurrentDirectory(dir) }
- use engine = new Microsoft.Build.Evaluation.ProjectCollection()
- let host = new HostCompile()
-
- engine.HostServices.RegisterHostObject(fsprojFullPath, "CoreCompile", "Fsc", host)
-
- let projectInstanceFromFullPath (fsprojFullPath: string) =
- use file = new FileStream(fsprojFullPath, FileMode.Open, FileAccess.Read, FileShare.Read)
- use stream = new StreamReader(file)
- use xmlReader = System.Xml.XmlReader.Create(stream)
-
- let project =
- try
- engine.LoadProject(xmlReader, FullPath=fsprojFullPath)
- with
- | exn ->
- let tools = engine.Toolsets |> Seq.map (fun x -> x.ToolsPath) |> Seq.toList
- raise (new Exception(sprintf "Could not load project %s in ProjectCollection. Available tools: %A. Message: %s" fsprojFullPath tools exn.Message))
-
- project.SetGlobalProperty("BuildingInsideVisualStudio", "true") |> ignore
- if not (List.exists (fun (p,_) -> p = "VisualStudioVersion") properties) then
- match vs with
- | Some version -> project.SetGlobalProperty("VisualStudioVersion", version) |> ignore
- | None -> ()
- project.SetGlobalProperty("ShouldUnsetParentConfigurationAndPlatform", "false") |> ignore
- for (prop, value) in properties do
- project.SetGlobalProperty(prop, value) |> ignore
-
- project.CreateProjectInstance()
-
- let project = projectInstanceFromFullPath fsprojFullPath
- let directory = project.Directory
-
- let getprop (p: Microsoft.Build.Execution.ProjectInstance) s =
- let v = p.GetPropertyValue s
- if String.IsNullOrWhiteSpace v then None
- else Some v
-
- let outFileOpt = getprop project "TargetPath"
-
- let log = match logOpt with
- | None -> []
- | Some l -> [l :> ILogger]
-
- project.Build([| "Build" |], log) |> ignore
-
- let getItems s = [ for f in project.GetItems(s) -> mkAbsolute directory f.EvaluatedInclude ]
-
- let projectReferences =
- [ for cp in project.GetItems("ProjectReference") do
- yield cp.GetMetadataValue("FullPath")
- ]
-
- let references =
- [ for i in project.GetItems("ReferencePath") do
- yield i.EvaluatedInclude
- for i in project.GetItems("ChildProjectReferences") do
- yield i.EvaluatedInclude ]
-
- outFileOpt, directory, getItems, references, projectReferences, getprop project, project.FullPath
-
-#if !NETCOREAPP2_0
- let CrackProjectUsingOldBuildAPI (fsprojFile:string) properties logOpt =
- let engine = new Microsoft.Build.BuildEngine.Engine()
- Option.iter (fun l -> engine.RegisterLogger(l)) logOpt
-
- let bpg = Microsoft.Build.BuildEngine.BuildPropertyGroup()
-
- bpg.SetProperty("BuildingInsideVisualStudio", "true")
- for (prop, value) in properties do
- bpg.SetProperty(prop, value)
-
- engine.GlobalProperties <- bpg
-
- let projectFromFile (fsprojFile:string) =
- // We seem to need to pass 12.0/4.0 in here for some unknown reason
- let project = new Microsoft.Build.BuildEngine.Project(engine, engine.DefaultToolsVersion)
- do project.Load(fsprojFile)
- project
-
- let project = projectFromFile fsprojFile
- project.Build([| "ResolveReferences" |]) |> ignore
- let directory = Path.GetDirectoryName project.FullFileName
-
- let getProp (p: Microsoft.Build.BuildEngine.Project) s =
- let v = p.GetEvaluatedProperty s
- if String.IsNullOrWhiteSpace v then None
- else Some v
-
- let outFileOpt =
- match mkAbsoluteOpt directory (getProp project "OutDir") with
- | None -> None
- | Some d -> mkAbsoluteOpt d (getProp project "TargetFileName")
-
- let getItems s =
- let fs = project.GetEvaluatedItemsByName(s)
- [ for f in fs -> mkAbsolute directory f.FinalItemSpec ]
-
- let projectReferences =
- [ for i in project.GetEvaluatedItemsByName("ProjectReference") do
- yield mkAbsolute directory i.FinalItemSpec
- ]
-
- let references =
- [ for i in project.GetEvaluatedItemsByName("ReferencePath") do
- yield i.FinalItemSpec
- for i in project.GetEvaluatedItemsByName("ChildProjectReferences") do
- yield i.FinalItemSpec ]
- // Duplicate slashes sometimes appear in the output here, which prevents
- // them from matching keys used in FSharpProjectOptions.ReferencedProjects
- |> List.map (fun (s: string) -> s.Replace("//","/"))
-
- outFileOpt, directory, getItems, references, projectReferences, getProp project, project.FullFileName
-
-#endif
-
- //----------------------------------------------------------------------------
- // FSharpProjectFileInfo
- //
- []
- type FSharpProjectFileInfo (fsprojFileName:string, ?properties, ?enableLogging) =
- let properties = defaultArg properties []
- let enableLogging = defaultArg enableLogging false
-
- let logOpt =
- if enableLogging then
- let log = new BasicStringLogger()
- do log.Verbosity <- Microsoft.Build.Framework.LoggerVerbosity.Diagnostic
- Some log
- else
- None
-
- let outFileOpt, directory, getItems, references, projectReferences, getProp, fsprojFullPath =
- try
-#if NETCOREAPP2_0
- CrackProjectUsingNewBuildAPI fsprojFileName properties logOpt
- with
-#else
- if runningOnMono then
- CrackProjectUsingOldBuildAPI fsprojFileName properties logOpt
- else
- CrackProjectUsingNewBuildAPI fsprojFileName properties logOpt
- with
- | :? Microsoft.Build.BuildEngine.InvalidProjectFileException as e ->
- raise (Microsoft.Build.Exceptions.InvalidProjectFileException(
- e.ProjectFile,
- e.LineNumber,
- e.ColumnNumber,
- e.EndLineNumber,
- e.EndColumnNumber,
- e.Message,
- e.ErrorSubcategory,
- e.ErrorCode,
- e.HelpKeyword))
-#endif
- | :? ArgumentException as e -> raise (IO.FileNotFoundException(e.Message))
-
- let logOutput = match logOpt with None -> "" | Some l -> l.Log
- let pages = getItems "Page"
- let embeddedResources = getItems "EmbeddedResource"
- let files = getItems "Compile"
- let resources = getItems "Resource"
- let noaction = getItems "None"
- let content = getItems "Content"
-
- let split (s : string option) (cs : char []) =
- match s with
- | None -> [||]
- | Some s ->
- if String.IsNullOrWhiteSpace s then [||]
- else s.Split(cs, StringSplitOptions.RemoveEmptyEntries)
-
- let getbool (s : string option) =
- match s with
- | None -> false
- | Some s ->
- match (Boolean.TryParse s) with
- | (true, result) -> result
- | (false, _) -> false
-
- let fxVer = getProp "TargetFrameworkVersion"
- let optimize = getProp "Optimize" |> getbool
- let assemblyNameOpt = getProp "AssemblyName"
- let tailcalls = getProp "Tailcalls" |> getbool
- let outputPathOpt = getProp "OutputPath"
- let docFileOpt = getProp "DocumentationFile"
- let outputTypeOpt = getProp "OutputType"
- let debugTypeOpt = getProp "DebugType"
- let baseAddressOpt = getProp "BaseAddress"
- let sigFileOpt = getProp "GenerateSignatureFile"
- let keyFileOpt = getProp "KeyFile"
- let pdbFileOpt = getProp "PdbFile"
- let platformOpt = getProp "Platform"
- let targetTypeOpt = getProp "TargetType"
- let versionFileOpt = getProp "VersionFile"
- let targetProfileOpt = getProp "TargetProfile"
- let warnLevelOpt = getProp "Warn"
- let subsystemVersionOpt = getProp "SubsystemVersion"
- let win32ResOpt = getProp "Win32ResourceFile"
- let heOpt = getProp "HighEntropyVA" |> getbool
- let win32ManifestOpt = getProp "Win32ManifestFile"
- let debugSymbols = getProp "DebugSymbols" |> getbool
- let prefer32bit = getProp "Prefer32Bit" |> getbool
- let warnAsError = getProp "TreatWarningsAsErrors" |> getbool
- let defines = split (getProp "DefineConstants") [| ';'; ','; ' ' |]
- let nowarn = split (getProp "NoWarn") [| ';'; ','; ' ' |]
- let warningsAsError = split (getProp "WarningsAsErrors") [| ';'; ','; ' ' |]
- let libPaths = split (getProp "ReferencePath") [| ';'; ',' |]
- let otherFlags = split (getProp "OtherFlags") [| ' ' |]
- let isLib = (outputTypeOpt = Some "Library")
-
- let docFileOpt =
- match docFileOpt with
- | None -> None
- | Some docFile -> Some(mkAbsolute directory docFile)
-
-
- let options =
- [ yield "--simpleresolution"
- yield "--noframework"
- match outFileOpt with
- | None -> ()
- | Some outFile -> yield "--out:" + outFile
- match docFileOpt with
- | None -> ()
- | Some docFile -> yield "--doc:" + docFile
- match baseAddressOpt with
- | None -> ()
- | Some baseAddress -> yield "--baseaddress:" + baseAddress
- match keyFileOpt with
- | None -> ()
- | Some keyFile -> yield "--keyfile:" + keyFile
- match sigFileOpt with
- | None -> ()
- | Some sigFile -> yield "--sig:" + sigFile
- match pdbFileOpt with
- | None -> ()
- | Some pdbFile -> yield "--pdb:" + pdbFile
- match versionFileOpt with
- | None -> ()
- | Some versionFile -> yield "--versionfile:" + versionFile
- match warnLevelOpt with
- | None -> ()
- | Some warnLevel -> yield "--warn:" + warnLevel
- match subsystemVersionOpt with
- | None -> ()
- | Some s -> yield "--subsystemversion:" + s
- if heOpt then yield "--highentropyva+"
- match win32ResOpt with
- | None -> ()
- | Some win32Res -> yield "--win32res:" + win32Res
- match win32ManifestOpt with
- | None -> ()
- | Some win32Manifest -> yield "--win32manifest:" + win32Manifest
- match targetProfileOpt with
- | None -> ()
- | Some targetProfile -> yield "--targetprofile:" + targetProfile
- yield "--fullpaths"
- yield "--flaterrors"
- if warnAsError then yield "--warnaserror"
- yield
- if isLib then "--target:library"
- else "--target:exe"
- for symbol in defines do
- if not (String.IsNullOrWhiteSpace symbol) then yield "--define:" + symbol
- for nw in nowarn do
- if not (String.IsNullOrWhiteSpace nw) then yield "--nowarn:" + nw
- for nw in warningsAsError do
- if not (String.IsNullOrWhiteSpace nw) then yield "--warnaserror:" + nw
- yield if debugSymbols then "--debug+"
- else "--debug-"
- yield if optimize then "--optimize+"
- else "--optimize-"
- yield if tailcalls then "--tailcalls+"
- else "--tailcalls-"
- match debugTypeOpt with
- | None -> ()
- | Some debugType ->
- match debugType.ToUpperInvariant() with
- | "NONE" -> ()
- | "PDBONLY" -> yield "--debug:pdbonly"
- | "FULL" -> yield "--debug:full"
- | _ -> ()
- match platformOpt |> Option.map (fun o -> o.ToUpperInvariant()), prefer32bit,
- targetTypeOpt |> Option.map (fun o -> o.ToUpperInvariant()) with
- | Some "ANYCPU", true, Some "EXE" | Some "ANYCPU", true, Some "WINEXE" -> yield "--platform:anycpu32bitpreferred"
- | Some "ANYCPU", _, _ -> yield "--platform:anycpu"
- | Some "X86", _, _ -> yield "--platform:x86"
- | Some "X64", _, _ -> yield "--platform:x64"
- | Some "ITANIUM", _, _ -> yield "--platform:Itanium"
- | _ -> ()
- match targetTypeOpt |> Option.map (fun o -> o.ToUpperInvariant()) with
- | Some "LIBRARY" -> yield "--target:library"
- | Some "EXE" -> yield "--target:exe"
- | Some "WINEXE" -> yield "--target:winexe"
- | Some "MODULE" -> yield "--target:module"
- | _ -> ()
- yield! otherFlags
- for f in resources do
- yield "--resource:" + f
- for i in libPaths do
- yield "--lib:" + mkAbsolute directory i
- for r in references do
- yield "-r:" + r
- yield! files ]
-
- member x.Options = options
- member x.FrameworkVersion = fxVer
- member x.ProjectReferences = projectReferences
- member x.References = references
- member x.CompileFiles = files
- member x.ResourceFiles = resources
- member x.EmbeddedResourceFiles = embeddedResources
- member x.ContentFiles = content
- member x.OtherFiles = noaction
- member x.PageFiles = pages
- member x.OutputFile = outFileOpt
- member x.Directory = directory
- member x.AssemblyName = assemblyNameOpt
- member x.OutputPath = outputPathOpt
- member x.FullPath = fsprojFullPath
- member x.LogOutput = logOutput
- static member Parse(fsprojFileName:string, ?properties, ?enableLogging) = new FSharpProjectFileInfo(fsprojFileName, ?properties=properties, ?enableLogging=enableLogging)
-
- let getOptions file enableLogging properties =
- let cache = new Dictionary<_,_>()
- let rec getOptions file : Option * ProjectOptions =
- match cache.TryGetValue file with
- | true, option -> option
- | _ ->
- let parsedProject = FSharpProjectFileInfo.Parse(file, properties=properties, enableLogging=enableLogging)
-
- let referencedProjectOptions =
- [| for file in parsedProject.ProjectReferences do
- if Path.GetExtension(file) = ".fsproj" then
- match getOptions file with
- | Some outFile, opts -> yield outFile, opts
- | None, _ -> () |]
-
- // Workaround for Mono 4.2, which doesn't populate the subproject
- // details anymore outside of a solution context. See https://github.com/mono/mono/commit/76c6a08e730393927b6851709cdae1d397cbcc3a#diff-59afd196a55d61d5d1eaaef7bd49d1e5
- // and some explanation from the author at https://github.com/fsharp/FSharp.Compiler.Service/pull/455#issuecomment-154103963
- //
- // In particular we want the output path, which we can get from
- // fully parsing that project itself. We also have to specially parse
- // C# referenced projects, as we don't look at them otherwise.
- let referencedProjectOutputs =
- if runningOnMono then
- [ yield! Array.map (fun (s,_) -> "-r:" + s) referencedProjectOptions
- for file in parsedProject.ProjectReferences do
- let ext = Path.GetExtension(file)
- if ext = ".csproj" || ext = ".vbproj" then
- let parsedProject = FSharpProjectFileInfo.Parse(file, properties=properties, enableLogging=false)
- match parsedProject.OutputFile with
- | None -> ()
- | Some f -> yield "-r:" + f ]
- else
- []
-
- // On some versions of Mono the referenced projects are already
- // correctly included, so we make sure not to introduce duplicates
- |> List.filter (fun r -> not (Set.contains r (set parsedProject.Options)))
-
- let options = { ProjectFile = file
- Options = Array.ofSeq (parsedProject.Options @ referencedProjectOutputs)
- ReferencedProjectOptions = referencedProjectOptions
- LogOutput = parsedProject.LogOutput
- Error = null }
-
- let result = parsedProject.OutputFile, options
- cache.Add(file,result)
- result
-
- snd (getOptions file)
-
-
- let rec pairs l =
- match l with
- | [] | [_] -> []
- | x::y::rest -> (x,y) :: pairs rest
-
- let crackOpen (argv: string[])=
- if argv.Length >= 2 then
- let projectFile = argv.[0]
- let enableLogging = match Boolean.TryParse(argv.[1]) with
- | true, true -> true
- | _ -> false
- try
- let props = pairs (List.ofArray argv.[2..])
- let opts = getOptions argv.[0] enableLogging props
- 0, opts
- with e ->
- 2, { ProjectFile = projectFile;
- Options = [||];
- ReferencedProjectOptions = [||];
- LogOutput = e.ToString() + " StackTrace: " + e.StackTrace
- Error = e.Message + " StackTrace: " + e.StackTrace }
- else
- 1, { ProjectFile = "";
- Options = [||];
- ReferencedProjectOptions = [||];
- LogOutput = "At least two arguments required."
- Error = null }
diff --git a/fcs/FSharp.Compiler.Service.Tests/App.config b/fcs/FSharp.Compiler.Service.Tests/App.config
deleted file mode 100644
index fb0bc6286b1..00000000000
--- a/fcs/FSharp.Compiler.Service.Tests/App.config
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/fcs/FSharp.Compiler.Service.Tests/CSharp_Analysis/CSharp_Analysis.csproj b/fcs/FSharp.Compiler.Service.Tests/CSharp_Analysis/CSharp_Analysis.csproj
deleted file mode 100644
index 534a1435415..00000000000
--- a/fcs/FSharp.Compiler.Service.Tests/CSharp_Analysis/CSharp_Analysis.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- $(FcsTargetNetFxFramework);netstandard2.0
- false
- $(NoWarn);0067;1591
-
-
-
-
-
\ No newline at end of file
diff --git a/fcs/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj b/fcs/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj
deleted file mode 100644
index d6c71b55456..00000000000
--- a/fcs/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj
+++ /dev/null
@@ -1,105 +0,0 @@
-
-
-
- $(FcsTargetNetFxFramework);netcoreapp2.0
- true
- 4.1.19
- $(NoWarn);44;75;
- true
- true
- false
- true
- true
-
-
- $(DefineConstants);NO_PROJECTCRACKER
-
-
-
- FsUnit.fs
-
-
- Common.fs
-
-
- AssemblyReaderShim.fs
-
-
- EditorTests.fs
-
-
- Symbols.fs
-
-
- FileSystemTests.fs
-
-
- ProjectAnalysisTests.fs
-
-
- MultiProjectAnalysisTests.fs
-
-
- PerfTests.fs
-
-
- InteractiveCheckerTests.fs
-
-
- ExprTests.fs
-
-
- CSharpProjectAnalysis.fs
-
-
- ProjectOptionsTests.fs
-
-
- StructureTests.fs
-
-
- TokenizerTests.fs
-
-
- ServiceUntypedParseTests.fs
-
-
- TreeVisitorTests.fs
-
-
- Program.fs
-
-
- {{FSCoreVersion}}
- $(FSCoreVersion)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/fcs/FSharp.Compiler.Service.sln b/fcs/FSharp.Compiler.Service.sln
deleted file mode 100644
index 192f8bd6242..00000000000
--- a/fcs/FSharp.Compiler.Service.sln
+++ /dev/null
@@ -1,153 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26730.16
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "project", "project", "{B6B68AE6-E7A4-4D43-9B34-FFA74BFE192B}"
- ProjectSection(SolutionItems) = preProject
- build.cmd = build.cmd
- build.fsx = build.fsx
- build.sh = build.sh
- nuget\FSharp.Compiler.Service.MSBuild.v12.nuspec = nuget\FSharp.Compiler.Service.MSBuild.v12.nuspec
- nuget\FSharp.Compiler.Service.nuspec = nuget\FSharp.Compiler.Service.nuspec
- nuget\FSharp.Compiler.Service.ProjectCracker.nuspec = nuget\FSharp.Compiler.Service.ProjectCracker.nuspec
- paket.dependencies = paket.dependencies
- README.md = README.md
- RELEASE_NOTES.md = RELEASE_NOTES.md
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docsrc", "docsrc", "{83FEE492-6701-4E59-9184-16B1D30E91F8}"
- ProjectSection(SolutionItems) = preProject
- docsrc\content\caches.fsx = docsrc\content\caches.fsx
- docsrc\content\corelib.fsx = docsrc\content\corelib.fsx
- docsrc\content\devnotes.md = docsrc\content\devnotes.md
- docsrc\content\editor.fsx = docsrc\content\editor.fsx
- docsrc\content\filesystem.fsx = docsrc\content\filesystem.fsx
- docsrc\content\fsharp-readme.md = docsrc\content\fsharp-readme.md
- docsrc\content\index.md = docsrc\content\index.md
- docsrc\content\interactive.fsx = docsrc\content\interactive.fsx
- docsrc\content\project.fsx = docsrc\content\project.fsx
- docsrc\content\queue.fsx = docsrc\content\queue.fsx
- docsrc\content\symbols.fsx = docsrc\content\symbols.fsx
- docsrc\content\tokenizer.fsx = docsrc\content\tokenizer.fsx
- docsrc\content\typedtree.fsx = docsrc\content\typedtree.fsx
- docsrc\content\untypedtree.fsx = docsrc\content\untypedtree.fsx
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{0554567F-1DCB-46A5-9EF2-E1938A3D4F14}"
- ProjectSection(SolutionItems) = preProject
- docsrc\tools\generate.fsx = docsrc\tools\generate.fsx
- docsrc\tools\templates\template.cshtml = docsrc\tools\templates\template.cshtml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{E396742E-B4E5-4584-A9E4-CC1A491F5BC1}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "EditorService", "samples\EditorService\EditorService.fsproj", "{A40507D6-FA48-43D3-B18A-AE3DAACE4020}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "InteractiveService", "samples\InteractiveService\InteractiveService.fsproj", "{067E95E5-E3DC-4CA7-813A-4D1E277D2D52}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Tokenizer", "samples\Tokenizer\Tokenizer.fsproj", "{92793069-816F-4F69-84AC-0966F8275E65}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "UntypedTree", "samples\UntypedTree\UntypedTree.fsproj", "{C816728D-BBEA-472D-9F6C-E8913957A673}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FscExe", "samples\FscExe\FscExe.fsproj", "{C94C257C-3C0A-4858-B5D8-D746498D1F08}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharp_Analysis", "FSharp.Compiler.Service.Tests\CSharp_Analysis\CSharp_Analysis.csproj", "{887630A3-4B1D-40EA-B8B3-2D842E9C40DB}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FsiExe", "samples\FsiExe\FsiExe.fsproj", "{F9540CA8-1CE0-4546-A23A-A461E416E95B}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.Service.ProjectCrackerTool", "FSharp.Compiler.Service.ProjectCrackerTool\FSharp.Compiler.Service.ProjectCrackerTool.fsproj", "{B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.Service.ProjectCracker", "FSharp.Compiler.Service.ProjectCracker\FSharp.Compiler.Service.ProjectCracker.fsproj", "{893C3CD9-5AF8-4027-A667-21E62FC2C703}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{098D1C35-D0FB-4720-83DD-8002293EA237}"
- ProjectSection(SolutionItems) = preProject
- .gitattributes = .gitattributes
- .gitignore = .gitignore
- .travis.yml = .travis.yml
- appveyor.yml = appveyor.yml
- NuGet.Config = NuGet.Config
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "package", "package", "{9020E136-794A-473F-9B1B-9623C97B7161}"
- ProjectSection(SolutionItems) = preProject
- nuget\FSharp.Compiler.Service.template = nuget\FSharp.Compiler.Service.template
- nuget\projectcracker.template = nuget\projectcracker.template
- EndProjectSection
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.Service.MSBuild.v12", "FSharp.Compiler.Service.MSBuild.v12\FSharp.Compiler.Service.MSBuild.v12.fsproj", "{8157B50E-397D-4232-A4E0-1977AFC7076D}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.Service", "FSharp.Compiler.Service\FSharp.Compiler.Service.fsproj", "{2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Compiler.Service.Tests", "FSharp.Compiler.Service.Tests\FSharp.Compiler.Service.Tests.fsproj", "{EE85AAB7-CDA0-4C4E-BDA0-A64DDDD13E3F}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {A40507D6-FA48-43D3-B18A-AE3DAACE4020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A40507D6-FA48-43D3-B18A-AE3DAACE4020}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A40507D6-FA48-43D3-B18A-AE3DAACE4020}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A40507D6-FA48-43D3-B18A-AE3DAACE4020}.Release|Any CPU.Build.0 = Release|Any CPU
- {067E95E5-E3DC-4CA7-813A-4D1E277D2D52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {067E95E5-E3DC-4CA7-813A-4D1E277D2D52}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {067E95E5-E3DC-4CA7-813A-4D1E277D2D52}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {067E95E5-E3DC-4CA7-813A-4D1E277D2D52}.Release|Any CPU.Build.0 = Release|Any CPU
- {92793069-816F-4F69-84AC-0966F8275E65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {92793069-816F-4F69-84AC-0966F8275E65}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {92793069-816F-4F69-84AC-0966F8275E65}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {92793069-816F-4F69-84AC-0966F8275E65}.Release|Any CPU.Build.0 = Release|Any CPU
- {C816728D-BBEA-472D-9F6C-E8913957A673}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C816728D-BBEA-472D-9F6C-E8913957A673}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C816728D-BBEA-472D-9F6C-E8913957A673}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C816728D-BBEA-472D-9F6C-E8913957A673}.Release|Any CPU.Build.0 = Release|Any CPU
- {C94C257C-3C0A-4858-B5D8-D746498D1F08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C94C257C-3C0A-4858-B5D8-D746498D1F08}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C94C257C-3C0A-4858-B5D8-D746498D1F08}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C94C257C-3C0A-4858-B5D8-D746498D1F08}.Release|Any CPU.Build.0 = Release|Any CPU
- {887630A3-4B1D-40EA-B8B3-2D842E9C40DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {887630A3-4B1D-40EA-B8B3-2D842E9C40DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {887630A3-4B1D-40EA-B8B3-2D842E9C40DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {887630A3-4B1D-40EA-B8B3-2D842E9C40DB}.Release|Any CPU.Build.0 = Release|Any CPU
- {F9540CA8-1CE0-4546-A23A-A461E416E95B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F9540CA8-1CE0-4546-A23A-A461E416E95B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F9540CA8-1CE0-4546-A23A-A461E416E95B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F9540CA8-1CE0-4546-A23A-A461E416E95B}.Release|Any CPU.Build.0 = Release|Any CPU
- {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B1BDD96D-47E1-4E65-8107-FBAE23A06DB4}.Release|Any CPU.Build.0 = Release|Any CPU
- {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {893C3CD9-5AF8-4027-A667-21E62FC2C703}.Release|Any CPU.Build.0 = Release|Any CPU
- {8157B50E-397D-4232-A4E0-1977AFC7076D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8157B50E-397D-4232-A4E0-1977AFC7076D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8157B50E-397D-4232-A4E0-1977AFC7076D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8157B50E-397D-4232-A4E0-1977AFC7076D}.Release|Any CPU.Build.0 = Release|Any CPU
- {2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2E4D67B4-522D-4CF7-97E4-BA940F0B18F3}.Release|Any CPU.Build.0 = Release|Any CPU
- {EE85AAB7-CDA0-4C4E-BDA0-A64DDDD13E3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {EE85AAB7-CDA0-4C4E-BDA0-A64DDDD13E3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {EE85AAB7-CDA0-4C4E-BDA0-A64DDDD13E3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EE85AAB7-CDA0-4C4E-BDA0-A64DDDD13E3F}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {0554567F-1DCB-46A5-9EF2-E1938A3D4F14} = {83FEE492-6701-4E59-9184-16B1D30E91F8}
- {A40507D6-FA48-43D3-B18A-AE3DAACE4020} = {E396742E-B4E5-4584-A9E4-CC1A491F5BC1}
- {067E95E5-E3DC-4CA7-813A-4D1E277D2D52} = {E396742E-B4E5-4584-A9E4-CC1A491F5BC1}
- {92793069-816F-4F69-84AC-0966F8275E65} = {E396742E-B4E5-4584-A9E4-CC1A491F5BC1}
- {C816728D-BBEA-472D-9F6C-E8913957A673} = {E396742E-B4E5-4584-A9E4-CC1A491F5BC1}
- {C94C257C-3C0A-4858-B5D8-D746498D1F08} = {E396742E-B4E5-4584-A9E4-CC1A491F5BC1}
- {F9540CA8-1CE0-4546-A23A-A461E416E95B} = {E396742E-B4E5-4584-A9E4-CC1A491F5BC1}
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {9E9BAC7B-3834-497C-B7AC-6B7988778D1A}
- EndGlobalSection
-EndGlobal
diff --git a/fcs/FSharp.Compiler.Service/.gitignore b/fcs/FSharp.Compiler.Service/.gitignore
deleted file mode 100644
index 722f2e9b839..00000000000
--- a/fcs/FSharp.Compiler.Service/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-net4*/
-netstandard*/
diff --git a/fcs/FSharp.Compiler.Service/AssemblyInfo.fs b/fcs/FSharp.Compiler.Service/AssemblyInfo.fs
deleted file mode 100644
index 90521fefd5a..00000000000
--- a/fcs/FSharp.Compiler.Service/AssemblyInfo.fs
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-
-namespace Microsoft.FSharp
-open System.Reflection
-open System.Runtime.InteropServices
-
-[]
-[]
-[]
-[]
-[]
-[]
-
-#if NO_STRONG_NAMES
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-
-// Note: internals visible to unit test DLLs in Retail (and all) builds.
-[]
-[]
-[]
-[]
-[]
-#endif
-
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-
-// Until dotnet sdk can version assemblies, use this
-#if BUILD_FROM_SOURCE
-[]
-[]
-[]
-#endif
-
-do()
\ No newline at end of file
diff --git a/fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj b/fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj
index 5e0d2250f7e..11cefec408b 100644
--- a/fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj
+++ b/fcs/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj
@@ -1,6 +1,8 @@
-
+
+
+
$(FcsTargetNetFxFramework);netstandard2.0
true
@@ -17,34 +19,45 @@
true
true
true
+ embedded
+ 16.6
+ $(MicrosoftBuildOverallPackagesVersion)
+ $(MicrosoftBuildOverallPackagesVersion)
+ $(MicrosoftBuildOverallPackagesVersion)
+ $(MicrosoftBuildOverallPackagesVersion)
The F# compiler as library. For editors, for tools, for scripting. For you.
The F# compiler services package contains a custom build of the F# compiler that exposes additional functionality for implementing F# language bindings, additional tools based on the compiler or refactoring tools. The package also includes F# interactive service that can be used for embedding F# scripting into your applications.
false
Microsoft Corporation; F# community contributors
- https://github.com/fsharp/FSharp.Compiler.Service/blob/master/LICENSE
+ MIT
https://github.com/fsharp/FSharp.Compiler.Service
- https://raw.github.com/fsharp/FSharp.Compiler.Service/master/misc/logo.png
+ logo.png
F#, fsharp, interactive, compiler, editor
+ true
+ true
$(DefineConstants);FX_NO_PDB_READER
$(DefineConstants);FX_NO_PDB_WRITER
$(DefineConstants);FX_NO_SYMBOLSTORE
- $(DefineConstants);FX_NO_LINKEDRESOURCES
$(DefineConstants);FX_NO_APP_DOMAINS
$(DefineConstants);FX_NO_WIN_REGISTRY
$(DefineConstants);FX_NO_SYSTEM_CONFIGURATION
$(DefineConstants);FX_RESHAPED_REFEMIT
+
AssemblyInfo/AssemblyInfo.fs
FSComp.txt
+
+ DependencyManager.txt
+
FSIstrings.txt
@@ -230,6 +243,12 @@
+
+ AbsIL/ilnativeres.fsi
+
+
+ AbsIL/ilnativeres.fs
+
AbsIL/ilsupp.fsi
@@ -269,9 +288,6 @@
AbsIL/ilreflect.fs
-
- ReferenceResolution/reshapedmsbuild.fs
-
ReferenceResolution/ReferenceResolver.fs
@@ -323,8 +339,17 @@
ParserAndUntypedAST/layout.fs
-
- ParserAndUntypedAST/ast.fs
+
+ ParserAndUntypedAST/XmlDoc.fs
+
+
+ ParserAndUntypedAST/SyntaxTree.fs
+
+
+ ParserAndUntypedAST/SyntaxTreeOps.fs
+
+
+ ParserAndUntypedAST/ParseHelpers.fs
ParserAndUntypedAST/pppars.fs
@@ -348,43 +373,46 @@
ParserAndUntypedAST/LexFilter.fs
- TypedAST/tainted.fsi
+ TypedTree/tainted.fsi
- TypedAST/tainted.fs
+ TypedTree/tainted.fs
- TypedAST/ExtensionTyping.fsi
+ TypedTree/ExtensionTyping.fsi
- TypedAST/ExtensionTyping.fs
+ TypedTree/ExtensionTyping.fs
- TypedAST/QuotationPickler.fsi
+ TypedTree/QuotationPickler.fsi
- TypedAST/QuotationPickler.fs
+ TypedTree/QuotationPickler.fs
- TypedAST/CompilerGlobalState.fs
+ TypedTree/CompilerGlobalState.fs
+
+
+ TypedTree/TypedTree.fs
-
- TypedAST/tast.fs
+
+ TypedTree/TypedTreeBasics.fs
- TypedAST/TcGlobals.fs
+ TypedTree/TcGlobals.fs
-
- TypedAST/TastOps.fsi
+
+ TypedTree/TypedTreeOps.fsi
-
- TypedAST/TastOps.fs
+
+ TypedTree/TypedTreeOps.fs
-
- TypedAST/TastPickle.fsi
+
+ TypedTree/TypedTreePickle.fsi
-
- TypedAST/TastPickle.fs
+
+ TypedTree/TypedTreePickle.fs
Logic/import.fsi
@@ -401,6 +429,9 @@
Logic/AttributeChecking.fs
+
+ Logic/TypeRelations.fs
+
Logic/InfoReader.fs
@@ -419,9 +450,6 @@
Logic/NameResolution.fs
-
- Logic/TypeRelations.fs
-
Logic/SignatureConformance.fs
@@ -512,6 +540,24 @@
Driver\DotNetFrameworkDependencies.fs
+
+ Driver\AssemblyResolveHandler.fsi
+
+
+ Driver\AssemblyResolveHandler.fs
+
+
+ Driver\NativeDllResolveHandler.fsi
+
+
+ Driver\NativeDllResolveHandler.fs
+
+
+ Driver/DependencyProvider.fsi
+
+
+ Driver/DependencyProvider.fs
+
Driver/CompileOps.fsi
@@ -560,6 +606,18 @@
Service/Reactor.fs
+
+ Service/SemanticClassification.fsi
+
+
+ Service/SemanticClassification.fs
+
+
+ Service/ItemKey.fsi
+
+
+ Service/ItemKey.fs
+
Service/IncrementalBuild.fsi
@@ -620,7 +678,7 @@
Service/ExternalSymbol.fs
-
+
Service/QuickParse.fsi
@@ -667,14 +725,17 @@
+
+
+
+
+
+
-
-
-
@@ -685,4 +746,4 @@
-
\ No newline at end of file
+
diff --git a/fcs/README.md b/fcs/README.md
deleted file mode 100644
index e176ffb1424..00000000000
--- a/fcs/README.md
+++ /dev/null
@@ -1,103 +0,0 @@
-# The FSharp.Compiler.Service components and NuGet package
-
-This directory contains the build, packaging, test and documentation-generation logic for the NuGet package ``FSharp.Compiler.Service``. The source for this NuGet
-package is in ``..\src``.
-
-Basically we are packaging up the compiler as a DLL and publishing it as a NuGet package.
-
-## FSharp.Compiler.Service v. FSharp.Compiler.Private
-
-There are subtle differences between FSharp.Compiler.Service and FSharp.Compiler.Private (shipped with the Visual F# Tools)
-
-- FCS has a public API
-
-- FCS is built against **.NET 4.6.1** and **FSharp.Core NuGet 4.6.2** to give broader reach
-
-- FCS has a NuGet package
-
-- FCS has a .NET Standard 2.0 version in the nuget package
-
-- FCS testing also tests the "Project Cracker" (see below)
-
-- FCS doesn't add the System.ValueTuple.dll reference by default, see ``#if COMPILER_SERVICE_AS_DLL`` in compiler codebase
-
-## Version Numbers
-
-FCS uses its own version number sequence for assemblies and packages, approximately following SemVer rules.
-To update the version number a global replace through fcs\... is currently needed, e.g.
-
- Directory.Build.props
- nuget/FSharp.Compiler.Service.nuspec
- nuget/FSharp.Compiler.Service.MSBuild.v12.nuspec
- nuget/FSharp.Compiler.Service.ProjectCracker.nuspec
- RELEASE_NOTES.md
-
-## Building, Testing, Packaging, Releases
-
-To build the package use any of:
-
- fcs\build Build.NetFx
- fcs\build Test.NetFx
- fcs\build NuGet.NetFx
-
- fcs\build Build.NetStd
- fcs\build Test.NetStd
- fcs\build NuGet.NetStd
-
- fcs\build Build
- fcs\build Test
- fcs\build NuGet
- fcs\build Release
-
-which does things like:
-
- cd fcs
- .paket\paket.bootstrapper.exe
- .paket\paket.exe restore
- dotnet restore tools.proj
- packages\FAKE\tools\FAKE.exe build.fsx WhateverTarget
-
-### Manual push of packages
-
-You can push the packages if you have permissions, either automatically using ``build Release`` or manually
-
- set APIKEY=...
- ..\fsharp\.nuget\nuget.exe push %HOMEDRIVE%%HOMEPATH%\Downloads\FSharp.Compiler.Service.22.0.3.nupkg %APIKEY% -Source https://nuget.org
- ..\fsharp\.nuget\nuget.exe push %HOMEDRIVE%%HOMEPATH%\Downloads\FSharp.Compiler.Service.MSBuild.v12.22.0.3.nupkg %APIKEY% -Source https://nuget.org
- ..\fsharp\.nuget\nuget.exe push %HOMEDRIVE%%HOMEPATH%\Downloads\FSharp.Compiler.Service.ProjectCracker.22.0.3.nupkg %APIKEY% -Source https://nuget.org
-
-### Use of Paket and FAKE
-
-Paket is only used to get FAKE and FSharp.Formatting tools. Eventually we will likely remove this once we update the project files to .NET SDK 2.0.
-
-FAKE is only used to run build.fsx. Eventually we will likely remove this once we update the project files to .NET SDK 2.0.
-
-### Testing
-
-Testing reuses the test files from ..\tests\service which were are also FCS tests.
-
-### Documentation Generation
-
- fcs\build GenerateDocs
-
-Output is in ``docs``. In the ``FSharp.Compiler.Service`` repo this is checked in and hosted as .
-
-## The two other NuGet packages
-
-It also contains both the source, build, packaging and test logic for
-
-- ``FSharp.Compiler.Service.MSBuild.v12`` adds legacy MSBuild v12 support to an instance of FSharp.Compiler.Service, if exact compatibility for scripting references such as ``#r "Foo, Version=1.3.4"`` is required.
-
-- ``FSharp.Compiler.Service.ProjectCracker`` is part of ``FsAutoComplete`` and Ionide and is used to crack old-style project formats using MSBuild. It used to be part of the FCS API.
-
-Both of these components are gradually becoming obsolete
-
-## Engineering road map
-
-FSharp.Compiler.Service is a somewhat awkward component. There are some things we can do to simplify things:
-
-1. Remove the use of Paket and FAKE
-1. Move all projects under fcs\... to new .NET SDK project file format
-1. Drop the use of ``dotnet mergenupkg`` since we should be able to use cross targeting
-1. Make FCS a DLL similar ot the rest of the build and make this an official component from Microsoft (signed etc.)
-1. Replace FSharp.Compiler.Private by FSharp.Compiler.Service
diff --git a/fcs/RELEASE_NOTES.md b/fcs/RELEASE_NOTES.md
deleted file mode 100644
index e1cb2f3ecb6..00000000000
--- a/fcs/RELEASE_NOTES.md
+++ /dev/null
@@ -1,629 +0,0 @@
-#### 23.0.1
- * FSharp.Compiler.Service nuget now uses net461, netstandard2.0 and FSharp.Core 4.6.2
-
-#### 22.0.3
- * [Add entity.DeclaringEntity](https://github.com/Microsoft/visualfsharp/pull/4633), [FCS feature request](https://github.com/fsharp/FSharp.Compiler.Service/issues/830)
-
-#### 22.0.2
- * Use correct version number in DLLs (needed until https://github.com/Microsoft/visualfsharp/issues/3113 is fixed)
-
-#### 22.0.1
- * Integrate visualfsharp master
- * Includes recent memory usage reduction work for ByteFile and ILAttributes
-
-#### 21.0.1
- * Use new .NET SDK project files
- * FSharp.Compiler.Service nuget now uses net461 and netstandard2.0
- * FSharp.Compiler.Service netstandard2.0 now supports type providers
-
-#### 19.0.1
- * Rename ``LogicalEnclosingEntity`` to ``ApparentEnclosingEntity`` for consistency int he F# codebase terminology.
- * Rename ``EnclosingEntity`` to ``DeclaringEntity``. In the case of extension properties, ``EnclosingEntity`` was incorrectly returning the logical enclosing entity (i.e. the type the property appears to extend), and in this case ``ApparentEnclosingEntity`` should be used instead.
-
-#### 18.0.1
- * Integrate visualfsharp master
-
-#### 17.0.2
- * Integrate visualfsharp master
-
-#### 16.0.3
- * [File name deduplication not working with ParseAndCheckFileInProject](https://github.com/fsharp/FSharp.Compiler.Service/issues/819)
-
-#### 16.0.2
- * [ProjectCracker returns *.fsi files in FSharpProjectOptions.SourceFiles array](https://github.com/fsharp/FSharp.Compiler.Service/pull/812)
-
- * [Fix line endings in the Nuget packages descriptions](https://github.com/fsharp/FSharp.Compiler.Service/pull/811)
-
-#### 16.0.1
- * FSharpChecker provides non-reactor ParseFile instead of ParseFileInProject
- * Add FSharpParsingOptions, GetParsingOptionsFromProjectOptions, GetParsingOptionsFromCommandLine
-
-#### 15.0.1
- * Integrate latest changes from visualfsharp
- * Add implementation file contents to CheckFileResults
- * Fix non-public API in .NET Standard 1.6 version
-
-#### 14.0.1
- * Integrate latest changes from visualfsharp
- * Trial release for new build in fcs\...
-
-#### 13.0.1
- * Move docs --> docssrc
-
-#### 13.0.0
- * Move FSharp.Compiler.Service.MSBuild.v12.dll to a separate nuget package
-
-#### 12.0.8
- * Set bit on output executables correctly
-
-#### 12.0.7
- * Integrate visualfsharp master
-
-#### 12.0.6
- * [758: Fix project cracker when invalid path given](https://github.com/fsharp/FSharp.Compiler.Service/pull/758)
-
-#### 12.0.5
- * Remove dependency on System.ValueTuple
-
-#### 12.0.3
- * [De-duplicate module names again](https://github.com/fsharp/FSharp.Compiler.Service/pull/749)
-
-#### 12.0.2
- * De-duplicate module names
-
-#### 12.0.1
- * [Integrate visualfsharp and fsharp](https://github.com/fsharp/fsharp/pull/696)
-
-#### 11.0.10
- * [Fix F# Interactive on Mono 4.0.9+](https://github.com/fsharp/fsharp/pull/696)
-
-#### 11.0.9
- * [Make incremental builder counter atomic](https://github.com/fsharp/FSharp.Compiler.Service/pull/724)
- * [Add IsValCompiledAsMethod to FSharpMemberOrFunctionOrValue](https://github.com/fsharp/FSharp.Compiler.Service/pull/727)
- * [Check before ILTypeInfo.FromType](https://github.com/fsharp/FSharp.Compiler.Service/issues/734)
- * [Transition over to dotnet cli Fsproj](https://github.com/fsharp/FSharp.Compiler.Service/issues/700)
-
-#### 11.0.8
- * Depend on FSharp.Core package
-
-#### 11.0.6
- * Fix [stack overflow exception](https://github.com/fsharp/FSharp.Compiler.Service/issues/672)
-
-#### 11.0.4
- * Fix [out of range exception](https://github.com/fsharp/FSharp.Compiler.Service/issues/709)
-
-#### 11.0.2
- * Integrate fsharp\fsharp and Microsoft\visualfsharp to 262deb017cfcd0f0d4138779ff42ede7dbf44c46
-
-#### 11.0.1
- * Integrate fsharp\fsharp and Microsoft\visualfsharp to d0cc249b951374257d5a806939e42714d8a2f4c6
-
-#### 10.0.3
- * [Expose assumeDotNetFramework in FSharpChecker.GetProjectOptionsFromScript](https://github.com/fsharp/FSharp.Compiler.Service/pull/699)
- * [SemanticClassificationType should not be internal](https://github.com/fsharp/FSharp.Compiler.Service/pull/696)
-
-#### 10.0.1
- * [Adds FormatValue to FsiEvaluationSession, using the fsi object values for formatting](https://github.com/fsharp/FSharp.Compiler.Service/pull/686)
-
-#### 10.0.0
- * Integrate fsharp\fsharp and Microsoft\visualfsharp to c3e55bf0b10bf08790235dc585b8cdc75f71618e
- * Integrate fsharp\fsharp and Microsoft\visualfsharp to 11c0a085c96a91102cc881145ce281271ac159fe
- * Some API changes for structured text provision for tagged structured text
-
-#### 9.0.0
- * Update names of union fields in AST API
- * Fix load closure for ParseAndCheckInteraction
- * [Fix #631 compiler dependency on MSBuild](https://github.com/fsharp/FSharp.Compiler.Service/pull/657)
- * Fixed netcore codegen on Linux
- * Explicit error when cracker exe is missing
-
-#### 8.0.0
- * Integrate fsharp\fsharp and Microsoft\visualfsharp to c494a9cab525dbd89585f7b733ea5310471a8001
- * Then integrate to 2002675f8aba5b3576a924a2e1e47b18e4e9a83d
- * [Add module values to navigable items](https://github.com/fsharp/FSharp.Compiler.Service/pull/650)
- * Optionally remove dependency on MSBuild reference resolution https://github.com/fsharp/FSharp.Compiler.Service/pull/649
- * [Compiler api harmonise](https://github.com/fsharp/FSharp.Compiler.Service/pull/639)
- * Various bits of work on .NET Core version (buildable from source but not in nuget package)
-
-#### 7.0.0
- * Integrate fsharp\fsharp and Microsoft\visualfsharp to 835b79c041f9032fceeceb39f680e0662cba92ec
-
-#### 6.0.2
- * [Fix #568: recognize provided expressions](https://github.com/fsharp/FSharp.Compiler.Service/pull/568)
-
-#### 6.0.1
- * [Fix ProjectFileNames order when getting project options from script](https://github.com/fsharp/FSharp.Compiler.Service/pull/594)
-
-#### 6.0.0
- * Switch to new major version on assumption integrated F# compiler changes induce API change
-
-#### 5.0.2
- * Integrate Microsoft\visualfsharp to 688c26bdbbfc766326fc45e4d918f87fcba1e7ba. F# 4.1 work
-
-#### 5.0.1
-* [Fixed dependencies in nuget package](https://github.com/fsharp/FSharp.Compiler.Service/pull/608)
-
-#### 5.0.0
-* Fixed empty symbol declared pdb #564 from kekyo/fix-empty-pdb
-* .NET Core ProjectCracker - updated version and dependencies
-* Properly embed 'FSIstrings' resource, fixes #591
-* make build.sh work on windows (git bash).
-* Added default script references for .NET Core
-* Store useMonoResolution flag
-* Updated MSBuild version
-* Assume FSharp.Core 4.4.0.0
-
-#### 4.0.1
-* Integrate Microsoft\visualfsharp and fsharp\fsharp to master (including portable PDB)
-* Remove .NET Framework 4.0 support (now needs .NET Framework 4.5)
-
-#### 4.0.0
-* Integrate Microsoft\visualfsharp and fsharp\fsharp to master
-
-#### 3.0.0.0
-* #538 - BackgroundCompiler takes a very long time on a big solution with a very connected project dependency graph
-* #544 - Losing operator call when one of operands is application of a partially applied function
-* #534 - Function valued property erasing calls
-* #495 - Detupling missing when calling a module function value
-* #543 - Tuple not being destructured in AST
-* #541 - Results of multiple calls to active pattern are always bound to variable with same name
-* #539 - BasicPatterns.NewDelegate shows same value for different arguments
-
-#### 2.0.0.6
-* #530 - Adjust ProjectCracker NuGet for VS/NuGet
-
-#### 2.0.0.5
-* #527 - Provide API that includes printf specifier arities along with ranges
-
-#### 2.0.0.4
-* #519 - Change nuget layout for ProjectCracker package
-* #523 - Project cracking: spaces in file paths
-
-#### 2.0.0.3
-* #508 - Integrate visualfsharp/master removal of Silverlight #if
-* #513 - Make CrackerTool `internal` to prevent accidental usage
-* #515 - Add simple Visual Studio version detection for project cracker
-
-#### 2.0.0.2
-* Integrate visualfsharp/master and fsharp/master --> master
-* Expose QualifiedName and FileName of FSharpImplementationFileContents
-* Add FSharpErrorInfo.ErrorNumber
-
-#### 2.0.0.1-beta
-* Fix 452 - FSharpField.IsMutable = true for BCL enum cases
-* Fix 414 - Add IsInstanceMemberInCompiledCode
-
-#### 2.0.0.0-beta
-* Feature #470, #478, #479 - Move ProjectCracker to separate nuget package and DLL, used ProjectCrackerTool.exe to run
-* Feature #463 - Expose slot signatures of members in object expressions
-* Feature #469, #475 - Add EvalExpressionNonThrowing, EvalInteractionNonThrowing, EvalScriptNonThrowing
-* Fix #456 - FCS makes calls to kernel32.dll when running on OSX
-* Fix #473 - stack overflow in resolution logic
-* Fix #460 - Failure getting expression for a provided method call
-
-#### 1.4.2.3 -
-* Fix bug in loop optimization, apply https://github.com/Microsoft/visualfsharp/pull/756/
-
-#### 1.4.2.2 -
-* #488 - Performance problems with project references
-
-#### 1.4.2.1 -
-* #450 - Correct generation of ReferencedProjects
-
-#### 1.4.2.0 -
-* Fix bug in double lookup of cache, see https://github.com/fsharp/FSharp.Compiler.Service/pull/447
-
-#### 1.4.1 -
-* Add pause before backgrounnd work starts. The FCS request queue must be empty for 1 second before work will start
-* Write trace information about the reactor queue to the event log
-* Rewrite reactor to consistently prioritize queued work
-* Implement cancellation for queued work if it is cancelled prior to being executed
-* Adjust caching to check cache correctly if there is a gap before the request is executed
-
-#### 1.4.0.9 -
-* FSharpType.Format fix
-* Disable maximum-memory trigger by default until use case ironed out
-
-#### 1.4.0.8 -
-* FSharpType.Format now prettifies type variables. If necessary, FSharpType.Prettify can also be called
-* Add maximum-memory trigger to downsize FCS caches. Defaults to 1.7GB of allocaed memory in the system
- process for a 32-bit process, and 2x this for a 64-bit process
-
-#### 1.4.0.7 -
-* fix 427 - Make event information available for properties which represent first-class uses of F#-declared events
-* fix 410 - Symbols for C# fields (and especially enum fields)
-* Expose implemented abstract slots
-* Fix problem with obscure filenames caught by Microsoft\visualfsharp tests
-* Integrate with visualfsharp master
-
-#### 1.4.0.6 -
-* fix 423 - Symbols for non-standard C# events
-* fix 235 - XmlDocSigs for references assemblies
-* fix 177 - GetAllUsesOfAllSymbolsInFile returns nothing for C# nested enum
-* make Internal.Utilities.Text.Lexing.Position a struct
-* Exposing assembly attributes on FSharpAssemblySignature
-* clean up IncrementalFSharpBuild.frameworkTcImportsCache
-
-#### 1.4.0.5 -
-* add more entries to FSharpTokenTag
-
-#### 1.4.0.4 -
-* add more entries to FSharpTokenTag
-* add PrettyNaming.QuoteIdentifierIfNeeded and PrettyNaming.KeywordNames
-
-#### 1.4.0.3 -
-* integrate Microsoft/visualfsharp OOB cleanup via fsharp/fsharp
-* Make Parser and Lexer private
-
-#### 1.4.0.2 -
-* #387 - types and arrays in F# attribute contructor arguments
-
-#### 1.4.0.1 - F# 4.0 support
-* Use FSharp.Core 4.4.0.0 by default for scripting scenarios if not FSharp.Core referenced by host process
-
-#### 1.4.0.0-beta - F# 4.0 support
-* Integrate F# 4.0 support into FSharp.Compiler.Service
-
-#### 1.3.1.0 -
-* simplified source indexing with new SourceLink
-* Add noframework option in AST compiler methods
-
-#### 0.0.90 -
-* Add fix for #343 Use ResolveReferences task
-* Expose BinFolderOfDefaultFSharpCompiler to editors
-* Fix the registry checking on mono to avoid unnecessary exceptions being thrown
-
-#### 0.0.89 -
-* Fix output location of referenced projects
-
-#### 0.0.88 -
-* Added Fix to allow implicit PCL references to be retrieved
-
-#### 0.0.87 -
-* Don't report fake symbols in indexing #325
-* Add EnclosingEntity for an active pattern group #327
-* Add ImmediateSubExpressions #284
-* integrate fsharp/fsharp master into master
-
-#### 0.0.85 -
-* Fix for FSharpSymbolUse for single case union type #301
-* Added supprt for ReturnParameter in nested functions
-
-#### 0.0.84 -
-* Added curried parameter groups for nested functions
-
-#### 0.0.83 -
-* Add Overloads to the symbols signature so it is publicly visible
-* Update OnEvaluation event to have FSharpSymbolUse information available
-
-#### 0.0.82 -
-* Better support for Metadata of C# (and other) Assemblies.
-* Expose the DefaultFileSystem as a type instead of anonymous
-
-#### 0.0.81 -
-* Update GetDeclarationListSymbols to expose FSharpSymbolUse
-* Improve reporting of format specifiers
-
-#### 0.0.80 -
-* Update to latest F# 3.1.3 (inclunding updated FsLex/FsYacc used in build of FCS)
-* Report printf specifiers from Service API
-* Improve Accessibility of non-F# symbols
-
-#### 0.0.79 -
-* Do not use memory mapped files when cracking a DLL to get an assembly reference
-* Fix for multilanguage projects in project cracker
-
-#### 0.0.78 -
-* Reduce background checker memory usage
-* add docs on FSharp.Core
-* docs on caches and queues
-
-#### 0.0.77 -
-* Update to github.com/fsharp/fsharp 05f426cee85609f2fe51b71473b07d7928bb01c8
-
-#### 0.0.76 -
-* Fix #249 - Fix TryFullName when used on namespaces of provided erased type definitions
-* Add OnEvaluation event to FCS to allow detailed information to be exposed
-
-#### 0.0.75 -
-* Do not use shared cursor for IL binaries (https://github.com/fsprojects/VisualFSharpPowerTools/issues/822)
-
-#### 0.0.74 -
-* Extension members are returned as members of current modules
-* Fix exceptions while cross-reference a type provider project
-
-#### 0.0.73 -
-* Add AssemblyContents and FSharpExpr to allow access to resolved, checked expression trees
-* Populate ReferencedProjects using ProjectFileInfo
-* Fix finding symbols declared in signature files
-* Add logging to project cracking facility
-
-#### 0.0.72 -
-* Allow project parser to be used on project file with relative paths
-* Expose attributes for non-F# symbols
-
-#### 0.0.71 -
-* More renamings in SourceCodeServices API for more consistent use of 'FSharp' prefix
-
-#### 0.0.70 -
-* Make FSharpProjectFileParser public
-* Fixes to project parser for Mono (.NET 4.0 component)
-* Renamings in SourceCodeServices API for more consistent use of 'FSharp' prefix
-
-#### 0.0.67 -
-* Fixes to project parser for Mono
-
-#### 0.0.66 -
-* Fixes to project parser for Mono
-* Use MSBuild v12.0 for reference resolution on .NET 4.5+
-
-#### 0.0.65 -
-* Fixes to project parser
-
-#### 0.0.64 -
-* Add project parser, particularly GetProjectOptionsFromProjectFile
-
-#### 0.0.63 -
-* #221 - Normalize return types of .NET events
-
-#### 0.0.62 -
-* Integrate to latest https://github.com/fsharp/fsharp (#80f9221f811217bd890b3a670d717ebc510aeeaf)
-
-#### 0.0.61 -
-* #216 - Return associated getters/setters from F# properties
-* #214 - Added missing XmlDocSig for FSharpMemberOrFunctionOrValue's Events, Methods and Properties
-* #213 - Retrieve information for all active pattern cases
-* #188 - Fix leak in file handles when using multiple instances of FsiEvaluationSession, and add optionally collectible assemblies
-
-#### 0.0.60 -
-* #207 - Add IsLiteral/LiteralValue to FSharpField
-* #205 - Add IsOptionalArg and related properties to FSharpParameter
-* #210 - Check default/override members via 'IsOverrideOrExplicitMember'
-* #209 - Add TryFullName to FSharpEntity
-
-#### 0.0.59 -
-* Fix for #184 - Fix EvalScript by using verbatim string for #Load
-* Fix for #183 - The line no. reporting is still using 0-based indexes in errors. This is confusing.
-
-#### 0.0.58 -
-* Fix for #156 - The FSharp.Core should be retrieved from the hosting environment
-
-#### 0.0.57 -
-* Second fix for #160 - Nuget package now contains .NET 4.0 and 4.5
-
-#### 0.0.56 -
-* Fix for #160 - Nuget package contains .NET 4.0 and 4.5
-
-#### 0.0.55 -
-* Integrate changes for F# 3.1.x, Fix #166
-
-#### 0.0.54 -
-* Fix for #159 - Unsubscribe from TP Invalidate events when disposing builders
-
-#### 0.0.53 -
-* Add queue length to InteractiveChecker
-
-#### 0.0.52 -
-* Fix caches keeping hold of stale entries
-
-#### 0.0.51 -
-* Add IsAccessible to FSharpSymbol, and ProjectContext.AccessibilityRights to give the context of an access
-
-#### 0.0.50 -
-* Fix #79 - FindUsesOfSymbol returns None at definition of properties with explicit getters and setters
-
-#### 0.0.49 -
-* Fix #138 - Fix symbol equality for provided type members
-* Fix #150 - Return IsGetterMethod = true for declarations of F# properties (no separate 'property' symbol is yet returned, see #79)
-* Fix #132 - Add IsStaticInstantiation on FSharpEntity to allow clients to detect fake symbols arising from application of static parameters
-* Fix #154 - Add IsArrayType on FSharpEntity to allow clients to detect the symbols for array types
-* Fix #96 - Return resolutions of 'Module' and 'Type' in "Module.field" and "Type.field"
-
-#### 0.0.48 -
-* Allow own fsi object without referencing FSharp.Compiler.Interactive.Settings.dll (#127)
-
-#### 0.0.47 -
-* Adjust fix for #143 for F# types with abstract+default events
-
-#### 0.0.46 -
-* Fix multi-project analysis when referenced projects have changed (#141)
-* Fix process exit on bad arguments to FsiEvaluationSession (#126)
-* Deprecate FsiEvaluationSession constructor and add FsiEvaluationSession.Create static method to allow for future API that can return errors
-* Return additional 'property' and 'event' methods for F#-defined types to regularize symbols (#108, #143)
-* Add IsPropertySetterMethod and IsPropertyGetterMethod which only return true for getter/setter methods, not properties. Deprecate IsSetterMethod and IsGetterMethod in favour of these.
-* Add IsEventAddMethod and IsEventRemoveMethod which return true for add/remove methods with an associated event
-* Change IsProperty and IsEvent to only return true for the symbols for properties and events, rather than the methods associated with these
-* Fix value of Assembly for some symbols (e.g. property symbols)
-
-#### 0.0.45 -
-* Add optional project cache size parameter to InteractiveChecker
-* Switch to openBinariesInMemory for SimpleSourceCodeServices
-* Cleanup SimpleSourceCodeServices to avoid code duplication
-
-#### 0.0.44 -
-* Integrate latest changes from visualfsharp.codeplex.com via github.com/fsharp/fsharp
-* Fix problem with task that generates description text of declaration
-* Add AllInterfaceTypes to FSharpEntity and FSharpType
-* Add BaseType to FSharpType to propagate instantiation
-* Add Instantiate to FSharpType
-
-#### 0.0.43 -
-* Fix #109 - Duplicates in GetUsesOfSymbolInFile
-
-#### 0.0.42 -
-* Fix #105 - Register enum symbols in patterns
-* Fix #107 - Return correct results for inheritance chain of .NET types
-* Fix #101 - Add DeclaringEntity property
-
-#### 0.0.41 -
-* Fixed #104 - Make all operations that may utilize the FCS reactor async
-* Add FSharpDisplayContext and FSharpType.Format
-* Replace GetSymbolAtLocationAlternate by GetSymbolUseAtLocation
-
-#### 0.0.40 -
-* Fixed #86 - Expose Microsoft.FSharp.Compiler.Interactive.Shell.Settings.fsi
-* Fixed #99 - Add IsNamespace property to FSharpEntity
-
-#### 0.0.39 -
-* Fixed #79 - Usage points for symbols in union patterns
-
-#### 0.0.38 -
-* Fixed #94 and #89 by addition of new properties to the FSharpSymbolUse type
-* Fixed #93 by addition of IsOpaque to FSharpEntity type
-* Fixed #92 - Issue with nested classes
-* Fixed #87 - Allow analysis of members from external assemblies
-
-#### 0.0.37 -
-* Obsolete HasDefaultValue - see https://github.com/fsharp/FSharp.Compiler.Service/issues/77
-
-#### 0.0.36 -
-* Fix #71 - Expose static parameters and xml docs of type providers
-* Fix #63 - SourceCodeServices: #r ignores include paths passed as command-line flags
-
-#### 0.0.35 -
-* Fix #38 - FSharp.Compiler.Services should tolerate an FSharp.Core without siginfo/optdata in the search path
-
-
-#### 0.0.34 -
-* Add StaticParameters property to entities, plus FSharpStaticParameter symbol
-* Fix #65
-
-#### 0.0.33 -
-* Add FullName and Assembly properties for symbols
-* Fix #76
-* Add Japanese documentation
-
-#### 0.0.32 -
-* Make ParseFileInProject asynchronous
-* Add ParseAndCheckFileInProject
-* Use cached results in ParseAndCheckFileInProject if available
-
-#### 0.0.31 -
-* Fix performance problem with CheckFileInProject
-
-#### 0.0.30 -
-* Add initial prototype version of multi-project support, through optional ProjectReferences in ProjectOptions. Leave this empty
- to use DLL/file-based references to results from other projects.
-
-#### 0.0.29 -
-* Fix symbols for named union fields in patterns
-
-#### 0.0.28 -
-* Fix symbols for named union fields
-* Add FSharpActivePatternCase to refine FSharpSymbol
-
-#### 0.0.27 -
-* Fix exception tag symbol reporting
-
-#### 0.0.26 -
-* Fix off-by-one in reporting of range for active pattern name
-
-#### 0.0.25 -
-* Add optional source argument to TryGetRecentTypeCheckResultsForFile to specify that source must match exactly
-
-#### 0.0.24 -
-* Update version number as nuget package may not have published properly
-
-#### 0.0.23 -
-* Move to one-based line numbering everywhere
-* Provide better symbol information for active patterns
-
-#### 0.0.22 -
-* Provide symbol location for type parameters
-
-#### 0.0.21 -
-* Add GetUsesOfSymbolInFile
-* Better symbol resolution results for type parameter symbols
-
-#### 0.0.20 -
-* Update version number as nuget package may not have published properly
-
-#### 0.0.19 -
-* Change return type of GetAllUsesOfSymbol, GetAllUsesOfAllSymbols and GetAllUsesOfAllSymbolsInFile to FSharpSymbolUse
-* Add symbol uses when an abstract member is implemented.
-
-#### 0.0.18 -
-* Add GetAllUsesOfAllSymbols and GetAllUsesOfAllSymbolsInFile
-
-#### 0.0.17 -
-* Improvements to symbol accuracy w.r.t. type abbreviations
-
-#### 0.0.16 -
-* Make FSharpEntity.BaseType return an option
-* FsiSesion got a new "EvalScript" method which allows to evaluate .fsx files
-
-#### 0.0.15 -
-* Update version number as nuget package may not have published properly
-
-#### 0.0.14 -
-* Update version number as nuget package may not have published properly
-
-#### 0.0.13-alpha -
-* Fix #39 - Constructor parameters are mistaken for record fields in classes
-
-#### 0.0.12-alpha -
-* Make the parts of the lexer/parser used by 'XmlDoc' tools in F# VS Power tools public
-
-#### 0.0.11-alpha -
-* Add 'IsUnresolved'
-
-#### 0.0.10-alpha -
-* Fix bug where 'multiple references to FSharp.Core' was given as error for scripts
-
-#### 0.0.9-alpha -
-* Fix fsc corrupting assemblies when generating pdb files (really)
-* Give better error messages for missing assemblies
-* Report more information about symbols returned by GetSymbolAtLocation (through subtypes)
-* Fix typos in docs
-* Return full project results from ParseAndCheckInteraction
-* Be more robust to missing assembly references by default.
-
-#### 0.0.8-alpha -
-* Fix fsc corrupting assemblies when generating pdb files
-
-#### 0.0.7-alpha -
-* Fix docs
-* Make symbols more robust to missing assemblies
-* Be robust to failures on IncrementalBuilder creation
-* Allow use of MSBuild resolution by IncrementalBuilder
-
-#### 0.0.6-alpha -
-* Fix version number
-
-#### 0.0.5-alpha -
-* Added GetUsesOfSymbol(), FSharpSymbol type, GetSymbolAtLocation(...)
-
-#### 0.0.4-alpha -
-* Added documentation of file system API
-* Reporte errors correctly from ParseAndCheckProject
-
-
-#### 0.0.3-alpha -
-* Integrate FSharp.PowerPack.Metadata as the FSharp* symbol API
-* Renamed Param --> MethodGroupItemParameter and hid record from view, made into an object
-* Renamed Method --> MethodGroupItem and hid record from view, made into an object
-* Renamed Methods --> MethodGroup and hid record from view, made into an object
-* Renamed MethodGroup.Name --> MethodGroup.MethodName
-* Renamed DataTip --> ToolTip consistently across all text
-* Renamed CheckOptions --> ProjectOptions
-* Renamed TypeCheckAnswer --> CheckFileAnswer
-* Renamed UntypedParseInfo --> ParseFileResults
-* Removed GetCheckOptionsFromScriptRoot member overload in favour of optional argument
-* Renamed GetCheckOptionsFromScriptRoot --> GetProjectOptionsFromScript
-* Renamed UntypedParse --> ParseFileInProject
-* Renamed TypeCheckSource --> CheckFileInProjectIfReady
-* Added numerous methods to API including CheckFileInProject
-* Added experimental GetBackgroundCheckResultsForFileInProject, GetBackgroundParseResultsForFileInProject
-* Added PartialAssemblySignature to TypeCheckResults/CheckFileResults
-* Added CurrentPartialAssemblySignature to FsiEvaluationSession
-* Added ParseAndCheckInteraction to FsiEvaluationSession to support intellisense implementation against a script fragment
-* Added initial testing in tests/service
-* Added ParseAndCheckProject to SourceCodeServices API. This will eventually return "whole project" information such as symbol tables.
-* Added GetDefaultConfiguration to simplify process of configuring FsiEvaluationSession
-* Added PartialAssemblySignatureUpdated event to FsiEvaluationSession
-* Added travis build
-
-#### 0.0.2-alpha -
-* Integrate hosted FSI configuration, SimpleSourceCodeServices, cleanup to SourceCodeServices API
-
-
diff --git a/fcs/build.cmd b/fcs/build.cmd
deleted file mode 100644
index e556a4bd7db..00000000000
--- a/fcs/build.cmd
+++ /dev/null
@@ -1,27 +0,0 @@
-@echo off
-
-setlocal
-pushd %~dp0%
-
-if errorlevel 1 (
- endlocal
- exit /b %errorlevel%
-)
-
-powershell -noprofile -executionPolicy RemoteSigned -file "%~dp0\download-paket.ps1"
-.paket\paket.exe restore
-if errorlevel 1 (
- endlocal
- exit /b %errorlevel%
-)
-
-:: don't care if this fails
-dotnet build-server shutdown >NUL 2>&1
-
-packages\FAKE\tools\FAKE.exe build.fsx %*
-if errorlevel 1 (
- endlocal
- exit /b %errorlevel%
-)
-endlocal
-exit /b 0
diff --git a/fcs/build.fsx b/fcs/build.fsx
deleted file mode 100644
index cf0e0d8deda..00000000000
--- a/fcs/build.fsx
+++ /dev/null
@@ -1,173 +0,0 @@
-// --------------------------------------------------------------------------------------
-// FAKE build script
-// --------------------------------------------------------------------------------------
-
-#I "packages/FAKE/tools"
-#r "packages/FAKE/tools/FakeLib.dll"
-open System
-open System.IO
-open Fake
-open Fake.AppVeyor
-open Fake.ReleaseNotesHelper
-
-#if MONO
-// prevent incorrect output encoding (e.g. https://github.com/fsharp/FAKE/issues/1196)
-System.Console.OutputEncoding <- System.Text.Encoding.UTF8
-CleanDir (__SOURCE_DIRECTORY__ + "/../artifacts/TestResults")
-File.WriteAllText(__SOURCE_DIRECTORY__ + "/../artifacts/TestResults/notestsyet.txt","No tests yet")
-let isMono = true
-#else
-let isMono = false
-#endif
-
-// --------------------------------------------------------------------------------------
-// Utilities
-// --------------------------------------------------------------------------------------
-
-let dotnetExePath =
- // Build.cmd normally downloads a dotnet cli to: \artifacts\toolset\dotnet
- // check if there is one there to avoid downloading an additional one here
- let pathToCli = Path.Combine(__SOURCE_DIRECTORY__, @"..\artifacts\toolset\dotnet\dotnet.exe")
- if File.Exists(pathToCli) then
- pathToCli
- else
- DotNetCli.InstallDotNetSDK "2.2.105"
-
-let runDotnet workingDir args =
- let result =
- ExecProcess (fun info ->
- info.FileName <- dotnetExePath
- info.WorkingDirectory <- workingDir
- info.Arguments <- args) TimeSpan.MaxValue
-
- if result <> 0 then failwithf "dotnet %s failed" args
-
-let assertExitCodeZero x = if x = 0 then () else failwithf "Command failed with exit code %i" x
-
-let runCmdIn workDir (exe:string) = Printf.ksprintf (fun (args:string) ->
-#if MONO
- let exe = exe.Replace("\\","/")
- let args = args.Replace("\\","/")
- printfn "[%s] mono %s %s" workDir exe args
- Shell.Exec("mono", sprintf "%s %s" exe args, workDir)
-#else
- printfn "[%s] %s %s" workDir exe args
- Shell.Exec(exe, args, workDir)
-#endif
- |> assertExitCodeZero
-)
-
-// --------------------------------------------------------------------------------------
-// The rest of the code is standard F# build script
-// --------------------------------------------------------------------------------------
-
-let releaseDir = Path.Combine(__SOURCE_DIRECTORY__, "../artifacts/bin/fcs/Release")
-
-// Read release notes & version info from RELEASE_NOTES.md
-let release = LoadReleaseNotes (__SOURCE_DIRECTORY__ + "/RELEASE_NOTES.md")
-let isAppVeyorBuild = buildServer = BuildServer.AppVeyor
-let isJenkinsBuild = buildServer = BuildServer.Jenkins
-let isVersionTag (tag: string) = Version.TryParse tag |> fst
-let hasRepoVersionTag = isAppVeyorBuild && AppVeyorEnvironment.RepoTag && isVersionTag AppVeyorEnvironment.RepoTagName
-let assemblyVersion = if hasRepoVersionTag then AppVeyorEnvironment.RepoTagName else release.NugetVersion
-
-let buildVersion =
- if hasRepoVersionTag then assemblyVersion
- else if isAppVeyorBuild then sprintf "%s-b%s" assemblyVersion AppVeyorEnvironment.BuildNumber
- else assemblyVersion
-
-Target "Clean" (fun _ ->
- CleanDir releaseDir
-)
-
-Target "Restore" (fun _ ->
- // We assume a paket restore has already been run
- runDotnet __SOURCE_DIRECTORY__ "restore ../src/buildtools/buildtools.proj -v n"
- runDotnet __SOURCE_DIRECTORY__ "restore FSharp.Compiler.Service.sln -v n"
-)
-
-Target "BuildVersion" (fun _ ->
- Shell.Exec("appveyor", sprintf "UpdateBuild -Version \"%s\"" buildVersion) |> ignore
-)
-
-Target "Build" (fun _ ->
- runDotnet __SOURCE_DIRECTORY__ "build ../src/buildtools/buildtools.proj -v n -c Proto"
- let fslexPath = __SOURCE_DIRECTORY__ + "/../artifacts/bin/fslex/Proto/netcoreapp2.1/fslex.dll"
- let fsyaccPath = __SOURCE_DIRECTORY__ + "/../artifacts/bin/fsyacc/Proto/netcoreapp2.1/fsyacc.dll"
- runDotnet __SOURCE_DIRECTORY__ (sprintf "build FSharp.Compiler.Service.sln -v n -c Release /p:FsLexPath=%s /p:FsYaccPath=%s" fslexPath fsyaccPath)
-)
-
-Target "Test" (fun _ ->
- // This project file is used for the netcoreapp2.0 tests to work out reference sets
- runDotnet __SOURCE_DIRECTORY__ "build ../tests/projects/Sample_NETCoreSDK_FSharp_Library_netstandard2_0/Sample_NETCoreSDK_FSharp_Library_netstandard2_0.fsproj -v n /restore /p:DisableCompilerRedirection=true"
-
- // Now run the tests
- let logFilePath = Path.Combine(__SOURCE_DIRECTORY__, "..", "artifacts", "TestResults", "Release", "FSharp.Compiler.Service.Test.xml")
- runDotnet __SOURCE_DIRECTORY__ (sprintf "test FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj --no-restore --no-build -v n -c Release --test-adapter-path . --logger \"nunit;LogFilePath=%s\"" logFilePath)
-)
-
-Target "NuGet" (fun _ ->
- runDotnet __SOURCE_DIRECTORY__ "pack FSharp.Compiler.Service.sln -v n -c Release"
-)
-
-Target "GenerateDocsEn" (fun _ ->
- executeFSIWithArgs "docsrc/tools" "generate.fsx" [] [] |> ignore
-)
-
-Target "GenerateDocsJa" (fun _ ->
- executeFSIWithArgs "docsrc/tools" "generate.ja.fsx" [] [] |> ignore
-)
-
-Target "PublishNuGet" (fun _ ->
- Paket.Push (fun p ->
- let apikey =
- match getBuildParam "nuget-apikey" with
- | s when not (String.IsNullOrWhiteSpace s) -> s
- | _ -> getUserInput "Nuget API Key: "
- { p with
- ApiKey = apikey
- WorkingDir = releaseDir })
-)
-
-// --------------------------------------------------------------------------------------
-// Run all targets by default. Invoke 'build ' to override
-
-Target "Start" DoNothing
-Target "Release" DoNothing
-Target "GenerateDocs" DoNothing
-Target "TestAndNuGet" DoNothing
-
-"Start"
- =?> ("BuildVersion", isAppVeyorBuild)
- ==> "Restore"
- ==> "Build"
-
-"Build"
- ==> "Test"
-
-"Build"
- ==> "NuGet"
-
-"Test"
- ==> "TestAndNuGet"
-
-"NuGet"
- ==> "TestAndNuGet"
-
-"Build"
- ==> "NuGet"
- ==> "PublishNuGet"
- ==> "Release"
-
-"Build"
- ==> "GenerateDocsEn"
- ==> "GenerateDocs"
-
-"Build"
- ==> "GenerateDocsJa"
- ==> "GenerateDocs"
-
-"GenerateDocs"
- ==> "Release"
-
-RunTargetOrDefault "Build"
diff --git a/fcs/build.sh b/fcs/build.sh
deleted file mode 100755
index 0b71dd409d2..00000000000
--- a/fcs/build.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-if test "$OS" = "Windows_NT"
-then
- # use .Net
- cmd fcs/build.cmd $@
-else
- cd fcs
-
- # use mono
- if [[ ! -e ~/.config/.mono/certs ]]; then
- mozroots --import --sync --quiet
- fi
-
- ./download-paket.sh
- mono .paket/paket.exe restore
- exit_code=$?
- if [ $exit_code -ne 0 ]; then
- exit $exit_code
- fi
-
- mono packages/FAKE/tools/FAKE.exe $@ --fsiargs -d:MONO build.fsx
-fi
diff --git a/fcs/cibuild.sh b/fcs/cibuild.sh
deleted file mode 100755
index ddc49d8ff34..00000000000
--- a/fcs/cibuild.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-
-# note: expects to run from top directory
-./mono/latest-mono-stable.sh
-./fcs/build.sh NuGet
diff --git a/fcs/dependencies/MSBuild.v12.0/.gitignore b/fcs/dependencies/MSBuild.v12.0/.gitignore
deleted file mode 100644
index 6a7461313bb..00000000000
--- a/fcs/dependencies/MSBuild.v12.0/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.dll
diff --git a/fcs/dependencies/MSBuild.v12.0/MSBuild.v12.0.csproj b/fcs/dependencies/MSBuild.v12.0/MSBuild.v12.0.csproj
deleted file mode 100644
index b59e15cd058..00000000000
--- a/fcs/dependencies/MSBuild.v12.0/MSBuild.v12.0.csproj
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
- net45
- MSBuild.v12.0.nuspec
-
-
-
-
-
diff --git a/fcs/dependencies/MSBuild.v12.0/MSBuild.v12.0.nuspec b/fcs/dependencies/MSBuild.v12.0/MSBuild.v12.0.nuspec
deleted file mode 100644
index e3047f0a962..00000000000
--- a/fcs/dependencies/MSBuild.v12.0/MSBuild.v12.0.nuspec
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
- FSharp.Compiler.Service.MSBuild.v12.0
- 1.0
- Microsoft and F# Software Foundation
- MSBuild.v12.0 dependencies for fcs.
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/fcs/dependencies/MSBuild.v12.0/README.md b/fcs/dependencies/MSBuild.v12.0/README.md
deleted file mode 100644
index 6fe2cf4f3b1..00000000000
--- a/fcs/dependencies/MSBuild.v12.0/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-The MSBuild.12.0 dependencies have been converted to a NuGet package.
-
-To create an updated version of the package:
-
-1. Copy the appropriate `Microsoft.Build.*.dll` files to this directory.
-2. Update the `` element of `MSBuild.v12.0.nuspec`.
-3. Run `msbuild MSBuild.v12.0.csproj /t:Pack`
-4. Upload `\artifacts\bin\fcs\FSharp.Compiler.Service.MSBuild.v12.0.*.nupkg` to the MyGet feed at
- `https://dotnet.myget.org/F/fsharp/api/v3/index.json`
diff --git a/fcs/docsrc/content/compiler.fsx b/fcs/docsrc/content/compiler.fsx
deleted file mode 100644
index c87f755ed35..00000000000
--- a/fcs/docsrc/content/compiler.fsx
+++ /dev/null
@@ -1,100 +0,0 @@
-(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
-(**
-Hosted Compiler
-===============
-
-This tutorial demonstrates how to host the F# compiler.
-
-> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published
-*)
-
-(**
-> **NOTE:** There are several options for hosting the F# compiler. The easiest one is to use the
-`fsc.exe` process and pass arguments.
-*)
-
-(**
-
-> **NOTE:** By default [compilations using FSharp.Compiler.Service reference FSharp.Core 4.3.0.0](https://github.com/fsharp/FSharp.Compiler.Service/issues/156) (matching F# 3.0). You can override
-this choice by passing a reference to FSharp.Core for 4.3.1.0 or later explicitly in your command-line arguments.
-
-*)
-
-(**
----------------------------
-
-First, we need to reference the libraries that contain F# interactive service:
-*)
-
-#r "FSharp.Compiler.Service.dll"
-open System.IO
-open FSharp.Compiler.SourceCodeServices
-
-// Create an interactive checker instance
-let checker = FSharpChecker.Create()
-
-(**
-Now write content to a temporary file:
-
-*)
-let fn = Path.GetTempFileName()
-let fn2 = Path.ChangeExtension(fn, ".fsx")
-let fn3 = Path.ChangeExtension(fn, ".dll")
-
-File.WriteAllText(fn2, """
-module M
-
-type C() =
- member x.P = 1
-
-let x = 3 + 4
-""")
-
-(**
-Now invoke the compiler:
-*)
-
-let errors1, exitCode1 =
- checker.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |])
- |> Async.RunSynchronously
-
-(**
-
-If errors occur you can see this in the 'exitCode' and the returned array of errors:
-
-*)
-File.WriteAllText(fn2, """
-module M
-
-let x = 1.0 + "" // a type error
-""")
-
-let errors1b, exitCode1b =
- checker.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |])
- |> Async.RunSynchronously
-
-(**
-
-Compiling to a dynamic assembly
-===============================
-
-You can also compile to a dynamic assembly, which uses the F# Interactive code generator.
-This can be useful if you are, for example, in a situation where writing to the file system
-is not really an option.
-
-You still have to pass the "-o" option to name the output file, but the output file is not actually written to disk.
-
-The 'None' option indicates that the initiatlization code for the assembly is not executed.
-*)
-let errors2, exitCode2, dynAssembly2 =
- checker.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], execute=None)
- |> Async.RunSynchronously
-
-(*
-Passing 'Some' for the 'execute' parameter executes the initiatlization code for the assembly.
-*)
-let errors3, exitCode3, dynAssembly3 =
- checker.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], Some(stdout,stderr))
- |> Async.RunSynchronously
-
diff --git a/fcs/docsrc/content/corelib.fsx b/fcs/docsrc/content/corelib.fsx
deleted file mode 100644
index a0c1e85f029..00000000000
--- a/fcs/docsrc/content/corelib.fsx
+++ /dev/null
@@ -1,96 +0,0 @@
-(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
-(**
-Compiler Services: Notes on FSharp.Core.dll
-=================================================
-
-Shipping an FSharp.Core with your application
----------------------------------------------
-
-When building applications or plug-in components which use FSharp.Compiler.Service.dll, you will normally also
-include a copy of FSharp.Core.dll as part of your application.
-
-For example, if you build a ``HostedCompiler.exe``, you will normally place an FSharp.Core.dll (say 4.3.1.0) alongside
-your ``HostedCompiler.exe``.
-
-Binding redirects for your application
---------------------------------------
-
-The FSharp.Compiler.Service.dll component depends on FSharp.Core 4.4.0.0. Normally your application will target
-a later version of FSharp.Core, and you may need a [binding redirect](https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/redirect-assembly-versions) to ensure
-that other versions of FSharp.Core forward to the final version of FSharp.Core.dll your application uses.
-Binding redirect files are normally generated automatically by build tools. If not, you can use one like this
-(if your tool is called ``HostedCompiler.exe``, the binding redirect file is called ``HostedCompiler.exe.config``)
-
-Some other dependencies may also need to be reconciled and forwarded.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Which FSharp.Core and .NET Framework gets referenced in compilation?
---------------------------------------
-
-The FSharp.Compiler.Service component can be used to do more or less any sort of F# compilation.
-In particular you can reference an explicit FSharp.Core and/or framework
-assemblies in the command line arguments (different to the FSharp.Core and a .NET Framework being used to run your tool).
-
-To target a specific FSharp.Core and/or .NET Framework assemblies, use the ``--noframework`` argument
-and the appropriate command-line arguments:
-
- []
- let fsharpCorePath =
- @"C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.1.0\FSharp.Core.dll"
- let errors2, exitCode2 =
- scs.Compile(
- [| "fsc.exe"; "--noframework";
- "-r"; fsharpCorePath;
- "-r"; @"C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll";
- "-o"; fn3;
- "-a"; fn2 |])
-
-You will need to determine the location of these assemblies. The easiest way to locate these DLLs in a cross-platform way and
-convert them to command-line arguments is to [crack an F# project file](https://fsharp.github.io/FSharp.Compiler.Service/project.html).
-Alternatively you can compute SDK paths yourself, and some helpers to do this are in [the tests for FSharp.Compiler.Service.dll](https://github.com/fsharp/FSharp.Compiler.Service/blob/8a943dd3b545648690cb3bed652a469bdb6dd869/tests/service/Common.fs#L54).
-
-
-What about if I am processing a script or using ``GetCheckOptionsFromScriptRoot``
--------------------------------------------------------------------------
-
-If you do _not_ explicitly reference an FSharp.Core.dll from an SDK location, or if you are processing a script
-using ``FsiEvaluationSession`` or ``GetCheckOptionsFromScriptRoot``, then an implicit reference to FSharp.Core will be made
-by the following choice:
-
-1. The version of FSharp.Core.dll statically referenced by the host assembly returned by ``System.Reflection.Assembly.GetEntryAssembly()``.
-
-2. If there is no static reference to FSharp.Core in the host assembly, then
-
- - For FSharp.Compiler.Service 1.4.0.x above (F# 4.0 series), a reference to FSharp.Core version 4.4.0.0 is added
-
-Do I need to include FSharp.Core.optdata and FSharp.Core.sigdata?
---------------------------------------
-
-No, unless you are doing something with very old FSharp.Core.dll.
-
-Summary
--------
-
-In this design note we have discussed three things:
-
-- which FSharp.Core.dll is used to run your compilation tools
-- how to configure binding redirects for the FSharp.Core.dll used to run your compilation tools
-- which FSharp.Core.dll and/or framework assemblies are referenced during the checking and compilations performed by your tools.
-
-*)
diff --git a/fcs/docsrc/content/editor.fsx b/fcs/docsrc/content/editor.fsx
deleted file mode 100644
index b8af9d0117b..00000000000
--- a/fcs/docsrc/content/editor.fsx
+++ /dev/null
@@ -1,253 +0,0 @@
-(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
-(**
-Compiler Services: Editor services
-==================================
-
-This tutorial demonstrates how to use the editor services provided by the F# compiler.
-This API is used to provide auto-complete, tool-tips, parameter info help, matching of
-brackets and other functions in F# editors including Visual Studio, Xamarin Studio and Emacs
-(see [fsharpbindings](https://github.com/fsharp/fsharpbinding) project for more information).
-Similarly to [the tutorial on using untyped AST](untypedtree.html), we start by
-getting the `InteractiveChecker` object.
-
-> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published
-
-
-Type checking sample source code
---------------------------------
-
-As in the [previous tutorial (using untyped AST)](untypedtree.html), we start by referencing
-`FSharp.Compiler.Service.dll`, opening the relevant namespace and creating an instance
-of `InteractiveChecker`:
-
-*)
-// Reference F# compiler API
-#r "FSharp.Compiler.Service.dll"
-
-open System
-open FSharp.Compiler.SourceCodeServices
-
-// Create an interactive checker instance
-let checker = FSharpChecker.Create()
-
-(**
-
-As [previously](untypedtree.html), we use `GetProjectOptionsFromScriptRoot` to get a context
-where the specified input is the only file passed to the compiler (and it is treated as a
-script file or stand-alone F# source code).
-
-*)
-// Sample input as a multi-line string
-let input =
- """
- open System
-
- let foo() =
- let msg = String.Concat("Hello"," ","world")
- if true then
- printfn "%s" msg.
- """
-// Split the input & define file name
-let inputLines = input.Split('\n')
-let file = "/home/user/Test.fsx"
-
-let projOptions, errors =
- checker.GetProjectOptionsFromScript(file, input)
- |> Async.RunSynchronously
-
-let parsingOptions, _errors = checker.GetParsingOptionsFromProjectOptions(projOptions)
-
-(**
-To perform type checking, we first need to parse the input using
-`ParseFile`, which gives us access to the [untyped AST](untypedtree.html). However,
-then we need to call `CheckFileInProject` to perform the full type checking. This function
-also requires the result of `ParseFileInProject`, so the two functions are often called
-together.
-*)
-// Perform parsing
-
-let parseFileResults =
- checker.ParseFile(file, input, parsingOptions)
- |> Async.RunSynchronously
-(**
-Before we look at the interesting operations provided by `TypeCheckResults`, we
-need to run the type checker on a sample input. On F# code with errors, you would get some type checking
-result (but it may contain incorrectly "guessed" results).
-*)
-
-// Perform type checking
-let checkFileAnswer =
- checker.CheckFileInProject(parseFileResults, file, 0, input, projOptions)
- |> Async.RunSynchronously
-
-(**
-Alternatively you can use `ParseAndCheckFileInProject` to check both in one step:
-*)
-
-let parseResults2, checkFileAnswer2 =
- checker.ParseAndCheckFileInProject(file, 0, input, projOptions)
- |> Async.RunSynchronously
-
-(**
-
-The function returns both the untyped parse result (which we do not use in this
-tutorial), but also a `CheckFileAnswer` value, which gives us access to all
-the interesting functionality...
-*)
-
-let checkFileResults =
- match checkFileAnswer with
- | FSharpCheckFileAnswer.Succeeded(res) -> res
- | res -> failwithf "Parsing did not finish... (%A)" res
-
-(**
-
-Here, we type check a simple function that (conditionally) prints "Hello world".
-On the last line, we leave an additional dot in `msg.` so that we can get the
-completion list on the `msg` value (we expect to see various methods on the string
-type there).
-
-
-Using type checking results
----------------------------
-
-Let's now look at some of the API that is exposed by the `TypeCheckResults` type. In general,
-this is the type that lets you implement most of the interesting F# source code editor services.
-
-### Getting a tool tip
-
-To get a tool tip, you can use `GetToolTipTextAlternate` method. The method takes a line number and character
-offset. Both of the numbers are zero-based. In the sample code, we want to get tooltip for the `foo`
-function that is defined on line 3 (line 0 is blank) and the letter `f` starts at index 7 (the tooltip
-would work anywhere inside the identifier).
-
-In addition, the method takes a tag of token which is typically `IDENT`, when getting tooltip for an
-identifier (the other option lets you get tooltip with full assembly location when using `#r "..."`).
-
-*)
-// Get tag of the IDENT token to be used as the last argument
-open FSharp.Compiler
-let identToken = FSharpTokenTag.Identifier
-
-// Get tool tip at the specified location
-let tip = checkFileResults.GetToolTipText(4, 7, inputLines.[1], ["foo"], identToken)
-printfn "%A" tip
-
-(**
-
-> **NOTE:** `GetToolTipTextAlternate` is an alternative name for the old `GetToolTipText`. The old `GetToolTipText` was
-deprecated because it accepted zero-based line numbers. At some point it will be removed, and `GetToolTipTextAlternate` will be renamed back to `GetToolTipText`.
-*)
-
-(**
-Aside from the location and token kind, the function also requires the current contents of the line
-(useful when the source code changes) and a `Names` value, which is a list of strings representing
-the current long name. For example to get tooltip for the `Random` identifier in a long name
-`System.Random`, you would use location somewhere in the string `Random` and you would pass
-`["System"; "Random"]` as the `Names` value.
-
-The returned value is of type `ToolTipText` which contains a discriminated union `ToolTipElement`.
-The union represents different kinds of tool tips that you can get from the compiler.
-
-### Getting auto-complete lists
-
-The next method exposed by `TypeCheckResults` lets us perform auto-complete on a given location.
-This can be called on any identifier or in any scope (in which case you get a list of names visible
-in the scope) or immediately after `.` to get a list of members of some object. Here, we get a
-list of members of the string value `msg`.
-
-To do this, we call `GetDeclarationListInfo` with the location of the `.` symbol on the last line
-(ending with `printfn "%s" msg.`). The offsets are one-based, so the location is `7, 23`.
-We also need to specify a function that says that the text has not changed and the current identifer
-where we need to perform the completion.
-*)
-// Get declarations (autocomplete) for a location
-let decls =
- checkFileResults.GetDeclarationListInfo
- (Some parseFileResults, 7, inputLines.[6], PartialLongName.Empty 23, (fun () -> []), fun _ -> false)
- |> Async.RunSynchronously
-
-// Print the names of available items
-for item in decls.Items do
- printfn " - %s" item.Name
-
-(**
-
-> **NOTE:** `v` is an alternative name for the old `GetDeclarations`. The old `GetDeclarations` was
-deprecated because it accepted zero-based line numbers. At some point it will be removed, and `GetDeclarationListInfo` will be renamed back to `GetDeclarations`.
-*)
-
-(**
-When you run the code, you should get a list containing the usual string methods such as
-`Substring`, `ToUpper`, `ToLower` etc. The fourth argument of `GetDeclarations`, here `([], "msg")`,
-specifies the context for the auto-completion. Here, we want a completion on a complete name
-`msg`, but you could for example use `(["System"; "Collections"], "Generic")` to get a completion list
-for a fully qualified namespace.
-
-### Getting parameter information
-
-The next common feature of editors is to provide information about overloads of a method. In our
-sample code, we use `String.Concat` which has a number of overloads. We can get the list using
-`GetMethods` operation. As previously, this takes zero-indexed offset of the location that we are
-interested in (here, right at the end of the `String.Concat` identifier) and we also need to provide
-the identifier again (so that the compiler can provide up-to-date information when the source code
-changes):
-
-*)
-// Get overloads of the String.Concat method
-let methods =
- checkFileResults.GetMethods(5, 27, inputLines.[4], Some ["String"; "Concat"])
- |> Async.RunSynchronously
-
-// Print concatenated parameter lists
-for mi in methods.Methods do
- [ for p in mi.Parameters -> p.Display ]
- |> String.concat ", "
- |> printfn "%s(%s)" methods.MethodName
-(**
-The code uses the `Display` property to get the annotation for each parameter. This returns information
-such as `arg0: obj` or `params args: obj[]` or `str0: string, str1: string`. We concatenate the parameters
-and print a type annotation with the method name.
-*)
-
-(**
-
-## Asynchronous and immediate operations
-
-You may have noticed that `CheckFileInProject` is an asynchronous operation.
-This indicates that type checking of F# code can take some time.
-The F# compiler performs the work in background (automatically) and when
-we call `CheckFileInProject` method, it returns an asynchronous operation.
-
-There is also the `CheckFileInProjectIfReady` method. This returns immediately if the
-type checking operation can't be started immediately, e.g. if other files in the project
-are not yet type-checked. In this case, a background worker might choose to do other
-work in the meantime, or give up on type checking the file until the `FileTypeCheckStateIsDirty` event
-is raised.
-
-> The [fsharpbinding](https://github.com/fsharp/fsharpbinding) project has more advanced
-example of handling the background work where all requests are sent through an F# agent.
-This may be a more appropriate for implementing editor support.
-
-*)
-
-
-(**
-Summary
--------
-
-The `CheckFileAnswer` object contains other useful methods that were not covered in this tutorial. You
-can use it to get location of a declaration for a given identifier, additional colorization information
-(the F# 3.1 colorizes computation builder identifiers & query operators) and others.
-
-Using the FSharpChecker component in multi-project, incremental and interactive editing situations may involve
-knowledge of the [FSharpChecker operations queue](queue.html) and the [FSharpChecker caches](caches.html).
-
-
-Finally, if you are implementing an editor support for an editor that cannot directly call .NET API,
-you can call many of the methods discussed here via a command line interface that is available in the
-[FSharp.AutoComplete](https://github.com/fsharp/fsharpbinding/tree/master/FSharp.AutoComplete) project.
-
-
-*)
diff --git a/fcs/docsrc/content/filesystem.fsx b/fcs/docsrc/content/filesystem.fsx
deleted file mode 100644
index ad0a57712b9..00000000000
--- a/fcs/docsrc/content/filesystem.fsx
+++ /dev/null
@@ -1,190 +0,0 @@
-(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
-(**
-Compiler Services: Virtualized File System
-==========================================
-
-The `FSharp.Compiler.Service` component has a global variable
-representing the file system. By setting this variable you can host the compiler in situations where a file system
-is not available.
-
-> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published.
-
-
-Setting the FileSystem
-----------------------
-
-In the example below, we set the file system to an implementation which reads from disk
-*)
-#r "FSharp.Compiler.Service.dll"
-open System
-open System.IO
-open System.Collections.Generic
-open System.Text
-open FSharp.Compiler.AbstractIL.Internal.Library
-
-let defaultFileSystem = Shim.FileSystem
-
-let fileName1 = @"c:\mycode\test1.fs" // note, the path doesn't exist
-let fileName2 = @"c:\mycode\test2.fs" // note, the path doesn't exist
-
-type MyFileSystem() =
- let file1 = """
-module File1
-
-let A = 1"""
- let file2 = """
-module File2
-let B = File1.A + File1.A"""
- let files = dict [(fileName1, file1); (fileName2, file2)]
-
- interface IFileSystem with
- // Implement the service to open files for reading and writing
- member __.FileStreamReadShim(fileName) =
- match files.TryGetValue fileName with
- | true, text -> new MemoryStream(Encoding.UTF8.GetBytes(text)) :> Stream
- | _ -> defaultFileSystem.FileStreamReadShim(fileName)
-
- member __.FileStreamCreateShim(fileName) =
- defaultFileSystem.FileStreamCreateShim(fileName)
-
- member __.FileStreamWriteExistingShim(fileName) =
- defaultFileSystem.FileStreamWriteExistingShim(fileName)
-
- member __.ReadAllBytesShim(fileName) =
- match files.TryGetValue fileName with
- | true, text -> Encoding.UTF8.GetBytes(text)
- | _ -> defaultFileSystem.ReadAllBytesShim(fileName)
-
- // Implement the service related to temporary paths and file time stamps
- member __.GetTempPathShim() =
- defaultFileSystem.GetTempPathShim()
-
- member __.GetLastWriteTimeShim(fileName) =
- defaultFileSystem.GetLastWriteTimeShim(fileName)
-
- member __.GetFullPathShim(fileName) =
- defaultFileSystem.GetFullPathShim(fileName)
-
- member __.IsInvalidPathShim(fileName) =
- defaultFileSystem.IsInvalidPathShim(fileName)
-
- member __.IsPathRootedShim(fileName) =
- defaultFileSystem.IsPathRootedShim(fileName)
-
- member __.IsStableFileHeuristic(fileName) =
- defaultFileSystem.IsStableFileHeuristic(fileName)
-
- // Implement the service related to file existence and deletion
- member __.SafeExists(fileName) =
- files.ContainsKey(fileName) || defaultFileSystem.SafeExists(fileName)
-
- member __.FileDelete(fileName) =
- defaultFileSystem.FileDelete(fileName)
-
- // Implement the service related to assembly loading, used to load type providers
- // and for F# interactive.
- member __.AssemblyLoadFrom(fileName) =
- defaultFileSystem.AssemblyLoadFrom fileName
-
- member __.AssemblyLoad(assemblyName) =
- defaultFileSystem.AssemblyLoad assemblyName
-
-let myFileSystem = MyFileSystem()
-Shim.FileSystem <- MyFileSystem()
-
-(**
-
-Doing a compilation with the FileSystem
----------------------------------------
-
-*)
-open FSharp.Compiler.SourceCodeServices
-
-let checker = FSharpChecker.Create()
-
-let projectOptions =
- let sysLib nm =
- if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then // file references only valid on Windows
- System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86) +
- @"\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\" + nm + ".dll"
- else
- let sysDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()
- let (++) a b = System.IO.Path.Combine(a,b)
- sysDir ++ nm + ".dll"
-
- let fsCore4300() =
- if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then // file references only valid on Windows
- System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86) +
- @"\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.0.0\FSharp.Core.dll"
- else
- sysLib "FSharp.Core"
-
- let allFlags =
- [| yield "--simpleresolution";
- yield "--noframework";
- yield "--debug:full";
- yield "--define:DEBUG";
- yield "--optimize-";
- yield "--doc:test.xml";
- yield "--warn:3";
- yield "--fullpaths";
- yield "--flaterrors";
- yield "--target:library";
- let references =
- [ sysLib "mscorlib"
- sysLib "System"
- sysLib "System.Core"
- fsCore4300() ]
- for r in references do
- yield "-r:" + r |]
-
- { ProjectFileName = @"c:\mycode\compilation.fsproj" // Make a name that is unique in this directory.
- ProjectId = None
- SourceFiles = [| fileName1; fileName2 |]
- OriginalLoadReferences = []
- ExtraProjectInfo=None
- Stamp = None
- OtherOptions = allFlags
- ReferencedProjects = [| |]
- IsIncompleteTypeCheckEnvironment = false
- UseScriptResolutionRules = true
- LoadTime = System.DateTime.Now // Note using 'Now' forces reloading
- UnresolvedReferences = None }
-
-let results = checker.ParseAndCheckProject(projectOptions) |> Async.RunSynchronously
-
-results.Errors
-results.AssemblySignature.Entities.Count //2
-results.AssemblySignature.Entities.[0].MembersFunctionsAndValues.Count //1
-results.AssemblySignature.Entities.[0].MembersFunctionsAndValues.[0].DisplayName // "B"
-
-(**
-Summary
--------
-In this tutorial, we've seen how to globally customize the view of the file system used by the FSharp.Compiler.Service
-component.
-
-At the time of writing, the following System.IO operations are not considered part of the virtualized file system API.
-Future iterations on the compiler service implementation may add these to the API.
-
- - Path.Combine
- - Path.DirectorySeparatorChar
- - Path.GetDirectoryName
- - Path.GetFileName
- - Path.GetFileNameWithoutExtension
- - Path.HasExtension
- - Path.GetRandomFileName (used only in generation compiled win32 resources in assemblies)
-
-**NOTE:** Several operations in the `SourceCodeServices` API accept the contents of a file to parse
-or check as a parameter, in addition to a file name. In these cases, the file name is only used for
-error reporting.
-
-**NOTE:** Type provider components do not use the virtualized file system.
-
-**NOTE:** The compiler service may use MSBuild for assembly resolutions unless `--simpleresolution` is
-provided. When using the `FileSystem` API you will normally want to specify `--simpleresolution` as one
-of your compiler flags. Also specify `--noframework`. You will need to supply explicit resolutions of all
-referenced .NET assemblies.
-
-*)
\ No newline at end of file
diff --git a/fcs/docsrc/content/interactive.fsx b/fcs/docsrc/content/interactive.fsx
deleted file mode 100644
index 2854d4529e8..00000000000
--- a/fcs/docsrc/content/interactive.fsx
+++ /dev/null
@@ -1,279 +0,0 @@
-(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
-(**
-Interactive Service: Embedding F# Interactive
-=============================================
-
-This tutorial demonstrates how to embed F# interactive in your application. F# interactive
-is an interactive scripting environment that compiles F# code into highly efficient IL code
-and executes it on the fly. The F# interactive service allows you to embed F# evaluation in
-your application.
-
-> **NOTE:** There is a number of options for embedding F# Interactive. The easiest one is to use the
-`fsi.exe` process and communicate with it using standard input and standard output. In this
-tutorial, we look at calling F# Interactive directly through .NET API. However, if you have
-no control over the input, it is a good idea to run F# interactive in a separate process.
-One reason is that there is no way to handle `StackOverflowException` and so a poorly written
-script can terminate the host process. **Remember that while calling F# Interactive through .NET API,
-` --shadowcopyreferences` option will be ignored**. For detailed discussion, please take a look at
-[this thread](https://github.com/fsharp/FSharp.Compiler.Service/issues/292).
-> **NOTE:** If `FsiEvaluationSession.Create` fails with an error saying that `FSharp.Core.dll` cannot be found,
-add the `FSharp.Core.sigdata` and `FSharp.Core.optdata` files. More info [here](https://fsharp.github.io/FSharp.Compiler.Service/corelib.html).
-
-However, the F# interactive service is still useful, because you might want to wrap it in your
-own executable that is then executed (and communicates with the rest of your application), or
-if you only need to execute limited subset of F# code (e.g. generated by your own DSL).
-
-Starting the F# interactive
----------------------------
-
-First, we need to reference the libraries that contain F# interactive service:
-*)
-
-#r "FSharp.Compiler.Service.dll"
-open FSharp.Compiler.SourceCodeServices
-open FSharp.Compiler.Interactive.Shell
-
-(**
-To communicate with F# interactive, we need to create streams that represent input and
-output. We will use those later to read the output printed as a result of evaluating some
-F# code that prints:
-*)
-open System
-open System.IO
-open System.Text
-
-// Intialize output and input streams
-let sbOut = new StringBuilder()
-let sbErr = new StringBuilder()
-let inStream = new StringReader("")
-let outStream = new StringWriter(sbOut)
-let errStream = new StringWriter(sbErr)
-
-// Build command line arguments & start FSI session
-let argv = [| "C:\\fsi.exe" |]
-let allArgs = Array.append argv [|"--noninteractive"|]
-
-let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
-let fsiSession = FsiEvaluationSession.Create(fsiConfig, allArgs, inStream, outStream, errStream)
-
-
-
-(**
-Evaluating and executing code
------------------------------
-
-The F# interactive service exposes several methods that can be used for evaluation. The first
-is `EvalExpression` which evaluates an expression and returns its result. The result contains
-the returned value (as `obj`) and the statically inferred type of the value:
-*)
-/// Evaluate expression & return the result
-let evalExpression text =
- match fsiSession.EvalExpression(text) with
- | Some value -> printfn "%A" value.ReflectionValue
- | None -> printfn "Got no result!"
-
-(**
-This takes a string as an argument and evaluates (i.e. executes) it as F# code.
-*)
-evalExpression "42+1" // prints '43'
-
-(**
-This can be used in a strongly typed way as follows:
-*)
-
-/// Evaluate expression & return the result, strongly typed
-let evalExpressionTyped<'T> (text) =
- match fsiSession.EvalExpression(text) with
- | Some value -> value.ReflectionValue |> unbox<'T>
- | None -> failwith "Got no result!"
-
-evalExpressionTyped "42+1" // gives '43'
-
-
-(**
-The `EvalInteraction` method can be used to evaluate side-effectful operations
-such as printing, declarations, or other interactions that are not valid F# expressions, but can be entered in
-the F# Interactive console. Such commands include `#time "on"` (and other directives), `open System`
-all declarations and other top-level statements. The code
-does not require `;;` at the end. Just enter the code that you want to execute:
-*)
-fsiSession.EvalInteraction "printfn \"bye\""
-
-
-(**
-The `EvalScript` method allows to evaluate a complete .fsx script.
-*)
-
-File.WriteAllText("sample.fsx", "let twenty = 10 + 10")
-fsiSession.EvalScript "sample.fsx"
-
-(**
-Catching errors
-------------------
-
-``EvalExpression``, ``EvalInteraction`` and ``EvalScript`` are awkward if the
-code has type checking warnings or errors, or if evaluation fails with an exception.
-In these cases you can use ``EvalExpressionNonThrowing``, ``EvalInteractionNonThrowing``
-and ``EvalScriptNonThrowing``. These return a tuple of a result and an array of ``FSharpErrorInfo`` values.
-These represent the errors and warnings. The result part is a ``Choice<_,_>`` between an actual
-result and an exception.
-
-The result part of ``EvalExpression`` and ``EvalExpressionNonThrowing`` is an optional ``FSharpValue``.
-If that value is not present then it just indicates that the expression didn't have a tangible
-result that could be represented as a .NET object. This siutation shouldn't actually
-occur for any normal input expressions, and only for primitives used in libraries.
-*)
-
-File.WriteAllText("sample.fsx", "let twenty = 'a' + 10.0")
-let result, warnings = fsiSession.EvalScriptNonThrowing "sample.fsx"
-
-// show the result
-match result with
-| Choice1Of2 () -> printfn "checked and executed ok"
-| Choice2Of2 exn -> printfn "execution exception: %s" exn.Message
-
-
-(**
-Gives:
-
- execution exception: Operation could not be completed due to earlier error
-*)
-
-// show the errors and warnings
-for w in warnings do
- printfn "Warning %s at %d,%d" w.Message w.StartLineAlternate w.StartColumn
-
-(**
-Gives:
-
- Warning The type 'float' does not match the type 'char' at 1,19
- Warning The type 'float' does not match the type 'char' at 1,17
-
-For expressions:
-*)
-
-
-let evalExpressionTyped2<'T> text =
- let res, warnings = fsiSession.EvalExpressionNonThrowing(text)
- for w in warnings do
- printfn "Warning %s at %d,%d" w.Message w.StartLineAlternate w.StartColumn
- match res with
- | Choice1Of2 (Some value) -> value.ReflectionValue |> unbox<'T>
- | Choice1Of2 None -> failwith "null or no result"
- | Choice2Of2 (exn:exn) -> failwith (sprintf "exception %s" exn.Message)
-
-evalExpressionTyped2 "42+1" // gives '43'
-
-
-(**
-Executing in parallel
-------------------
-
-By default the code passed to ``EvalExpression`` is executed immediately. To execute in parallel, submit a computation that starts a task:
-*)
-
-open System.Threading.Tasks
-
-let sampleLongRunningExpr =
- """
-async {
- // The code of what you want to run
- do System.Threading.Thread.Sleep 5000
- return 10
-}
- |> Async.StartAsTask"""
-
-let task1 = evalExpressionTyped>(sampleLongRunningExpr)
-let task2 = evalExpressionTyped>(sampleLongRunningExpr)
-
-(**
-Both computations have now started. You can now fetch the results:
-*)
-
-
-task1.Result // gives the result after completion (up to 5 seconds)
-task2.Result // gives the result after completion (up to 5 seconds)
-
-(**
-Type checking in the evaluation context
-------------------
-
-Let's assume you have a situation where you would like to typecheck code
-in the context of the F# Interactive scripting session. For example, you first
-evaluation a declaration:
-*)
-
-fsiSession.EvalInteraction "let xxx = 1 + 1"
-
-(**
-
-Now you want to typecheck the partially complete code `xxx + xx`
-*)
-
-let parseResults, checkResults, checkProjectResults =
- fsiSession.ParseAndCheckInteraction("xxx + xx")
- |> Async.RunSynchronously
-
-(**
-The `parseResults` and `checkResults` have types `ParseFileResults` and `CheckFileResults`
-explained in [Editor](editor.html). You can, for example, look at the type errors in the code:
-*)
-checkResults.Errors.Length // 1
-
-(**
-The code is checked with respect to the logical type context available in the F# interactive session
-based on the declarations executed so far.
-
-You can also request declaration list information, tooltip text and symbol resolution:
-*)
-open FSharp.Compiler
-
-// get a tooltip
-checkResults.GetToolTipText(1, 2, "xxx + xx", ["xxx"], FSharpTokenTag.IDENT)
-
-checkResults.GetSymbolUseAtLocation(1, 2, "xxx + xx", ["xxx"]) // symbol xxx
-
-(**
-The 'fsi' object
-------------------
-
-If you want your scripting code to be able to access the 'fsi' object, you should pass in an implementation of this object explicitly.
-Normally the one fromm FSharp.Compiler.Interactive.Settings.dll is used.
-*)
-
-let fsiConfig2 = FsiEvaluationSession.GetDefaultConfiguration(fsi)
-
-(**
-Collectible code generation
-------------------
-
-Evaluating code in using FsiEvaluationSession generates a .NET dynamic assembly and uses other resources.
-You can make generated code collectible by passing `collectible=true`. However code will only
-be collected if there are no outstanding object references involving types, for example
-`FsiValue` objects returned by `EvalExpression`, and you must have disposed the `FsiEvaluationSession`.
-See also [Restrictions on Collectible Assemblies](https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/dd554932(v=vs.100)#restrictions).
-
-The example below shows the creation of 200 evaluation sessions. Note that `collectible=true` and
-`use session = ...` are both used.
-
-If collectible code is working correctly,
-overall resource usage will not increase linearly as the evaluation progresses.
-*)
-
-let collectionTest() =
-
- for i in 1 .. 200 do
- let defaultArgs = [|"fsi.exe";"--noninteractive";"--nologo";"--gui-"|]
- use inStream = new StringReader("")
- use outStream = new StringWriter()
- use errStream = new StringWriter()
-
- let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
- use session = FsiEvaluationSession.Create(fsiConfig, defaultArgs, inStream, outStream, errStream, collectible=true)
-
- session.EvalInteraction (sprintf "type D = { v : int }")
- let v = session.EvalExpression (sprintf "{ v = 42 * %d }" i)
- printfn "iteration %d, result = %A" i v.Value.ReflectionValue
-
-// collectionTest() <-- run the test like this
diff --git a/fcs/docsrc/content/ja/compiler.fsx b/fcs/docsrc/content/ja/compiler.fsx
deleted file mode 100644
index 788c715294f..00000000000
--- a/fcs/docsrc/content/ja/compiler.fsx
+++ /dev/null
@@ -1,89 +0,0 @@
-(*** hide ***)
-#I "../../../../artifacts/bin/fcs/net461"
-(**
-コンパイラの組み込み
-====================
-
-このチュートリアルではF#コンパイラをホストする方法を紹介します。
-
-> **注意:** 以下で使用しているAPIは実験的なもので、
- 新しいnugetパッケージの公開に伴って変更される可能性があります。
-
-> **注意:** F#コンパイラをホストする方法はいくつかあります。
- 一番簡単な方法は `fsc.exe` のプロセスを使って引数を渡す方法です。
-
----------------------------
-
-まず、F# Interactiveサービスを含むライブラリへの参照を追加します:
-*)
-
-#r "FSharp.Compiler.Service.dll"
-open FSharp.Compiler.SourceCodeServices
-open System.IO
-
-let scs = FSharpChecker.Create()
-
-(**
-次に、一時ファイルへコンテンツを書き込みます:
-
-*)
-let fn = Path.GetTempFileName()
-let fn2 = Path.ChangeExtension(fn, ".fs")
-let fn3 = Path.ChangeExtension(fn, ".dll")
-
-File.WriteAllText(fn2, """
-module M
-
-type C() =
- member x.P = 1
-
-let x = 3 + 4
-""")
-
-(**
-そしてコンパイラを呼び出します:
-*)
-
-let errors1, exitCode1 = scs.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |]) |> Async.RunSynchronously
-
-(**
-
-エラーが発生した場合は「終了コード」とエラーの配列から原因を特定できます:
-
-*)
-File.WriteAllText(fn2, """
-module M
-
-let x = 1.0 + "" // a type error
-""")
-
-let errors1b, exitCode1b = scs.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |]) |> Async.RunSynchronously
-
-if exitCode1b <> 0 then
- errors1b
- |> Array.iter (printfn "%A")
-
-(**
-
-動的アセンブリへのコンパイル
-============================
-
-コードを動的アセンブリとしてコンパイルすることもできます。
-動的アセンブリはF# Interactiveコードジェネレータでも使用されています。
-
-この機能はたとえばファイルシステムが必ずしも利用できないような状況で役に立ちます。
-
-出力ファイルの名前を指定する "-o" オプションを指定することは可能ですが、
-実際には出力ファイルがディスク上に書き込まれることはありません。
-
-'execute' 引数に 'None' を指定するとアセンブリ用の初期化コードが実行されません。
-*)
-let errors2, exitCode2, dynAssembly2 =
- scs.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], execute=None) |> Async.RunSynchronously
-
-(**
-'Some' を指定するとアセンブリ用の初期化コードが実行されます。
-*)
-let errors3, exitCode3, dynAssembly3 =
- scs.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], Some(stdout,stderr)) |> Async.RunSynchronously
-
diff --git a/fcs/docsrc/content/ja/corelib.fsx b/fcs/docsrc/content/ja/corelib.fsx
deleted file mode 100644
index ea9ee87f8fb..00000000000
--- a/fcs/docsrc/content/ja/corelib.fsx
+++ /dev/null
@@ -1,93 +0,0 @@
-(*** hide ***)
-#I "../../../../artifacts/bin/fcs/net461"
-(**
-コンパイラサービス: FSharp.Core.dll についてのメモ
-==================================================
-
-あなたのアプリケーションとともに FSharp.Core を配布する
--------------------------------------------------------
-
-FSharp.Compiler.Service.dll を利用するアプリケーションまたはプラグイン・コンポーネントをビルドする際、普通はアプリの一部として FSharp.Core.dll のコピーも含めることになるでしょう。
-
-例えば、 ``HostedCompiler.exe`` をビルドする場合、普通はあなたの ``HostedCompiler.exe`` と同じフォルダに FSharp.Core.dll (例えば 4.3.1.0)を配置します。
-
-動的コンパイルや動的実行を行う場合、FSharp.Core.optdata と FSharp.Core.sigdata も含める必要があるかもしれませんが、これらについては下記の指針をご覧ください。
-
-あなたのアプリケーションにリダイレクトをバインドする
-----------------------------------------------------
-
-FSharp.Compiler.Service.dll コンポーネントは FSharp.Core 4.3.0.0 に依存しています。通例、あなたのアプリケーションはこれより後のバージョンの FSharp.Core をターゲットにしており、FSharp.Core 4.3.0.0 をあなたのアプリケーションで用いる FSharp.Core.dll の最終バージョンにちゃんと転送させるように[バインド リダイレクト](https://msdn.microsoft.com/ja-jp/library/7wd6ex19(v=vs.110).aspx)が必要になるでしょう。バインド リダイレクト ファイルは通常ビルドツールによって自動的に生成されます。そうでない場合、下記のようなファイル(あなたのツールが ``HostedCompiler.exe`` という名前で、バインド リダイレクト ファイルが ``HostedCompiler.exe.config`` という名前の場合)を使うことが出来ます。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-どの FSharp.Core と .NET フレームワークがコンパイル時に参照される?
---------------------------------------
-
-FSharp.Combiler.Service コンポーネントは多かれ少なかれ、F#コードを コンパイルするために使われるに過ぎません。特に、コマンドライン引数(あなたのツールを実行するために使われる FSharp.Core や .NET フレームワークとは違います)に明示的に FSharp.Core および/またはフレームワークのアセンブリを参照することが出来ます。
-
-特定の FSharp.Core および .NET フレームワーク アセンブリ、またはそのいずれかをターゲットにする場合、 ``--noframework`` 引数と適切なコマンドライン引数を使います:
-
- []
- let fsharpCorePath =
- @"C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.1.0\FSharp.Core.dll"
- let errors2, exitCode2 =
- scs.Compile(
- [| "fsc.exe"; "--noframework";
- "-r"; fsharpCorePath;
- "-r"; @"C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll";
- "-o"; fn3;
- "-a"; fn2 |])
-
-これらのアセンブリが配置されている場所を指定する必要があります。クロスプラットフォームに対応した方法でDLL を配置して、それらをコマンドライン引数に変換する最も簡単な方法は、[F# プロジェクトファイルをクラックする](https://fsharp.github.io/FSharp.Compiler.Service/ja/project.html)ことです。
-自分で SDK のパスを処理する代わりに、[FSharp.Compiler.Service.dll 用のテスト](https://github.com/fsharp/FSharp.Compiler.Service/blob/8a943dd3b545648690cb3bed652a469bdb6dd869/tests/service/Common.fs#L54)で使用しているようなヘルパー関数も用意されています。
-
-
-スクリプトを処理しているか ``GetCheckOptionsFromScriptRoot`` を使っている場合
--------------------------------------------------------------------------
-
-もし SDK 配置先にある FSharp.Core.dll を明示的に参照 *していない* 場合、または ``FsiEvaluationSession`` や ``GetCheckOptionsFromScriptRoot`` を使用してスクリプトを処理している場合、以下のいずれかの方法により、暗黙的にFSharp.Core が参照されます:
-
-1. ``System.Reflection.Assembly.GetEntryAssembly()`` によって返されるホストアセンブリから静的に参照されたFSharp.Core.dll のバージョン
-
-2. ホストアセンブリに FSharp.Core への静的な参照がない場合、
-
- - FSharp.Compiler.Service 0.x シリーズでは、FSharp.Core バージョン 4.3.0.0 への参照が付与されます
-
- - FSharp.Compiler.Service 1.3.1.x (F# 3.1 シリーズ)では、FSharp.Core バージョン 4.3.1.0 への参照が付与されます
-
- - FSharp.Compiler.Service 1.4.0.x (F# 4.0 シリーズ)では、FSharp.Core バージョン 4.4.0.0 への参照が付与されます
-
-FSharp.Core.optdata と FSharp.Core.sigdata を含める必要はありますか?
---------------------------------------
-
-もしあなたのコンパイル引数が SDK 配置先にある FSharp.Core.dll を明示的に参照している場合、FSharp.Core.sigdata と FSharp.Core.optdata はその DLL と同じフォルダになければいけません(これらのファイルがインストールされていない場合、F# SDKの インストールに問題があります)。もしコンパイル引数で常に明示的に参照していたなら、FSharp.Core.optdata と FSharp.Core.sigdata はあなたのアプリケーションの一部として含める必要は *ありません* 。
-
-もしあなたが暗黙的な参照(例えば、上記のスクリプト処理など)に頼っているのなら、これはあなたのツールがアプリケーションの一部として FSharp.Core.dll を参照しているかもしれない、ということです。この場合、FSharp.Core.optdata および FSharp.Core.sigdata が FSharp.Core.dll と同じフォルダに見つからないというエラーが発生するかもしれません。 **もしあなたがアプリケーションに含めている FSharp.Core.dll を暗黙的に参照したいのであれば、FSharp.Core.sigdata と FSharp.Core.optdata もアプリケーションに追加する2つのファイルとして追加しましょう。** ``CombileToDynamicAssembly`` を使用する場合、この問題によって[アセンブリ解決中のスタックオーバーフロー](https://github.com/fsharp/FSharp.Compiler.Service/issues/258)も引き起こされるでしょう。
-
-動的コンパイルと動的コード実行を行うツール(例: ``HostedExecution.exe``)はしばしば FSharp.Core.dll を暗黙的に参照するようになっています。
-これはつまり通常 FSharp.Core.optdata と FSharp.Core.sigdata を含んでいるということです。
-
-要約
--------
-
-このデザインノートでは3つのポイントを検討しました:
-
-- どの FSharp.Core.dll があなたのコンパイルツールを実行するのに使われるか
-- あなたのコンパイルツールを実行するのに使われる FSharp.Core.dll へのバインド リダイレクトを設定する方法
-- あなたのツールによって実行されるチェック時およびコンパイル時にどの FSharp.Core.dll および/またはフレームワークのアセンブリが参照されるか
-
-*)
diff --git a/fcs/docsrc/content/ja/editor.fsx b/fcs/docsrc/content/ja/editor.fsx
deleted file mode 100644
index f8a33e9a75a..00000000000
--- a/fcs/docsrc/content/ja/editor.fsx
+++ /dev/null
@@ -1,270 +0,0 @@
-(*** hide ***)
-#I "../../../../artifacts/bin/fcs/net461"
-(**
-コンパイラサービス: エディタサービス
-====================================
-
-このチュートリアルはF#コンパイラによって公開されるエディタサービスの
-使用方法についてのデモです。
-このAPIにより、Visual StudioやXamarin Studio、EmacsなどのF#エディタ内において、
-自動補完機能やツールチップ表示、引数情報のヘルプ表示、括弧の補完などの機能を
-実装することができます
-(詳細については [fsharpbindings](https://github.com/fsharp/fsharpbinding) のプロジェクトを参照してください)。
-[型無しASTを使用するチュートリアル](untypedtree.html) と同じく、
-今回も `FSharpChecker` オブジェクトを作成するところから始めます。
-
-> **注意:** 以下で使用しているAPIは試験的なもので、最新バージョンのnugetパッケージの
-公開に伴って変更されることがあります。
-
-サンプルソースコードの型チェック
---------------------------------
-
-[前回の(型無しASTを使った)チュートリアル](untypedtree.html) と同じく、
-`FSharp.Compiler.Service.dll` への参照を追加した後に特定の名前空間をオープンし、
-`FSharpChecker` のインスタンスを作成します:
-
-*)
-// F#コンパイラAPIを参照
-#r "FSharp.Compiler.Service.dll"
-
-open System
-open FSharp.Compiler.SourceCodeServices
-
-// インタラクティブチェッカーのインスタンスを作成
-let checker = FSharpChecker.Create()
-
-(**
-
-[前回](untypedtree.html) 同様、
-コンパイラに渡されるファイルとしては特定の入力値だけであるという
-コンテキストを想定するため、 `GetCheckOptionsFromScriptRoot` を使います
-(この入力値はコンパイラによってスクリプトファイル、
-あるいはスタンドアロンのF#ソースコードとみなされます)。
-
-*)
-// サンプルの入力となる複数行文字列
-let input =
- """
-open System
-
-let foo() =
-let msg = String.Concat("Hello"," ","world")
-if true then
-printfn "%s" msg.
-"""
-// 入力値の分割とファイル名の定義
-let inputLines = input.Split('\n')
-let file = "/home/user/Test.fsx"
-
-let projOptions, _errors1 = checker.GetProjectOptionsFromScript(file, input) |> Async.RunSynchronously
-
-let parsingOptions, _errors2 = checker.GetParsingOptionsFromProjectOptions(projOptions)
-
-(**
-
-型チェックを実行するには、まず `ParseFile` を使って
-入力値をパースする必要があります。
-このメソッドを使うと [型無しAST](untypedtree.html) にアクセスできるようになります。
-しかし今回は完全な型チェックを実行するため、続けて `CheckFileInProject`
-を呼び出す必要があります。
-このメソッドは `ParseFile` の結果も必要とするため、
-たいていの場合にはこれら2つのメソッドをセットで呼び出すことになります。
-
-*)
-// パースを実行
-let parseFileResults =
- checker.ParseFile(file, input, parsingOptions)
- |> Async.RunSynchronously
-(**
-`TypeCheckResults` に備えられた興味深い機能の紹介に入る前に、
-サンプル入力に対して型チェッカーを実行する必要があります。
-F#コードにエラーがあった場合も何らかの型チェックの結果が返されます
-(ただし間違って「推測された」結果が含まれることがあります)。
-*)
-
-// 型チェックを実行
-let checkFileAnswer =
- checker.CheckFileInProject(parseFileResults, file, 0, input, projOptions)
- |> Async.RunSynchronously
-
-(**
-あるいは `ParseAndCheckFileInProject` を使用すれば1つの操作で両方のチェックを行うことができます:
-*)
-
-let parseResults2, checkFileAnswer2 =
- checker.ParseAndCheckFileInProject(file, 0, input, projOptions)
- |> Async.RunSynchronously
-
-(**
-この返り値は `CheckFileAnswer` 型で、この型に機能的に興味深いものが揃えられています...
-*)
-
-let checkFileResults =
- match checkFileAnswer with
- | FSharpCheckFileAnswer.Succeeded(res) -> res
- | res -> failwithf "パースが完了していません... (%A)" res
-
-(**
-
-今回は単に(状況に応じて)「Hello world」と表示するだけの
-単純な関数の型をチェックしています。
-最終行では値 `msg` に対する補完リストを表示することができるように、
-`msg.` というようにドットを追加している点に注意してください
-(今回の場合は文字列型に対する様々なメソッドが期待されます)。
-
-
-型チェックの結果を使用する
---------------------------
-
-では `TypeCheckResults` 型で公開されているAPIをいくつか見ていきましょう。
-一般的に、F#ソースコードエディタサービスの実装に必要な機能は
-ほとんどこの型に備えられています。
-
-### ツールチップの取得
-
-ツールチップを取得するには `GetToolTipTextAlternate` メソッドを使用します。
-このメソッドには行数と文字オフセットを指定します。
-いずれも0から始まる数値です。
-サンプルコードでは3行目(0行目は空白行)、インデックス7にある文字 `f` から始まる関数
-`foo` のツールチップを取得しています
-(ツールチップは識別子の中であれば任意の位置で機能します)。
-
-またこのメソッドにはトークンタグを指定する必要もあります。
-トークンタグは一般的には `IDENT` を指定して、識別子に対する
-ツールチップが取得できるようにします
-(あるいは `#r "..."` を使用している場合にはアセンブリの完全パスを表示させるように
-することもできるでしょう)。
-
-*)
-// 最後の引数に指定する、IDENTトークンのタグを取得
-open FSharp.Compiler
-
-// 特定の位置におけるツールチップを取得
-let tip = checkFileResults.GetToolTipText(4, 7, inputLines.[1], ["foo"], FSharpTokenTag.Identifier)
-printfn "%A" tip
-
-(**
-
-> **注意:** `GetToolTipTextAlternate` は古い関数 `GetToolTipText` に代わるものです。
-`GetToolTipText` は0から始まる行番号を受け取るようになっていたため、非推奨になりました。
-
-この関数には位置とトークンの種類の他にも、
-(ソースコードの変更時に役立つように)特定行の現在の内容と、
-現時点における完全修飾された `名前` を表す文字列のリストを指定する必要があります。
-たとえば完全修飾名 `System.Random` という名前を持った識別子 `Random` に対する
-ツールチップを取得する場合、 `Random` という文字列が現れる場所の他に、
-`["System"; "Random"]` という値を指定する必要があります。
-
-返り値の型は `ToolTipText` で、この型には `ToolTipElement` という
-判別共用体が含まれます。
-この共用体は、コンパイラによって返されたツールチップの種類に応じて異なります。
-
-### 自動補完リストの取得
-
-次に紹介する `TypeCheckResults` のメソッドを使用すると、
-特定の位置における自動補完機能を実装できます。
-この機能は任意の識別子上、
-あるいは(特定のスコープ内で利用可能な名前の一覧を取得する場合には)任意のスコープ、
-あるいは特定のオブジェクトにおけるメンバーリストを取得する場合には
-`.` の直後で呼び出すことができます。
-今回は文字列の値 `msg` に対するメンバーリストを取得することにします。
-
-そのためには最終行( `printfn "%s" msg.` で終わっている行)にある
-シンボル `.` の位置を指定して `GetDeclarationListInfo` を呼び出します。
-オフセットは1から始まるため、位置は `7, 23` になります。
-また、テキストが変更されていないことを表す関数と、
-現時点において補完する必要がある識別子を指定する必要もあります。
-*)
-// 特定の位置における宣言(自動補完)を取得する
-let decls =
- checkFileResults.GetDeclarationListInfo
- (Some parseFileResults, 7, inputLines.[6], PartialLongName.Empty 23, (fun _ -> []), fun _ -> false)
- |> Async.RunSynchronously
-
-// 利用可能な項目を表示
-for item in decls.Items do
- printfn " - %s" item.Name
-(**
-
-> **注意:** `GetDeclarationListInfo` は古い関数 `GetDeclarations` に代わるものです。
-`GetDeclarations` は0から始まる行番号を受け取るようになっていたため、非推奨になりました。
-また、将来的には現在の `GetDeclarations` が削除され、 `GetDeclarationListInfo` が
-`GetDeclarations` になる予定です。
-
-コードを実行してみると、 `Substring` や `ToUpper` 、 `ToLower` といった
-文字列に対するいつものメソッドのリストが取得できていることでしょう。
-`GetDeclarations` の5,6番目の引数( `[]` および `"msg"` )には
-自動補完用のコンテキストを指定します。
-今回の場合は完全名 `msg` に対する補完を行いましたが、
-たとえば `["System"; "Collections"]` と `"Generic"` というように
-完全修飾された名前空間を指定して補完リストを取得することもできます。
-
-### 引数の情報を取得する
-
-次に一般的なエディタの機能としては、メソッドのオーバーロードに
-関する情報を提供するというものでしょう。
-サンプルコード中では多数のオーバーロードを持った `String.Concat` を使っています。
-このオーバーロード一覧は `GetMethods` で取得できます。
-先ほどと同じく、このメソッドには対象とする項目の位置を0基準のオフセットで指定し
-(今回は `String.Concat` 識別子の右側の終端)、
-識別子もやはり指定します
-(これにより、コンパイラはソースコードが変更された場合でも最新の情報に追従できます):
-
-*)
-//String.Concatメソッドのオーバーロードを取得する
-let methods =
- checkFileResults.GetMethods(5, 27, inputLines.[4], Some ["String"; "Concat"]) |> Async.RunSynchronously
-
-// 連結された引数リストを表示
-for mi in methods.Methods do
- [ for p in mi.Parameters -> p.Display ]
- |> String.concat ", "
- |> printfn "%s(%s)" methods.MethodName
-(**
-ここでは `Display` プロパティを使用することで各引数に対する
-アノテーションを取得しています。
-このプロパティは `arg0: obj` あるいは `params args: obj[]` 、
-`str0: string, str1: string` といった情報を返します。
-これらの引数を連結した後、メソッド名とメソッドの型情報とともに表示させています。
-*)
-
-(**
-
-## 非同期操作と即時操作
-
-`CheckFileInProject` が非同期操作であることを気にされる人もいるかもしれません。
-これはつまり、F#コードの型チェックにはある程度時間がかかることを示唆しています。
-F#コンパイラは型チェックを(自動的に)バックグラウンドで処理を進めているため、
-`CheckFileInProject` メソッドを呼び出すと非同期操作が返されることになります。
-
-また、 `CheckFileInProjectIfReady` というメソッドもあります。
-このメソッドは、型チェックの操作が即座に開始できない場合、
-つまりプロジェクト内の他のファイルがまだ型チェックされていない場合には
-処理が即座に返されます。
-この場合、バックグラウンドワーカーは一定期間他の作業を進めるか、
-`FileTypeCheckStateIsDirty` イベントが発生するまでは
-ファイルに対する型チェックを諦めるか、どちらか選択することになります。
-
-> [fsharpbinding](https://github.com/fsharp/fsharpbinding) プロジェクトには
-1つのF#エージェント経由ですべてのリクエストをバックグラウンドワークとして
-処理するような、より複雑な具体例も含まれています。
-エディタの機能を実装する方法としてはこちらのほうが適切です。
-
-*)
-
-
-(**
-まとめ
-------
-
-`CheckFileAnswer` にはチュートリアルで紹介していないような便利なメソッドが
-多数揃えられています。
-これらを使用すれば特定の識別子に対する宣言の位置を取得したり、
-付加的な色情報を取得したりすることができます
-(F# 3.1では式ビルダーの識別子やクエリ演算子も着色表示されます)。
-
-最後に、直接.NET APIを呼び出すことができないようなエディタに対するサポート機能を
-実装する場合、ここで紹介した様々な機能を
-[FSharp.AutoComplete](https://github.com/fsharp/fsharpbinding/tree/master/FSharp.AutoComplete)
-プロジェクトのコマンドラインインターフェイス経由で呼び出すこともできます。
-*)
diff --git a/fcs/docsrc/content/ja/filesystem.fsx b/fcs/docsrc/content/ja/filesystem.fsx
deleted file mode 100644
index 0680f34122f..00000000000
--- a/fcs/docsrc/content/ja/filesystem.fsx
+++ /dev/null
@@ -1,175 +0,0 @@
-(*** hide ***)
-#I "../../../../artifacts/bin/fcs/net461"
-(**
-コンパイラサービス: ファイルシステム仮想化
-==========================================
-
-`FSharp.Compiler.Service` にはファイルシステムを表すグローバル変数があります。
-この変数を設定するこにより、ファイルシステムが利用できない状況でも
-コンパイラをホストすることができるようになります。
-
-> **注意:** 以下で使用しているAPIは実験的なもので、
- 新しいnugetパッケージの公開に伴って変更される可能性があります。
-
-FileSystemの設定
-----------------
-
-以下の例ではディスクからの読み取りを行うような実装をファイルシステムに設定しています:
-*)
-#r "FSharp.Compiler.Service.dll"
-open System
-open System.IO
-open System.Collections.Generic
-open System.Text
-open FSharp.Compiler.AbstractIL.Internal.Library
-
-let defaultFileSystem = Shim.FileSystem
-
-let fileName1 = @"c:\mycode\test1.fs" // 注意: 実際には存在しないファイルのパス
-let fileName2 = @"c:\mycode\test2.fs" // 注意: 実際には存在しないファイルのパス
-
-type MyFileSystem() =
- let file1 = """
-module File1
-
-let A = 1"""
- let file2 = """
-module File2
-let B = File1.A + File1.A"""
- let files = dict [(fileName1, file1); (fileName2, file2)]
-
- interface IFileSystem with
- // 読み取りおよび書き込み用にファイルをオープンする機能を実装
- member __.FileStreamReadShim(fileName) =
- match files.TryGetValue fileName with
- | true, text -> new MemoryStream(Encoding.UTF8.GetBytes(text)) :> Stream
- | _ -> defaultFileSystem.FileStreamReadShim(fileName)
-
- member __.FileStreamCreateShim(fileName) =
- defaultFileSystem.FileStreamCreateShim(fileName)
-
- member __.IsStableFileHeuristic(fileName) =
- defaultFileSystem.IsStableFileHeuristic(fileName)
-
- member __.FileStreamWriteExistingShim(fileName) =
- defaultFileSystem.FileStreamWriteExistingShim(fileName)
-
- member __.ReadAllBytesShim(fileName) =
- match files.TryGetValue fileName with
- | true, text -> Encoding.UTF8.GetBytes(text)
- | _ -> defaultFileSystem.ReadAllBytesShim(fileName)
-
- // 一時パスおよびファイルのタイムスタンプに関連する機能を実装
- member __.GetTempPathShim() =
- defaultFileSystem.GetTempPathShim()
-
- member __.GetLastWriteTimeShim(fileName) =
- defaultFileSystem.GetLastWriteTimeShim(fileName)
-
- member __.GetFullPathShim(fileName) =
- defaultFileSystem.GetFullPathShim(fileName)
-
- member __.IsInvalidPathShim(fileName) =
- defaultFileSystem.IsInvalidPathShim(fileName)
-
- member __.IsPathRootedShim(fileName) =
- defaultFileSystem.IsPathRootedShim(fileName)
-
- // ファイルの存在確認および削除に関連する機能を実装
- member __.SafeExists(fileName) =
- files.ContainsKey(fileName) || defaultFileSystem.SafeExists(fileName)
-
- member __.FileDelete(fileName) =
- defaultFileSystem.FileDelete(fileName)
-
- // アセンブリのロードに関連する機能を実装。
- // 型プロバイダやF# Interactiveで使用される。
- member __.AssemblyLoadFrom(fileName) =
- defaultFileSystem.AssemblyLoadFrom fileName
-
- member __.AssemblyLoad(assemblyName) =
- defaultFileSystem.AssemblyLoad assemblyName
-
-let myFileSystem = MyFileSystem()
-Shim.FileSystem <- MyFileSystem()
-
-(**
-
-FileSystemによるコンパイルの実行
---------------------------------
-
-*)
-open FSharp.Compiler.SourceCodeServices
-
-let checker = FSharpChecker.Create()
-let projectOptions =
- let allFlags =
- [| yield "--simpleresolution";
- yield "--noframework";
- yield "--debug:full";
- yield "--define:DEBUG";
- yield "--optimize-";
- yield "--doc:test.xml";
- yield "--warn:3";
- yield "--fullpaths";
- yield "--flaterrors";
- yield "--target:library";
- let references =
- [ @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\mscorlib.dll";
- @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll";
- @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll";
- @"C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.0.0\FSharp.Core.dll"]
- for r in references do
- yield "-r:" + r |]
-
- { ProjectFileName = @"c:\mycode\compilation.fsproj" // 現在のディレクトリで一意な名前を指定
- ProjectId = None
- SourceFiles = [| fileName1; fileName2 |]
- OriginalLoadReferences = []
- ExtraProjectInfo=None
- Stamp = None
- OtherOptions = allFlags
- ReferencedProjects=[| |]
- IsIncompleteTypeCheckEnvironment = false
- UseScriptResolutionRules = true
- LoadTime = System.DateTime.Now // 'Now' を指定して強制的に再読込させている点に注意
- UnresolvedReferences = None }
-
-let results = checker.ParseAndCheckProject(projectOptions) |> Async.RunSynchronously
-
-results.Errors
-results.AssemblySignature.Entities.Count //2
-results.AssemblySignature.Entities.[0].MembersFunctionsAndValues.Count //1
-results.AssemblySignature.Entities.[0].MembersFunctionsAndValues.[0].DisplayName // "B"
-
-(**
-まとめ
-------
-このチュートリアルでは FSharp.Compiler.Service コンポーネントで使用される
-ファイルシステムに注目して、グローバルな設定を変更する方法について紹介しました。
-
-このチュートリアルの執筆時点では、以下に列挙したSystem.IOの操作に対しては
-仮想化されたファイルシステムAPIが用意されない予定になっています。
-将来のバージョンのコンパイラサービスではこれらのAPIが追加されるかもしれません。
-
- - Path.Combine
- - Path.DirectorySeparatorChar
- - Path.GetDirectoryName
- - Path.GetFileName
- - Path.GetFileNameWithoutExtension
- - Path.HasExtension
- - Path.GetRandomFileName (アセンブリ内にコンパイル済みwin32リソースを生成する場合にのみ使用される)
-
-**注意:** `SourceCodeServices` API内の一部の操作では、
-引数にファイルの内容だけでなくファイル名を指定する必要があります。
-これらのAPIにおいて、ファイル名はエラーの報告のためだけに使用されます。
-
-**注意:** 型プロバイダーコンポーネントは仮想化されたファイルシステムを使用しません。
-
-**注意:** コンパイラサービスは `--simpleresolution` が指定されていない場合、
-MSBuildを使ってアセンブリの解決を試みることがあります。
-`FileSystem` APIを使用する場合、通常はコンパイラへのフラグとして
-`--simpleresolution` を指定することになります。
-それと同時に `--noframework` を指定します。
-.NETアセンブリに対するすべての参照を明示的に指定する必要があるでしょう。
-*)
diff --git a/fcs/docsrc/content/ja/interactive.fsx b/fcs/docsrc/content/ja/interactive.fsx
deleted file mode 100644
index 59bae44f01b..00000000000
--- a/fcs/docsrc/content/ja/interactive.fsx
+++ /dev/null
@@ -1,299 +0,0 @@
-(*** hide ***)
-#I "../../../../artifacts/bin/fcs/net461"
-(**
-インタラクティブサービス: F# Interactiveの組み込み
-==================================================
-
-このチュートリアルでは、独自のアプリケーションに
-F# Interactiveを組み込む方法について紹介します。
-F# Interactiveは対話式のスクリプティング環境で、
-F#コードを高度に最適化されたILコードへとコンパイルしつつ、
-それを即座に実行することができます。
-F# Interactiveサービスを使用すると、独自のアプリケーションに
-F#の評価機能を追加できます。
-
-> **注意:** F# Interactiveは様々な方法で組み込むことができます。
- 最も簡単な方法は `fsi.exe` プロセスとの間で標準入出力経由でやりとりする方法です。
- このチュートリアルではF# Interactiveの機能を.NET APIで
- 直接呼び出す方法について紹介します。
- ただし入力用のコントロールを備えていない場合、別プロセスでF# Interactiveを
- 起動するのはよい方法だといえます。
- 理由の1つとしては `StackOverflowException` を処理する方法がないため、
- 出来の悪いスクリプトによってはホストプロセスが停止させられてしまう
- 場合があるからです。
- **.NET APIを通じてF# Interactiveを呼び出すとしても、 `--shadowcopyreferences`
- オプションは無視されることを覚えておきましょう。**
- 詳細な議論については、[このスレッド](https://github.com/fsharp/FSharp.Compiler.Service/issues/292)
- に目を通してみてください。
- **注意:** もし`FSharp.Core.dll` が見つからないというエラーが出て `FsiEvaluationSession.Create`
- に失敗した場合、 `FSharp.Core.sigdata` と `FSharp.Core.optdata` というファイルを追加してください。
- 詳しい内容は[こちら](https://fsharp.github.io/FSharp.Compiler.Service/ja/corelib.html)
- にあります。
-
-しかしそれでもF# InteractiveサービスにはF# Interactiveを実行ファイルに埋め込んで
-実行出来る(そしてアプリケーションの各機能とやりとり出来る)、あるいは
-機能限定されたF#コード(たとえば独自のDSLによって生成されたコード)だけを
-実行させることが出来るという便利さがあります。
-
-F# Interactiveの開始
---------------------
-
-まずF# Interactiveサービスを含むライブラリへの参照を追加します:
-*)
-
-#r "FSharp.Compiler.Service.dll"
-open FSharp.Compiler.SourceCodeServices
-open FSharp.Compiler.Interactive.Shell
-
-(**
-F# Interactiveとやりとりするには、入出力を表すストリームを作成する必要があります。
-これらのストリームを使用することで、
-いくつかのF#コードに対する評価結果を後から出力することができます:
-*)
-open System
-open System.IO
-open System.Text
-
-// 入出力のストリームを初期化
-let sbOut = new StringBuilder()
-let sbErr = new StringBuilder()
-let inStream = new StringReader("")
-let outStream = new StringWriter(sbOut)
-let errStream = new StringWriter(sbErr)
-
-// コマンドライン引数を組み立てて、FSIセッションを開始する
-let argv = [| "C:\\fsi.exe" |]
-let allArgs = Array.append argv [|"--noninteractive"|]
-
-let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
-let fsiSession = FsiEvaluationSession.Create(fsiConfig, allArgs, inStream, outStream, errStream)
-
-(**
-コードの評価および実行
-----------------------
-
-F# Interactiveサービスにはコードを評価するためのメソッドがいくつか用意されています。
-最初の1つは `EvalExpression` で、式を評価してその結果を返します。
-結果には戻り値が( `obj` として)含まれる他、値に対して静的に推論された型も含まれます:
-*)
-/// 式を評価して結果を返す
-let evalExpression text =
- match fsiSession.EvalExpression(text) with
- | Some value -> printfn "%A" value.ReflectionValue
- | None -> printfn "結果が得られませんでした!"
-
-(**
-これは引数に文字列を取り、それをF#コードとして評価(つまり実行)します。
-*)
-evalExpression "42+1" // '43' を表示する
-
-(**
-これは以下のように強く型付けされた方法で使うことができます:
-*)
-
-/// 式を評価して、強く型付けされた結果を返す
-let evalExpressionTyped<'T> (text) =
- match fsiSession.EvalExpression(text) with
- | Some value -> value.ReflectionValue |> unbox<'T>
- | None -> failwith "結果が得られませんでした!"
-
-evalExpressionTyped "42+1" // '43' になる
-
-
-(**
-`EvalInteraction` メソッドは画面出力機能や宣言、
-F#の式としては不正なものの、F# Interactiveコンソールには入力できるようなものなど、
-副作用を伴う命令を評価する場合に使用できます。
-たとえば `#time "on"` (あるいはその他のディレクティブ)や `open System` 、
-その他の宣言やトップレベルステートメントなどが該当します。
-指定するコードの終端に `;;` を入力する必要はありません。
-実行したいコードだけを入力します:
-*)
-fsiSession.EvalInteraction "printfn \"bye\""
-
-
-(**
-`EvalScript` メソッドを使用すると、完全な .fsx スクリプトを評価することができます。
-*)
-
-File.WriteAllText("sample.fsx", "let twenty = 10 + 10")
-fsiSession.EvalScript "sample.fsx"
-
-(**
-例外処理
---------
-
-コードに型チェックの警告やエラーがあった場合、または評価して例外で失敗した場合、
-`EvalExpression` 、 `EvalInteraction` そして `EvalScript` ではあまりうまく処理されません。
-これらのケースでは、 `EvalExpressionNonThrowing` 、 `EvalInteractionNonThrowing`
-そして `EvalScriptNonThrowing` を使うことが出来ます。
-これらは結果と `FSharpErrorInfo` 値の配列の組を返します。
-これらはエラーと警告を表します。結果の部分は実際の結果と例外のいずれかを表す
-`Choice<_,_>` です。
-
-`EvalExpression` および `EvalExpressionNonThrowing` の結果部分は
-オプションの `FSharpValue` 値です。
-その値が存在しない場合、式が .NET オブジェクトとして表現できる具体的な結果を
-持っていなかったということを指し示しています。
-この状況は実際には入力されたどんな通常の式に対しても発生すべきではなく、
-ライブラリ内で使われるプリミティブ値に対してのみ発生すべきです。
-*)
-
-File.WriteAllText("sample.fsx", "let twenty = 'a' + 10.0")
-let result, warnings = fsiSession.EvalScriptNonThrowing "sample.fsx"
-
-// 結果を表示する
-match result with
-| Choice1Of2 () -> printfn "チェックと実行はOKでした"
-| Choice2Of2 exn -> printfn "実行例外: %s" exn.Message
-
-
-(**
-は次のようになります:
-
- 実行例外: Operation could not be completed due to earlier error
-*)
-
-// エラーと警告を表示する
-for w in warnings do
- printfn "警告 %s 場所 %d,%d" w.Message w.StartLineAlternate w.StartColumn
-
-(**
-は次のようになります:
-
- 警告 The type 'float' does not match the type 'char' 場所 1,19
- 警告 The type 'float' does not match the type 'char' 場所 1,17
-
-式に対しては:
-*)
-
-
-let evalExpressionTyped2<'T> text =
- let res, warnings = fsiSession.EvalExpressionNonThrowing(text)
- for w in warnings do
- printfn "警告 %s 場所 %d,%d" w.Message w.StartLineAlternate w.StartColumn
- match res with
- | Choice1Of2 (Some value) -> value.ReflectionValue |> unbox<'T>
- | Choice1Of2 None -> failwith "null または結果がありません"
- | Choice2Of2 (exn:exn) -> failwith (sprintf "例外 %s" exn.Message)
-
-evalExpressionTyped2 "42+1" // '43' になる
-
-
-(**
-並列実行
---------
-
-デフォルトでは `EvalExpression` に渡したコードは即時実行されます。
-並列に実行するために、タスクを開始する計算を投入します:
-*)
-
-open System.Threading.Tasks
-
-let sampleLongRunningExpr =
- """
-async {
- // 実行したいコード
- do System.Threading.Thread.Sleep 5000
- return 10
-}
- |> Async.StartAsTask"""
-
-let task1 = evalExpressionTyped>(sampleLongRunningExpr)
-let task2 = evalExpressionTyped>(sampleLongRunningExpr)
-
-(**
-両方の計算がいま開始しました。結果を取得することが出来ます:
-*)
-
-
-task1.Result // 完了後に結果が出てくる (最大5秒)
-task2.Result // 完了後に結果が出てくる (最大5秒)
-
-(**
-評価コンテキスト内での型チェック
---------------------------------
-
-F# Interactiveの一連のスクリプティングセッション中で
-コードの型チェックを実行したいような状況を考えてみましょう。
-たとえばまず宣言を評価します:
-*)
-
-fsiSession.EvalInteraction "let xxx = 1 + 1"
-
-(**
-
-次に部分的に完全な `xxx + xx` というコードの型チェックを実行したいとします:
-*)
-
-let parseResults, checkResults, checkProjectResults =
- fsiSession.ParseAndCheckInteraction("xxx + xx") |> Async.RunSynchronously
-
-(**
-`parseResults` と `checkResults` はそれぞれ [エディタ](editor.html)
-のページで説明している `ParseFileResults` と `CheckFileResults` 型です。
-たとえば以下のようなコードでエラーを確認出来ます:
-*)
-checkResults.Errors.Length // 1
-
-(**
-コードはF# Interactiveセッション内において、その時点までに実行された
-有効な宣言からなる論理的な型コンテキストと結びつく形でチェックされます。
-
-また、宣言リスト情報やツールチップテキスト、シンボルの解決といった処理を
-要求することもできます:
-
-*)
-open FSharp.Compiler
-
-// ツールチップを取得する
-checkResults.GetToolTipText(1, 2, "xxx + xx", ["xxx"], FSharpTokenTag.IDENT)
-
-checkResults.GetSymbolUseAtLocation(1, 2, "xxx + xx", ["xxx"]) // シンボル xxx
-
-(**
-'fsi'オブジェクト
------------------
-
-スクリプトのコードが'fsi'オブジェクトにアクセスできるようにしたい場合、
-このオブジェクトの実装を明示的に渡さなければなりません。
-通常、FSharp.Compiler.Interactive.Settings.dll由来の1つが使われます。
-*)
-
-let fsiConfig2 = FsiEvaluationSession.GetDefaultConfiguration(fsi)
-
-(**
-収集可能なコード生成
---------------------
-
-FsiEvaluationSessionを使用してコードを評価すると、
-.NET の動的アセンブリを生成し、他のリソースを使用します。
-`collectible=true` を渡すことで、生成されたコードを収集可能に出来ます。
-しかしながら、例えば `EvalExpression` から返される `FsiValue` のような型を必要とする未解放のオブジェクト参照が無く、
-かつ `FsiEvaluationSession` を破棄したに違いない場合に限ってコードが収集されます。
-[収集可能なアセンブリに対する制限](https://msdn.microsoft.com/ja-jp/library/dd554932%28v=vs.110%29.aspx#Anchor_1)
-も参照してください。
-
-以下の例は200個の評価セッションを生成しています。 `collectible=true` と `use session = ...`
-の両方を使っていることに気をつけてください。
-
-収集可能なコードが正しく動いた場合、全体としてのリソース使用量は
-評価が進んでも線形には増加しないでしょう。
-*)
-
-let collectionTest() =
-
- for i in 1 .. 200 do
- let defaultArgs = [|"fsi.exe";"--noninteractive";"--nologo";"--gui-"|]
- use inStream = new StringReader("")
- use outStream = new StringWriter()
- use errStream = new StringWriter()
-
- let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
- use session = FsiEvaluationSession.Create(fsiConfig, defaultArgs, inStream, outStream, errStream, collectible=true)
-
- session.EvalInteraction (sprintf "type D = { v : int }")
- let v = session.EvalExpression (sprintf "{ v = 42 * %d }" i)
- printfn "その %d, 結果 = %A" i v.Value.ReflectionValue
-
-// collectionTest() <-- このようにテストを実行する
\ No newline at end of file
diff --git a/fcs/docsrc/content/ja/project.fsx b/fcs/docsrc/content/ja/project.fsx
deleted file mode 100644
index 8b70e3df5f7..00000000000
--- a/fcs/docsrc/content/ja/project.fsx
+++ /dev/null
@@ -1,282 +0,0 @@
-(*** hide ***)
-#I "../../../../artifacts/bin/fcs/net461"
-(**
-コンパイラサービス: プロジェクトの分析
-======================================
-
-このチュートリアルではF#コンパイラによって提供されるサービスを使用して
-プロジェクト全体を分析する方法について紹介します。
-
-> **注意:** 以下で使用しているAPIは試験的なもので、
- 最新のnugetパッケージの公開に伴って変更されることがあります。
-
-
-プロジェクト全体の結果を取得する
---------------------------------
-
-[以前の(型無しASTを使った)チュートリアル](untypedtree.html) と同じく、
-まずは `FSharp.Compiler.Service.dll` への参照追加と、適切な名前空間のオープン、
-`FSharpChecker` インスタンスの作成を行います:
-
-*)
-// F#コンパイラAPIへの参照
-#r "FSharp.Compiler.Service.dll"
-
-open System
-open System.Collections.Generic
-open FSharp.Compiler.SourceCodeServices
-
-// インタラクティブチェッカーのインスタンスを作成
-let checker = FSharpChecker.Create()
-
-(**
-今回のサンプル入力は以下の通りです:
-*)
-
-module Inputs =
- open System.IO
-
- let base1 = Path.GetTempFileName()
- let fileName1 = Path.ChangeExtension(base1, ".fs")
- let base2 = Path.GetTempFileName()
- let fileName2 = Path.ChangeExtension(base2, ".fs")
- let dllName = Path.ChangeExtension(base2, ".dll")
- let projFileName = Path.ChangeExtension(base2, ".fsproj")
- let fileSource1 = """
-module M
-
-type C() =
- member x.P = 1
-
-let xxx = 3 + 4
-let fff () = xxx + xxx
- """
- File.WriteAllText(fileName1, fileSource1)
-
- let fileSource2 = """
-module N
-
-open M
-
-type D1() =
- member x.SomeProperty = M.xxx
-
-type D2() =
- member x.SomeProperty = M.fff()
-
-// 警告を発生させる
-let y2 = match 1 with 1 -> M.xxx
- """
- File.WriteAllText(fileName2, fileSource2)
-
-
-(**
-`GetProjectOptionsFromCommandLineArgs` を使用して、
-2つのファイルを1つのプロジェクトとして扱えるようにします:
-*)
-
-let projectOptions =
- checker.GetProjectOptionsFromCommandLineArgs
- (Inputs.projFileName,
- [| yield "--simpleresolution"
- yield "--noframework"
- yield "--debug:full"
- yield "--define:DEBUG"
- yield "--optimize-"
- yield "--out:" + Inputs.dllName
- yield "--doc:test.xml"
- yield "--warn:3"
- yield "--fullpaths"
- yield "--flaterrors"
- yield "--target:library"
- yield Inputs.fileName1
- yield Inputs.fileName2
- let references =
- [ @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\mscorlib.dll"
- @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll"
- @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll"
- @"C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.0.0\FSharp.Core.dll"]
- for r in references do
- yield "-r:" + r |])
-
-(**
-そして(ディスク上に保存されたファイルを使用して)
-プロジェクト全体をチェックします:
-*)
-
-let wholeProjectResults = checker.ParseAndCheckProject(projectOptions) |> Async.RunSynchronously
-
-(**
-発生したエラーと警告は以下のようにしてチェックできます:
-*)
-wholeProjectResults.Errors.Length // 1
-wholeProjectResults.Errors.[0].Message.Contains("Incomplete pattern matches on this expression") // true
-
-wholeProjectResults.Errors.[0].StartLineAlternate // 13
-wholeProjectResults.Errors.[0].EndLineAlternate // 13
-wholeProjectResults.Errors.[0].StartColumn // 15
-wholeProjectResults.Errors.[0].EndColumn // 16
-
-(**
-推測されたプロジェクトのシグネチャをチェックします:
-*)
-[ for x in wholeProjectResults.AssemblySignature.Entities -> x.DisplayName ] // ["N"; "M"]
-[ for x in wholeProjectResults.AssemblySignature.Entities.[0].NestedEntities -> x.DisplayName ] // ["D1"; "D2"]
-[ for x in wholeProjectResults.AssemblySignature.Entities.[1].NestedEntities -> x.DisplayName ] // ["C"]
-[ for x in wholeProjectResults.AssemblySignature.Entities.[0].MembersFunctionsAndValues -> x.DisplayName ] // ["y2"]
-
-(**
-プロジェクト内の全シンボルを取得することもできます:
-*)
-let rec allSymbolsInEntities (entities: IList) =
- [ for e in entities do
- yield (e :> FSharpSymbol)
- for x in e.MembersFunctionsAndValues do
- yield (x :> FSharpSymbol)
- for x in e.UnionCases do
- yield (x :> FSharpSymbol)
- for x in e.FSharpFields do
- yield (x :> FSharpSymbol)
- yield! allSymbolsInEntities e.NestedEntities ]
-
-let allSymbols = allSymbolsInEntities wholeProjectResults.AssemblySignature.Entities
-(**
-プロジェクト全体のチェックが完了した後は、
-プロジェクト内の各ファイルに対する個別の結果を取得することもできます。
-この処理は即座に完了し、改めてチェックが実行されることもありません。
-*)
-
-let backgroundParseResults1, backgroundTypedParse1 =
- checker.GetBackgroundCheckResultsForFileInProject(Inputs.fileName1, projectOptions)
- |> Async.RunSynchronously
-
-
-(**
-そしてそれぞれのファイル内にあるシンボルを解決できます:
-*)
-
-let xSymbol =
- backgroundTypedParse1.GetSymbolUseAtLocation(9,9,"",["xxx"])
- |> Async.RunSynchronously
-
-(**
-それぞれのシンボルに対して、シンボルへの参照を検索することもできます:
-*)
-let usesOfXSymbol = wholeProjectResults.GetUsesOfSymbol(xSymbol.Value.Symbol)
-
-(**
-推測されたシグネチャ内にあるすべての定義済みシンボルに対して、
-それらがどこで使用されているのかを探し出すこともできます:
-*)
-let allUsesOfAllSignatureSymbols =
- [ for s in allSymbols do
- yield s.ToString(), wholeProjectResults.GetUsesOfSymbol(s) ]
-
-(**
-(ローカルスコープで使用されているものも含めて)
-プロジェクト全体で使用されているすべてのシンボルを確認することもできます:
-*)
-let allUsesOfAllSymbols = wholeProjectResults.GetAllUsesOfAllSymbols()
-
-(**
-また、プロジェクト内のファイルに対して、更新後のバージョンに対して
-チェックを実行するようにリクエストすることもできます
-(なお [FileSystem API](filesystem.html) を使用していない場合には、
-プロジェクト内のその他のファイルがまだディスクから
-読み取り中であることに注意してください):
-
-*)
-let parseResults1, checkAnswer1 =
- checker.ParseAndCheckFileInProject(Inputs.fileName1, 0, Inputs.fileSource1, projectOptions)
- |> Async.RunSynchronously
-
-let checkResults1 =
- match checkAnswer1 with
- | FSharpCheckFileAnswer.Succeeded x -> x
- | _ -> failwith "想定外の終了状態です"
-
-let parseResults2, checkAnswer2 =
- checker.ParseAndCheckFileInProject(Inputs.fileName2, 0, Inputs.fileSource2, projectOptions)
- |> Async.RunSynchronously
-
-let checkResults2 =
- match checkAnswer2 with
- | FSharpCheckFileAnswer.Succeeded x -> x
- | _ -> failwith "想定外の終了状態です"
-
-(**
-そして再びシンボルを解決したり、参照を検索したりすることができます:
-*)
-
-let xSymbol2 =
- checkResults1.GetSymbolUseAtLocation(9,9,"",["xxx"])
- |> Async.RunSynchronously
-
-let usesOfXSymbol2 = wholeProjectResults.GetUsesOfSymbol(xSymbol2.Value.Symbol)
-
-(**
-あるいは(ローカルスコープで使用されているシンボルも含めて)
-ファイル中で使用されているすべてのシンボルを検索することもできます:
-*)
-let allUsesOfAllSymbolsInFile1 = checkResults1.GetAllUsesOfAllSymbolsInFile()
-
-(**
-あるいは特定のファイル中で使用されているシンボルを検索することもできます:
-*)
-let allUsesOfXSymbolInFile1 = checkResults1.GetUsesOfSymbolInFile(xSymbol2.Value.Symbol)
-
-let allUsesOfXSymbolInFile2 = checkResults2.GetUsesOfSymbolInFile(xSymbol2.Value.Symbol)
-
-(**
-
-複数プロジェクトの分析
-----------------------
-
-複数のプロジェクトにまたがった参照があるような、
-複数のF# プロジェクトを分析したい場合、
-それらのプロジェクトを一旦ビルドして、
-ProjectOptionsで `-r:プロジェクト-出力-までの-パス.dll` 引数を指定して
-プロジェクトの相互参照を設定すると一番簡単です。
-しかしこの場合、それぞれのプロジェクトが正しくビルド出来、
-DLLファイルが参照可能なディスク上に生成されなければいけません。
-
-たとえばIDEを操作している場合など、状況によっては
-DLLのコンパイルが通るようになる前に
-プロジェクトを参照したいことがあるでしょう。
-この場合はProjectOptionsのReferencedProjectsを設定します。
-この値には依存するプロジェクトのオプションを再帰的に指定します。
-それぞれのプロジェクト参照にはやはり、
-ReferencedProjectsのエントリそれぞれに対応する
-`-r:プロジェクト-出力-までの-パス.dll` というコマンドライン引数を
-ProjectOptionsに設定する必要があります。
-
-プロジェクト参照が設定されると、ソースファイルからのF#プロジェクト分析処理が
-インクリメンタル分析の結果を使用して行われるようになります。
-その際にはソースファイルファイルをDLLへとコンパイルする必要はありません。
-
-相互参照を含むようなF#プロジェクトを効率よく分析するには、
-ReferencedProjectsを正しく設定した後、
-それぞれのプロジェクトを順番通りに分析していくとよいでしょう。
-
-> **注意:** プロジェクトの参照機能は試作段階です。
- プロジェクトの参照を使用すると、依存先のプロジェクトがまだ分析中で、
- 要求したサービスがまだ利用できないことがあるため、
- コンパイラサービスの性能が低下することがあります。
-
-> **注意:** アセンブリが型プロバイダーのコンポーネントを含む場合、
- プロジェクト参照機能は利用できません。
- プロジェクトの分析処理を強制しない限りはプロジェクト参照を設定しても
- 効果がありません。
- また、分析を強制する場合にはディスク上にDLLが存在しなければいけません。
-
-*)
-
-(**
-まとめ
-------
-
-これまで説明してきた通り、 `ParseAndCheckProject` を使用すると
-シンボルの参照などのようなプロジェクト全体の解析結果にアクセスできるようになります。
-シンボルに対する処理の詳細については [シンボル](symbols.html) のページを参照してください。
-
-*)
diff --git a/fcs/docsrc/content/ja/symbols.fsx b/fcs/docsrc/content/ja/symbols.fsx
deleted file mode 100644
index ff62b0de6b2..00000000000
--- a/fcs/docsrc/content/ja/symbols.fsx
+++ /dev/null
@@ -1,236 +0,0 @@
-(*** hide ***)
-#I "../../../../artifacts/bin/fcs/net461"
-(**
-コンパイラサービス: シンボルの処理
-==================================
-
-このチュートリアルでは、F#コンパイラによって提供される
-シンボルの扱い方についてのデモを紹介します。
-シンボルの参照に関する情報については [プロジェクト全体の分析](project.html)
-も参考にしてください。
-
-> **注意:** 以下で使用しているAPIは試験的なもので、
- 最新のnugetパッケージの公開に伴って変更されることがあります。
-
-これまでと同じく、 `FSharp.Compiler.Service.dll` への参照を追加した後、
-適切な名前空間をオープンし、 `FSharpChecker` のインスタンスを作成します:
-
-*)
-// F#コンパイラAPIへの参照
-#r "FSharp.Compiler.Service.dll"
-
-open System
-open System.IO
-open FSharp.Compiler.SourceCodeServices
-
-// インタラクティブチェッカーのインスタンスを作成
-let checker = FSharpChecker.Create()
-
-(**
-
-そして特定の入力値に対して型チェックを行います:
-
-*)
-
-let parseAndTypeCheckSingleFile (file, input) =
- // スタンドアロンの(スクリプト)ファイルを表すコンテキストを取得
- let projOptions, _errors =
- checker.GetProjectOptionsFromScript(file, input)
- |> Async.RunSynchronously
-
- let parseFileResults, checkFileResults =
- checker.ParseAndCheckFileInProject(file, 0, input, projOptions)
- |> Async.RunSynchronously
-
- // 型チェックが成功(あるいは100%に到達)するまで待機
- match checkFileResults with
- | FSharpCheckFileAnswer.Succeeded(res) -> parseFileResults, res
- | res -> failwithf "Parsing did not finish... (%A)" res
-
-let file = "/home/user/Test.fsx"
-
-(**
-## ファイルに対する解決済みのシグネチャ情報を取得する
-
-ファイルに対する型チェックが完了すると、
-`TypeCheckResults` の `PartialAssemblySignature` プロパティを参照することにより、
-チェック中の特定のファイルを含む、推論されたプロジェクトのシグネチャに
-アクセスすることができます。
-
-モジュールや型、属性、メンバ、値、関数、共用体、レコード型、測定単位、
-およびその他のF#言語要素に対する完全なシグネチャ情報が参照できます。
-
-ただし型付き式ツリーに対する情報は(今のところ)この方法では利用できません。
-
-*)
-
-let input2 =
- """
-[]
-let foo(x, y) =
- let msg = String.Concat("Hello"," ","world")
- if true then
- printfn "x = %d, y = %d" x y
- printfn "%s" msg
-
-type C() =
- member x.P = 1
- """
-let parseFileResults, checkFileResults =
- parseAndTypeCheckSingleFile(file, input2)
-
-(**
-これでコードに対する部分的なアセンブリのシグネチャが取得できるようになります:
-*)
-let partialAssemblySignature = checkFileResults.PartialAssemblySignature
-
-partialAssemblySignature.Entities.Count = 1 // エンティティは1つ
-
-(**
-そしてコードを含むモジュールに関連したエンティティを取得します:
-*)
-let moduleEntity = partialAssemblySignature.Entities.[0]
-
-moduleEntity.DisplayName = "Test"
-
-(**
-そしてコード内の型定義に関連したエンティティを取得します:
-*)
-let classEntity = moduleEntity.NestedEntities.[0]
-
-(**
-そしてコード内で定義された関数に関連した値を取得します:
-*)
-let fnVal = moduleEntity.MembersFunctionsAndValues.[0]
-
-(**
-関数値に関するプロパティの値を確認してみましょう。
-*)
-fnVal.Attributes.Count // 1
-fnVal.CurriedParameterGroups.Count // 1
-fnVal.CurriedParameterGroups.[0].Count // 2
-fnVal.CurriedParameterGroups.[0].[0].Name // "x"
-fnVal.CurriedParameterGroups.[0].[1].Name // "y"
-fnVal.DeclarationLocation.StartLine // 3
-fnVal.DisplayName // "foo"
-fnVal.DeclaringEntity.Value.DisplayName // "Test"
-fnVal.DeclaringEntity.Value.DeclarationLocation.StartLine // 1
-fnVal.GenericParameters.Count // 0
-fnVal.InlineAnnotation // FSharpInlineAnnotation.OptionalInline
-fnVal.IsActivePattern // false
-fnVal.IsCompilerGenerated // false
-fnVal.IsDispatchSlot // false
-fnVal.IsExtensionMember // false
-fnVal.IsPropertyGetterMethod // false
-fnVal.IsImplicitConstructor // false
-fnVal.IsInstanceMember // false
-fnVal.IsMember // false
-fnVal.IsModuleValueOrMember // true
-fnVal.IsMutable // false
-fnVal.IsPropertySetterMethod // false
-fnVal.IsTypeFunction // false
-
-(**
-次に、この関数の型がファーストクラスの値として使用されているかどうかチェックします。
-(ちなみに `CurriedParameterGroups` プロパティには引数の名前など、
-より多くの情報も含まれています)
-*)
-fnVal.FullType // int * int -> unit
-fnVal.FullType.IsFunctionType // true
-fnVal.FullType.GenericArguments.[0] // int * int
-fnVal.FullType.GenericArguments.[0].IsTupleType // true
-let argTy1 = fnVal.FullType.GenericArguments.[0].GenericArguments.[0]
-
-argTy1.TypeDefinition.DisplayName // int
-
-(**
-というわけで `int * int -> unit` という型を表現するオブジェクトが取得できて、
-その1つめの 'int' を確認できたわけです。
-また、以下のようにすると 'int' 型についてのより詳細な情報が取得でき、
-それが名前付きの型であり、F#の型省略形 `type int = int32` であることがわかります:
-*)
-
-argTy1.HasTypeDefinition // true
-argTy1.TypeDefinition.IsFSharpAbbreviation // true
-
-(**
-型省略形の右辺、つまり `int32` についてもチェックしてみましょう:
-*)
-
-let argTy1b = argTy1.TypeDefinition.AbbreviatedType
-argTy1b.TypeDefinition.Namespace // Some "Microsoft.FSharp.Core"
-argTy1b.TypeDefinition.CompiledName // "int32"
-
-(**
-そして再び型省略形 `type int32 = System.Int32` から型に関する完全な情報が取得できます:
-*)
-let argTy1c = argTy1b.TypeDefinition.AbbreviatedType
-argTy1c.TypeDefinition.Namespace // Some "System"
-argTy1c.TypeDefinition.CompiledName // "Int32"
-
-(**
-ファイルに対する型チェックの結果には、
-コンパイル時に使用されたプロジェクト(あるいはスクリプト)のオプションに関する
-`ProjectContext` と呼ばれる情報も含まれています:
-*)
-let projectContext = checkFileResults.ProjectContext
-
-for assembly in projectContext.GetReferencedAssemblies() do
- match assembly.FileName with
- | None -> printfn "コンパイル時にファイルの存在しないアセンブリを参照しました"
- | Some s -> printfn "コンパイル時にアセンブリ '%s' を参照しました" s
-
-(**
-**注意:**
-
- - 不完全なコードが存在する場合、一部あるいはすべての属性が意図したとおりには
- 並ばないことがあります。
- - (実際には非常によくあることですが)一部のアセンブリが見つからない場合、
- 外部アセンブリに関連する値やメンバ、エンティティにおける 'IsUnresolved' が
- trueになることがあります。
- IsUnresolvedによる例外に対処できるよう、堅牢なコードにしておくべきです。
-
-*)
-
-(**
-
-## プロジェクト全体に対するシンボル情報を取得する
-
-プロジェクト全体をチェックする場合、チェッカーを作成した後に `parseAndCheckScript`
-を呼び出します。
-今回の場合は単に1つのスクリプトだけが含まれたプロジェクトをチェックします。
-異なる "projOptions" を指定すると、巨大なプロジェクトに対する設定を
-構成することもできます。
-*)
-let parseAndCheckScript (file, input) =
- let projOptions, errors =
- checker.GetProjectOptionsFromScript(file, input)
- |> Async.RunSynchronously
-
- let projResults =
- checker.ParseAndCheckProject(projOptions)
- |> Async.RunSynchronously
-
- projResults
-
-(**
-そして特定の入力に対してこの関数を呼び出します:
-*)
-
-let tmpFile = Path.ChangeExtension(System.IO.Path.GetTempFileName() , "fs")
-File.WriteAllText(tmpFile, input2)
-
-let projectResults = parseAndCheckScript(tmpFile, input2)
-
-
-(**
-結果は以下の通りです:
-*)
-
-let assemblySig = projectResults.AssemblySignature
-
-assemblySig.Entities.Count = 1 // エンティティは1つ
-assemblySig.Entities.[0].Namespace // null
-assemblySig.Entities.[0].DisplayName // "Tmp28D0"
-assemblySig.Entities.[0].MembersFunctionsAndValues.Count // 1
-assemblySig.Entities.[0].MembersFunctionsAndValues.[0].DisplayName // "foo"
diff --git a/fcs/docsrc/content/ja/tokenizer.fsx b/fcs/docsrc/content/ja/tokenizer.fsx
deleted file mode 100644
index 4daf29b7ead..00000000000
--- a/fcs/docsrc/content/ja/tokenizer.fsx
+++ /dev/null
@@ -1,145 +0,0 @@
-(*** hide ***)
-#I "../../../../artifacts/bin/fcs/net461"
-(**
-コンパイラサービス:F#トークナイザを使用する
-============================================
-
-このチュートリアルではF#言語トークナイザの呼び出し方を紹介します。
-F#のソースコードに対して、トークナイザは
-コードの各行にあるトークンに関する情報を含んだソースコード行のリストを生成します。
-各トークンに対してはトークンの種類や位置を取得したり、
-トークンの種類(キーワード、識別子、数値、演算子など)に応じた
-色を取得したりすることができます。
-
-> **注意:** 以下で使用しているAPIは実験的なもので、
- 新しいnugetパッケージの公開に伴って変更される可能性があります。
-
-トークナイザの作成
-------------------
-
-トークナイザを使用するには、 `FSharp.Compiler.Service.dll` への参照を追加した後に
-`SourceCodeServices` 名前空間をオープンします:
-*)
-#r "FSharp.Compiler.Service.dll"
-open FSharp.Compiler.SourceCodeServices
-(**
-すると `FSharpSourceTokenizer` のインスタンスを作成できるようになります。
-このクラスには2つの引数を指定します。
-最初の引数には定義済みのシンボルのリスト、
-2番目の引数にはソースコードのファイル名を指定します。
-定義済みのシンボルのリストを指定するのは、
-トークナイザが `#if` ディレクティブを処理する必要があるからです。
-ファイル名はソースコードの位置を特定する場合にのみ指定する必要があります
-(存在しないファイル名でも指定できます):
-*)
-let sourceTok = FSharpSourceTokenizer([], "C:\\test.fsx")
-(**
-`sourceTok` オブジェクトを使用することでF#ソースコードの各行を
-(繰り返し)トークン化することができます。
-
-F#コードのトークン化
---------------------
-
-トークナイザはソースファイル全体ではなく、行単位で処理を行います。
-トークンを取得した後、トークナイザは新しいステートを( `int64` 値として)返します。
-この値を使うとF#コードをより効率的にトークン化できます。
-つまり、ソースコードが変更された場合もファイル全体を
-再度トークン化する必要はありません。
-変更された部分だけをトークン化すればよいのです。
-
-### 1行をトークン化する
-
-1行をトークン化するには、先ほど作成した `FSharpSourceTokenizer` オブジェクトに対して
-`CreateLineTokenizer` を呼び、 `FSharpLineTokenizer` を作成します:
-*)
-let tokenizer = sourceTok.CreateLineTokenizer("let answer=42")
-(**
-そして `tokenizer` の `ScanToken` を繰り返し `None` を返すまで
-(つまり最終行に到達するまで)繰り返し呼び出すような単純な再帰関数を用意します。
-この関数が成功すると、必要な詳細情報をすべて含んだ `FSharpTokenInfo` オブジェクトが
-返されます:
-*)
-/// F#コード1行をトークン化します
-let rec tokenizeLine (tokenizer:FSharpLineTokenizer) state =
- match tokenizer.ScanToken(state) with
- | Some tok, state ->
- // トークン名を表示
- printf "%s " tok.TokenName
- // 新しい状態で残りをトークン化
- tokenizeLine tokenizer state
- | None, state -> state
-(**
-この関数は、複数行コードや複数行コメント内の前方の行をトークン化する場合に
-必要となるような新しい状態を返します。
-初期値としては `0L` を指定します:
-*)
-tokenizeLine tokenizer FSharpTokenizerLexState.Initial
-(**
-この結果は LET WHITESPACE IDENT EQUALS INT32 という
-トークン名のシーケンスになります。
-`FSharpTokenInfo` にはたとえば以下のような興味深いプロパティが多数あります:
-
- - `CharClass` および `ColorClass` はF#コードを色づけする場合に使用できるような、
- トークンのカテゴリに関する情報を返します。
- - `LeftColumn` および `RightColumn` は行内におけるトークンの位置を返します。
- - `TokenName` は(F# レキサ内で定義された)トークンの名前を返します。
-
-なおトークナイザはステートフルであることに注意してください。
-つまり、1行を複数回トークン化したい場合にはその都度 `CreateLineTokenizer` を
-呼び出す必要があります。
-
-### サンプルコードのトークン化
-
-トークナイザをもっと長いサンプルコードやファイル全体に対して実行する場合、
-サンプル入力を `string` のコレクションとして読み取る必要があります:
-*)
-let lines = """
- // Hello world
- let hello() =
- printfn "Hello world!" """.Split('\r','\n')
-(**
-複数行の入力値をトークン化する場合も、現在の状態を保持するような
-再帰関数が必要になります。
-以下の関数はソースコード行を文字列のリストとして受け取ります
-(また、行番号および現在の状態も受け取ります)。
-各行に対して新しいトークナイザを作成して、
-直前の行における **最後** の状態を使って `tokenizeLine` を呼び出します:
-*)
-/// 複数行のコードに対してトークンの名前を表示します
-let rec tokenizeLines state count lines =
- match lines with
- | line::lines ->
- // トークナイザを作成して1行をトークン化
- printfn "\nLine %d" count
- let tokenizer = sourceTok.CreateLineTokenizer(line)
- let state = tokenizeLine tokenizer state
- // 新しい状態を使って残りをトークン化
- tokenizeLines state (count+1) lines
- | [] -> ()
-(**
-ここでは単に(先ほど定義した) `tokenizeLine` を呼び出して、
-各行にあるすべてのトークンの名前を表示しています。
-この関数は先と同じく、初期状態の値 `0L` と、1行目を表す `1` を
-指定して呼び出すことができます:
-*)
-lines
-|> List.ofSeq
-|> tokenizeLines FSharpTokenizerLexState.Initial 1
-(**
-重要ではない部分(各行の先頭にある空白文字や、1行目のように空白文字しかない行)
-を除けば、このコードを実行すると以下のような出力になります:
-
- [lang=text]
- Line 1
- LINE_COMMENT LINE_COMMENT (...) LINE_COMMENT
- Line 2
- LET WHITESPACE IDENT LPAREN RPAREN WHITESPACE EQUALS
- Line 3
- IDENT WHITESPACE STRING_TEXT (...) STRING_TEXT STRING
-
-注目すべきは、単一行コメントや文字列に対して、
-トークナイザが複数回(大まかにいって単語単位で) `LINE_COMMENT` や
-`STRING_TEXT` を返しているところです。
-したがって、コメントや文字列全体をテキストとして取得したい場合には
-それぞれのトークンを連結する必要があります。
-*)
\ No newline at end of file
diff --git a/fcs/docsrc/content/ja/untypedtree.fsx b/fcs/docsrc/content/ja/untypedtree.fsx
deleted file mode 100644
index 447e3742fff..00000000000
--- a/fcs/docsrc/content/ja/untypedtree.fsx
+++ /dev/null
@@ -1,276 +0,0 @@
-(*** hide ***)
-#I "../../../../artifacts/bin/fcs/net461"
-(**
-コンパイラサービス:型無し構文木の処理
-======================================
-
-このチュートリアルではF#コードに対する型無し抽象構文木
-(untyped abstract syntax tree: untyped AST)
-を取得する方法、および木全体を走査する方法を紹介します。
-この処理を行うことによって、コードフォーマットツールや
-基本的なリファクタリングツール、コードナビゲーションツールなどを作成できます。
-型無し構文木にはコードの構造に関する情報が含まれていますが、
-型情報が含まれていないだけでなく、後で型チェッカーを通すまでは
-解決されないような曖昧さも残されています。
-また、 [エディタサービス](editor.html) として提供されているAPIと
-型無しASTの情報を組み合わせることもできます。
-
-> **注釈:** 以下で使用しているAPIは試験的なもので、将来的に変更される場合があります。
- つまりFSharp.Compiler.Service.dll には既存のものと重複する機能が多数あるため、
- 将来的にはもっときちんとした形に変更されます。
- そのため、これらのサービスを使用するAPIには破壊的変更が加えられる可能性があります。
-
-
-型無しASTの取得
----------------
-
-
-型無しASTにアクセスするには、 `FSharpChecker` のインスタンスを作成します。
-これは型チェックおよびパース用のコンテキストを表す型で、、
-スタンドアロンのF#スクリプトファイル(たとえばVisual Studioで開いたファイル)、
-あるいは複数ファイルで構成されたロード済みのプロジェクトファイルの
-いずれかと結びつきます。
-このインスタンスを作成すると、型チェックの最初のステップである
-「型無しパース」を実行できます。
-次のフェーズは「型有りパース」で、これは [エディタサービス](editor.html) で
-使用されるものです。
-
-インタラクティブチェッカーを使用するには、
-`FSharp.Compiler.Service.dll` への参照を追加した後、
-`SourceCodeServices` 名前空間をオープンします:
-*)
-#r "FSharp.Compiler.Service.dll"
-open System
-open FSharp.Compiler.SourceCodeServices
-(**
-
-### 型無しパースの実行
-
-型無しパース処理は(それなりの時間がかかる型チェック処理と比較すると)
-かなり高速なため、同期的に実行できます。
-まず `FSharpChecker` を作成します。
-
-*)
-// インタラクティブチェッカーのインスタンスを作成
-let checker = FSharpChecker.Create()
-(**
-
-ASTを取得するために、ファイル名とソースコードを受け取る関数を用意します
-(ファイル名は位置情報のためだけに使用されるもので、存在しなくても構いません)。
-まず、コンテキストを表す「インタラクティブチェッカーオプション」を
-用意する必要があります。
-単純な処理に対しては、 `GetCheckOptionsFromScriptRoot` を使えば
-スクリプトファイルのコンテキストを推測させることができます。
-そして `UntypedParse` メソッドを呼び出した後、
-`ParseTree` プロパティの値を返します:
-
-*)
-/// 特定の入力に対する型無し構文木を取得する
-let getUntypedTree (file, input) =
- // 1つのスクリプトファイルから推測される「プロジェクト」用の
- // コンパイラオプションを取得する
- let projOptions, errors =
- checker.GetProjectOptionsFromScript(file, input)
- |> Async.RunSynchronously
-
- let parsingOptions, _errors = checker.GetParsingOptionsFromProjectOptions(projOptions)
-
- // コンパイラの第1フェーズを実行する
- let untypedRes =
- checker.ParseFile(file, input, parsingOptions)
- |> Async.RunSynchronously
-
- match untypedRes.ParseTree with
- | Some tree -> tree
- | None -> failwith "パース中に何らかの問題が発生しました!"
-
-(**
-`FSharpChecker` の詳細については
-[ APIドキュメント](../reference/microsoft-fsharp-compiler-sourcecodeservices-FSharpChecker.html)
-の他に、F# ソースコードのインラインコメントも参考になるでしょう
-( [`service.fsi` のソースコードを参照](https://github.com/fsharp/fsharp/blob/fsharp_31/src/fsharp/service/service.fsi) )。
-
-ASTの走査
----------
-
-抽象構文木は(式やパターン、宣言など)それぞれ異なる文法的要素を表現する、
-多数の判別共用体として定義されています。
-ASTを理解するには
-[`ast.fs`内にあるソースコード](https://github.com/fsharp/fsharp/blob/master/src/fsharp/ast.fs#L464)
-の定義を確認する方法が一番よいでしょう。
-
-ASTに関連する要素は以下の名前空間に含まれています:
-*)
-open FSharp.Compiler.Ast
-(**
-
-ASTを処理する場合、異なる文法的要素に対するパターンマッチを行うような
-相互再帰関数を多数用意することになります。
-サポートすべき要素は非常に多種多様です。
-たとえばトップレベル要素としてはモジュールや名前空間の宣言、
-モジュール内における(letバインディングや型などの)宣言などがあります。
-モジュール内のlet宣言には式が含まれ、さらにこの式に
-パターンが含まれていることもあります。
-
-### パターンと式を走査する
-
-まずは式とパターンを走査する関数から始めます。
-この関数は要素を走査しつつ、要素に関する情報を画面に表示します。
-パターンの場合、入力は `SynPat` 型であり、この型には `Wild` ( `_` パターンを表す)や
-`Named` ( ` という名前` のパターン)、
-`LongIdent` ( `Foo.Bar` 形式の名前)など、多数のケースがあります。
-なお、基本的にパース後のパターンは元のソースコードの見た目よりも複雑になります
-(具体的には `Named` がかなり多数現れます):
-*)
-/// パターンの走査
-/// これは let = あるいは 'match' 式に対する例です
-let rec visitPattern = function
- | SynPat.Wild(_) ->
- printfn " .. アンダースコアパターン"
- | SynPat.Named(pat, name, _, _, _) ->
- visitPattern pat
- printfn " .. 名前 '%s' のパターン" name.idText
- | SynPat.LongIdent(LongIdentWithDots(ident, _), _, _, _, _, _) ->
- let names = String.concat "." [ for i in ident -> i.idText ]
- printfn " .. 識別子: %s" names
- | pat -> printfn " .. その他のパターン: %A" pat
-(**
-この関数は (`bar という名前の (foo, _)` のような、
-ネストされたパターンに対応するために) 再帰関数になっていますが、
-以降で定義するいずれの関数も呼び出しません
-(パターンはその他の文法的な要素を含むことができないからです)。
-
-次の関数は式全体を走査するものです。
-これは処理の大部分が行われる関数で、
-20以上のケースをカバーすることになるでしょう
-( `SynExpr` と入力するとその他のオプションが確認できます)。
-以下のコードでは `if .. then ..` と `let .. = ...` という式を
-処理する方法だけを紹介しています:
-*)
-/// 式を走査する。
-/// 式に2つあるいは3つの部分式が含まれていた場合('else'の分岐がない場合は2つ)、
-/// let式にはパターンおよび2つの部分式が含まれる
-let rec visitExpression = function
- | SynExpr.IfThenElse(cond, trueBranch, falseBranchOpt, _, _, _, _) ->
- // すべての部分式を走査
- printfn "条件部:"
- visitExpression cond
- visitExpression trueBranch
- falseBranchOpt |> Option.iter visitExpression
-
- | SynExpr.LetOrUse(_, _, bindings, body, _) ->
- // バインディングを走査
- // ('let .. = .. and .. = .. in ...' に対しては複数回走査されることがある)
- printfn "以下のバインディングを含むLetOrUse:"
- for binding in bindings do
- let (Binding(access, kind, inlin, mutabl, attrs, xmlDoc,
- data, pat, retInfo, init, m, sp)) = binding
- visitPattern pat
- visitExpression init
- // 本体の式を走査
- printfn "本体は以下:"
- visitExpression body
- | expr -> printfn " - サポート対象外の式: %A" expr
-(**
-`visitExpression` 関数はモジュール内のすべてのトップレベル宣言を走査するような
-関数から呼ばれることになります。
-今回のチュートリアルでは型やメンバーを無視していますが、
-これらを走査する場合も `visitExpression` を呼び出すことになるでしょう。
-
-### 宣言を走査する
-
-既に説明したように、1つのファイルに対するASTには多数のモジュールや
-名前空間の宣言が(トップレベルノードとして)含まれ、
-モジュール内にも(letバインディングや型の)宣言が、
-名前空間にも(こちらは単に型だけの)宣言が含まれます。
-以下の関数はそれぞれの宣言を走査します。
-ただし今回は型やネストされたモジュール、その他の要素については無視して、
-トップレベルの(値および関数に対する) `let` バインディングだけを対象にしています:
-*)
-/// モジュール内の宣言リストを走査する。
-/// モジュール内のトップレベルに記述できるすべての要素
-/// (letバインディングやネストされたモジュール、型の宣言など)が対象になる。
-let visitDeclarations decls =
- for declaration in decls do
- match declaration with
- | SynModuleDecl.Let(isRec, bindings, range) ->
- // 宣言としてのletバインディングは
- // (visitExpressionで処理したような)式としてのletバインディングと
- // 似ているが、本体を持たない
- for binding in bindings do
- let (Binding(access, kind, inlin, mutabl, attrs, xmlDoc,
- data, pat, retInfo, body, m, sp)) = binding
- visitPattern pat
- visitExpression body
- | _ -> printfn " - サポート対象外の宣言: %A" declaration
-(**
-`visitDeclarations` 関数はモジュールや名前空間の宣言のシーケンスを走査する
-関数から呼ばれることになります。
-このシーケンスはたとえば複数の `namespace Foo` 宣言を含むようなファイルに対応します:
-*)
-/// すべてのモジュールや名前空間の宣言を走査する
-/// (基本的には 'module Foo =' または 'namespace Foo.Bar' というコード)
-/// なおファイル中で明示的に定義されていない場合であっても
-/// 暗黙的にモジュールまたは名前空間の宣言が存在することに注意。
-let visitModulesAndNamespaces modulesOrNss =
- for moduleOrNs in modulesOrNss do
- let (SynModuleOrNamespace(lid, isRec, isMod, decls, xml, attrs, _, m)) = moduleOrNs
- printfn "名前空間またはモジュール: %A" lid
- visitDeclarations decls
-(**
-以上でASTの要素を(宣言から始まって式やパターンに至るまで)走査するための
-関数がそろったので、サンプル入力からASTを取得した後、
-上記の関数を実行することができるようになりました。
-
-すべてを組み合わせる
---------------------
-
-既に説明したように、 `getUntypedTree` 関数では `FSharpChecker` を使って
-ASTに対する第1フェーズ(パース)を行ってツリーを返しています。
-この関数にはF#のソースコードとともに、ファイルのパスを指定する必要があります。
-(単に位置情報として利用されるだけなので)
-指定先のパスにファイルが存在している必要はなく、
-UnixとWindowsどちらの形式でも指定できます:
-*)
-// コンパイラサービスへのサンプル入力
-let input = """
- let foo() =
- let msg = "Hello world"
- if true then
- printfn "%s" msg """
-// Unix形式のファイル名
-let file = "/home/user/Test.fsx"
-
-// サンプルF#コードに対するASTを取得
-let tree = getUntypedTree(file, input)
-(**
-このコードをF# Interactiveで実行した場合、コンソールに `tree;;` と入力すると、
-データ構造に対する文字列表現が表示されることが確認できます。
-ツリーには大量の情報が含まれているため、あまり読みやすいものではありませんが、
-木が動作する様子を想像することはできるでしょう。
-
-`tree` の返値はやはり判別共用体で、2つのケースに分かれます。
-1つはF#のシグネチャファイル( `*.fsi` )を表す `ParsedInput.SigFile` で、
-もう1つは通常のソースコード( `*.fsx` または `*.fs` )を表す
-`ParsedInput.ImplFile` です。
-上記の手順で作成した関数に渡すことができるモジュールや名前空間のシーケンスは
-実装ファイルに含まれています:
-*)
-// 実装ファイルの詳細をチェックする
-match tree with
-| ParsedInput.ImplFile(implFile) ->
- // 宣言を展開してそれぞれを走査する
- let (ParsedImplFileInput(fn, script, name, _, _, modules, _)) = implFile
- visitModulesAndNamespaces modules
-| _ -> failwith "F# インターフェイスファイル (*.fsi) は未サポートです。"
-(**
-まとめ
-------
-このチュートリアルでは型無し抽象構文木に対する基本的な走査方法を紹介しました。
-このトピックは包括的なものであるため、1つの記事ですべてを説明することは不可能です。
-さらに深く理解するためには、型無しASTを活用するツールのよい例として
-[Fantomas project](https://github.com/dungpa/fantomas) を参考にするとよいでしょう。
-実際には今回参照したような情報と、次のチュートリアルで説明する
-[エディタサービス](editor.html) から得られる情報とを
-組み合わせて利用することになるでしょう。
-*)
diff --git a/fcs/docsrc/content/project.fsx b/fcs/docsrc/content/project.fsx
deleted file mode 100644
index 72bf7993f4b..00000000000
--- a/fcs/docsrc/content/project.fsx
+++ /dev/null
@@ -1,373 +0,0 @@
-(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
-(**
-Compiler Services: Project Analysis
-==================================
-
-This tutorial demonstrates how to can analyze a whole project using services provided by the F# compiler.
-
-> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published.
-
-*)
-
-
-(**
-
-Getting whole-project results
------------------------------
-
-As in the [previous tutorial (using untyped AST)](untypedtree.html), we start by referencing
-`FSharp.Compiler.Service.dll`, opening the relevant namespace and creating an instance
-of `InteractiveChecker`:
-
-*)
-// Reference F# compiler API
-#r "FSharp.Compiler.Service.dll"
-#r "FSharp.Compiler.Service.ProjectCracker.dll"
-
-open System
-open System.Collections.Generic
-open FSharp.Compiler.SourceCodeServices
-
-// Create an interactive checker instance
-let checker = FSharpChecker.Create()
-
-(**
-Here are our sample inputs:
-*)
-
-module Inputs =
- open System.IO
-
- let base1 = Path.GetTempFileName()
- let fileName1 = Path.ChangeExtension(base1, ".fs")
- let base2 = Path.GetTempFileName()
- let fileName2 = Path.ChangeExtension(base2, ".fs")
- let dllName = Path.ChangeExtension(base2, ".dll")
- let projFileName = Path.ChangeExtension(base2, ".fsproj")
- let fileSource1 = """
-module M
-
-type C() =
- member x.P = 1
-
-let xxx = 3 + 4
-let fff () = xxx + xxx
- """
- File.WriteAllText(fileName1, fileSource1)
-
- let fileSource2 = """
-module N
-
-open M
-
-type D1() =
- member x.SomeProperty = M.xxx
-
-type D2() =
- member x.SomeProperty = M.fff() + D1().P
-
-// Generate a warning
-let y2 = match 1 with 1 -> M.xxx
- """
- File.WriteAllText(fileName2, fileSource2)
-
-
-(**
-We use `GetProjectOptionsFromCommandLineArgs` to treat two files as a project:
-*)
-
-let projectOptions =
- let sysLib nm =
- if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then
- // file references only valid on Windows
- System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86) +
- @"\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\" + nm + ".dll"
- else
- let sysDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()
- let (++) a b = System.IO.Path.Combine(a,b)
- sysDir ++ nm + ".dll"
-
- let fsCore4300() =
- if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then
- // file references only valid on Windows
- System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86) +
- @"\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.0.0\FSharp.Core.dll"
- else
- sysLib "FSharp.Core"
-
- checker.GetProjectOptionsFromCommandLineArgs
- (Inputs.projFileName,
- [| yield "--simpleresolution"
- yield "--noframework"
- yield "--debug:full"
- yield "--define:DEBUG"
- yield "--optimize-"
- yield "--out:" + Inputs.dllName
- yield "--doc:test.xml"
- yield "--warn:3"
- yield "--fullpaths"
- yield "--flaterrors"
- yield "--target:library"
- yield Inputs.fileName1
- yield Inputs.fileName2
- let references =
- [ sysLib "mscorlib"
- sysLib "System"
- sysLib "System.Core"
- fsCore4300() ]
- for r in references do
- yield "-r:" + r |])
-
-(**
-Now check the entire project (using the files saved on disk):
-*)
-
-let wholeProjectResults = checker.ParseAndCheckProject(projectOptions) |> Async.RunSynchronously
-
-(**
-Now look at the errors and warnings:
-*)
-wholeProjectResults .Errors.Length // 1
-wholeProjectResults.Errors.[0].Message.Contains("Incomplete pattern matches on this expression") // yes it does
-
-wholeProjectResults.Errors.[0].StartLineAlternate // 13
-wholeProjectResults.Errors.[0].EndLineAlternate // 13
-wholeProjectResults.Errors.[0].StartColumn // 15
-wholeProjectResults.Errors.[0].EndColumn // 16
-
-(**
-Now look at the inferred signature for the project:
-*)
-[ for x in wholeProjectResults.AssemblySignature.Entities -> x.DisplayName ] // ["N"; "M"]
-[ for x in wholeProjectResults.AssemblySignature.Entities.[0].NestedEntities -> x.DisplayName ] // ["D1"; "D2"]
-[ for x in wholeProjectResults.AssemblySignature.Entities.[1].NestedEntities -> x.DisplayName ] // ["C"]
-[ for x in wholeProjectResults.AssemblySignature.Entities.[0].MembersFunctionsAndValues -> x.DisplayName ] // ["y"; "y2"]
-
-(**
-You can also get all symbols in the project:
-*)
-let rec allSymbolsInEntities (entities: IList) =
- [ for e in entities do
- yield (e :> FSharpSymbol)
- for x in e.MembersFunctionsAndValues do
- yield (x :> FSharpSymbol)
- for x in e.UnionCases do
- yield (x :> FSharpSymbol)
- for x in e.FSharpFields do
- yield (x :> FSharpSymbol)
- yield! allSymbolsInEntities e.NestedEntities ]
-
-let allSymbols = allSymbolsInEntities wholeProjectResults.AssemblySignature.Entities
-(**
-After checking the whole project, you can access the background results for individual files
-in the project. This will be fast and will not involve any additional checking.
-*)
-
-let backgroundParseResults1, backgroundTypedParse1 =
- checker.GetBackgroundCheckResultsForFileInProject(Inputs.fileName1, projectOptions)
- |> Async.RunSynchronously
-
-
-(**
-You can now resolve symbols in each file:
-*)
-
-let xSymbolUseOpt =
- backgroundTypedParse1.GetSymbolUseAtLocation(9,9,"",["xxx"])
- |> Async.RunSynchronously
-
-let xSymbolUse = xSymbolUseOpt.Value
-
-let xSymbol = xSymbolUse.Symbol
-
-(**
-You can find out more about a symbol by doing type checks on various symbol kinds:
-*)
-
-let xSymbolAsValue =
- match xSymbol with
- | :? FSharpMemberOrFunctionOrValue as xSymbolAsVal -> xSymbolAsVal
- | _ -> failwith "we expected this to be a member, function or value"
-
-
-(**
-For each symbol, you can look up the references to that symbol:
-*)
-let usesOfXSymbol =
- wholeProjectResults.GetUsesOfSymbol(xSymbol)
- |> Async.RunSynchronously
-
-(**
-You can iterate all the defined symbols in the inferred signature and find where they are used:
-*)
-let allUsesOfAllSignatureSymbols =
- [ for s in allSymbols do
- let uses = wholeProjectResults.GetUsesOfSymbol(s) |> Async.RunSynchronously
- yield s.ToString(), uses ]
-
-(**
-You can also look at all the symbols uses in the whole project (including uses of symbols with local scope)
-*)
-let allUsesOfAllSymbols =
- wholeProjectResults.GetAllUsesOfAllSymbols()
- |> Async.RunSynchronously
-
-(**
-You can also request checks of updated versions of files within the project (note that the other files
-in the project are still read from disk, unless you are using the [FileSystem API](filesystem.html)):
-
-*)
-
-let parseResults1, checkAnswer1 =
- checker.ParseAndCheckFileInProject(Inputs.fileName1, 0, Inputs.fileSource1, projectOptions)
- |> Async.RunSynchronously
-
-let checkResults1 =
- match checkAnswer1 with
- | FSharpCheckFileAnswer.Succeeded x -> x
- | _ -> failwith "unexpected aborted"
-
-let parseResults2, checkAnswer2 =
- checker.ParseAndCheckFileInProject(Inputs.fileName2, 0, Inputs.fileSource2, projectOptions)
- |> Async.RunSynchronously
-
-let checkResults2 =
- match checkAnswer2 with
- | FSharpCheckFileAnswer.Succeeded x -> x
- | _ -> failwith "unexpected aborted"
-
-(**
-Again, you can resolve symbols and ask for references:
-*)
-
-let xSymbolUse2Opt =
- checkResults1.GetSymbolUseAtLocation(9,9,"",["xxx"])
- |> Async.RunSynchronously
-
-let xSymbolUse2 = xSymbolUse2Opt.Value
-
-let xSymbol2 = xSymbolUse2.Symbol
-
-let usesOfXSymbol2 =
- wholeProjectResults.GetUsesOfSymbol(xSymbol2)
- |> Async.RunSynchronously
-
-
-(**
-Or ask for all the symbols uses in the file (including uses of symbols with local scope)
-*)
-let allUsesOfAllSymbolsInFile1 =
- checkResults1.GetAllUsesOfAllSymbolsInFile()
- |> Async.RunSynchronously
-
-(**
-Or ask for all the uses of one symbol in one file:
-*)
-let allUsesOfXSymbolInFile1 =
- checkResults1.GetUsesOfSymbolInFile(xSymbol2)
- |> Async.RunSynchronously
-
-let allUsesOfXSymbolInFile2 =
- checkResults2.GetUsesOfSymbolInFile(xSymbol2)
- |> Async.RunSynchronously
-
-(**
-
-Analyzing multiple projects
------------------------------
-
-If you have multiple F# projects to analyze which include references from some projects to others,
-then the simplest way to do this is to build the projects and specify the cross-project references using
-a `-r:path-to-output-of-project.dll` argument in the ProjectOptions. However, this requires the build
-of each project to succeed, producing the DLL file on disk which can be referred to.
-
-In some situations, e.g. in an IDE, you may wish to allow references to other F# projects prior to successful compilation to
-a DLL. To do this, fill in the ProjectReferences entry in ProjectOptions, which recursively specifies the project
-options for dependent projects. Each project reference still needs a corresponding `-r:path-to-output-of-project.dll`
-command line argument in ProjectOptions, along with an entry in ProjectReferences.
-The first element of each tuple in the ProjectReferences entry should be the DLL name, i.e. `path-to-output-of-project.dll`.
-This should be the same as the text used in the `-r` project reference.
-
-When a project reference is used, the analysis will make use of the results of incremental
-analysis of the referenced F# project from source files, without requiring the compilation of these files to DLLs.
-
-To efficiently analyze a set of F# projects which include cross-references, you should populate the ProjectReferences
-correctly and then analyze each project in turn.
-
-*)
-
-(**
-
-> **NOTE:** Project references are disabled if the assembly being referred to contains type provider components -
- specifying the project reference will have no effect beyond forcing the analysis of the project, and the DLL will
- still be required on disk.
-
-*)
-
-(**
-Cracking a legacy project file
------------------------------
-
-F# projects normally use the '.fsproj' project file format.
-A project cracking facility for legacy old-style .fsproj is provided as a separate NuGet package:
-FSharp.Compiler.Service.ProjectCracker.
-
-Projecet cracking for modern project files should be done using a library such as DotNetProjInfo.
-See FsAutoComplete for example code.
-
-The legacy NuGet package `FSharp.Compiler.Service.ProjectCracker` contains a
-library `FSharp.Compiler.Service.ProjectCracker.dll`, which should be
-referenced by your application directly, and an executable
-`FSharp.Compiler.Service.ProjectCrackerTool.exe`, which should be copied
-into the output folder of your application by the build process. If
-you install using Paket or NuGet, then this will be configured for you
-automatically. If not, you should reference the provided `.targets`
-file manually in your application. This can be found in the NuGet
-package at `build/net461/FSharp.Compiler.Service.ProjectCrackerTool.targets`.
-
-The reason for this split was so the analysis of an F# project
-file is performed out of process, in order that the necessary assembly
-binding redirects can be applied without requiring the caller to
-arrange this. In this way MSBuild versions from 4 up to 14 can be
-accommodated transparently.
-
-In this example we get the project options for one of the
-project files in the F# Compiler Service project itself - you should also be able to use this technique
-for any project that builds cleanly using the command line tools 'xbuild' or 'msbuild'.
-
-
-*)
-
-let projectFile = __SOURCE_DIRECTORY__ + @"/../../src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj"
-
-ProjectCracker.GetProjectOptionsFromProjectFile(projectFile)
-
-
-(**
-
-You can also request RELEASE mode and set other build configuration parameters:
-
-*)
-
-ProjectCracker.GetProjectOptionsFromProjectFile(projectFile, [("Configuration", "Release")])
-
-(**
-
-For debugging purposes it is also possible to obtain a detailed log from the assembly resolution process.
-
-*)
-
-let options, logs = ProjectCracker.GetProjectOptionsFromProjectFileLogged(projectFile, [("Configuration", "Release")])
-
-(**
-Summary
--------
-
-As you have seen, the `ParseAndCheckProject` lets you access results of project-wide analysis
-such as symbol references. To learn more about working with symbols, see [Symbols](symbols.html).
-
-Using the FSharpChecker component in multi-project, incremental and interactive editing situations may involve
-knowledge of the [FSharpChecker operations queue](queue.html) and the [FSharpChecker caches](caches.html).
-
-*)
diff --git a/fcs/docsrc/content/symbols.fsx b/fcs/docsrc/content/symbols.fsx
deleted file mode 100644
index 74701e8b73d..00000000000
--- a/fcs/docsrc/content/symbols.fsx
+++ /dev/null
@@ -1,223 +0,0 @@
-(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
-(**
-Compiler Services: Working with symbols
-============================================
-
-This tutorial demonstrates how to work with symbols provided by the F# compiler. See also [project wide analysis](project.html)
-for information on symbol references.
-
-> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published.
-
-As usual we start by referencing `FSharp.Compiler.Service.dll`, opening the relevant namespace and creating an instance
-of `FSharpChecker`:
-
-*)
-// Reference F# compiler API
-#r "FSharp.Compiler.Service.dll"
-
-open System
-open System.IO
-open FSharp.Compiler.SourceCodeServices
-
-// Create an interactive checker instance
-let checker = FSharpChecker.Create()
-
-(**
-
-We now perform type checking on the specified input:
-
-*)
-
-let parseAndTypeCheckSingleFile (file, input) =
- // Get context representing a stand-alone (script) file
- let projOptions, errors =
- checker.GetProjectOptionsFromScript(file, input)
- |> Async.RunSynchronously
-
- let parseFileResults, checkFileResults =
- checker.ParseAndCheckFileInProject(file, 0, input, projOptions)
- |> Async.RunSynchronously
-
- // Wait until type checking succeeds (or 100 attempts)
- match checkFileResults with
- | FSharpCheckFileAnswer.Succeeded(res) -> parseFileResults, res
- | res -> failwithf "Parsing did not finish... (%A)" res
-
-let file = "/home/user/Test.fsx"
-
-(**
-## Getting resolved signature information about the file
-
-After type checking a file, you can access the inferred signature of a project up to and including the
-checking of the given file through the `PartialAssemblySignature` property of the `TypeCheckResults`.
-
-The full signature information is available for modules, types, attributes, members, values, functions,
-union cases, record types, units of measure and other F# language constructs.
-
-The typed expression trees are also available, see [typed tree tutorial](typedtree.html).
-
-*)
-
-let input2 =
- """
-[]
-let foo(x, y) =
- let msg = String.Concat("Hello"," ","world")
- if true then
- printfn "x = %d, y = %d" x y
- printfn "%s" msg
-
-type C() =
- member x.P = 1
- """
-let parseFileResults, checkFileResults =
- parseAndTypeCheckSingleFile(file, input2)
-
-(**
-Now get the partial assembly signature for the code:
-*)
-let partialAssemblySignature = checkFileResults.PartialAssemblySignature
-
-partialAssemblySignature.Entities.Count = 1 // one entity
-
-
-(**
-Now get the entity that corresponds to the module containing the code:
-*)
-let moduleEntity = partialAssemblySignature.Entities.[0]
-
-moduleEntity.DisplayName = "Test"
-
-(**
-Now get the entity that corresponds to the type definition in the code:
-*)
-let classEntity = moduleEntity.NestedEntities.[0]
-
-(**
-Now get the value that corresponds to the function defined in the code:
-*)
-let fnVal = moduleEntity.MembersFunctionsAndValues.[0]
-
-(**
-Now look around at the properties describing the function value. All fo the following evaluate to `true`:
-*)
-fnVal.Attributes.Count = 1
-fnVal.CurriedParameterGroups.Count // 1
-fnVal.CurriedParameterGroups.[0].Count // 2
-fnVal.CurriedParameterGroups.[0].[0].Name // "x"
-fnVal.CurriedParameterGroups.[0].[1].Name // "y"
-fnVal.DeclarationLocation.StartLine // 3
-fnVal.DisplayName // "foo"
-fnVal.DeclaringEntity.Value.DisplayName // "Test"
-fnVal.DeclaringEntity.Value.DeclarationLocation.StartLine // 1
-fnVal.GenericParameters.Count // 0
-fnVal.InlineAnnotation // FSharpInlineAnnotation.OptionalInline
-fnVal.IsActivePattern // false
-fnVal.IsCompilerGenerated // false
-fnVal.IsDispatchSlot // false
-fnVal.IsExtensionMember // false
-fnVal.IsPropertyGetterMethod // false
-fnVal.IsImplicitConstructor // false
-fnVal.IsInstanceMember // false
-fnVal.IsMember // false
-fnVal.IsModuleValueOrMember // true
-fnVal.IsMutable // false
-fnVal.IsPropertySetterMethod // false
-fnVal.IsTypeFunction // false
-
-(**
-Now look at the type of the function if used as a first class value. (Aside: the `CurriedParameterGroups` property contains
-more information like the names of the arguments.)
-*)
-fnVal.FullType // int * int -> unit
-fnVal.FullType.IsFunctionType // int * int -> unit
-fnVal.FullType.GenericArguments.[0] // int * int
-fnVal.FullType.GenericArguments.[0].IsTupleType // int * int
-let argTy1 = fnVal.FullType.GenericArguments.[0].GenericArguments.[0]
-
-argTy1.TypeDefinition.DisplayName // int
-
-(**
-OK, so we got an object representation of the type `int * int -> unit`, and we have seen the first 'int'. We can find out more about the
-type 'int' as follows, determining that it is a named type, which is an F# type abbreviation, `type int = int32`:
-*)
-
-argTy1.HasTypeDefinition
-argTy1.TypeDefinition.IsFSharpAbbreviation // "int"
-
-(**
-We can now look at the right-hand-side of the type abbreviation, which is the type `int32`:
-*)
-
-let argTy1b = argTy1.TypeDefinition.AbbreviatedType
-argTy1b.TypeDefinition.Namespace // Some "Microsoft.FSharp.Core"
-argTy1b.TypeDefinition.CompiledName // "int32"
-
-(**
-Again we can now look through the type abbreviation `type int32 = System.Int32` to get the
-full information about the type:
-*)
-let argTy1c = argTy1b.TypeDefinition.AbbreviatedType
-argTy1c.TypeDefinition.Namespace // Some "SystemCore"
-argTy1c.TypeDefinition.CompiledName // "Int32"
-
-(**
-The type checking results for a file also contain information extracted from the project (or script) options
-used in the compilation, called the `ProjectContext`:
-*)
-let projectContext = checkFileResults.ProjectContext
-
-for assembly in projectContext.GetReferencedAssemblies() do
- match assembly.FileName with
- | None -> printfn "compilation referenced an assembly without a file"
- | Some s -> printfn "compilation references assembly '%s'" s
-
-
-(**
-**Notes:**
-
- - If incomplete code is present, some or all of the attirbutes may not be quite as expected.
- - If some assembly references are missing (which is actually very, very common), then 'IsUnresolved' may
- be true on values, members and/or entites related to external assemblies. You should be sure to make your
- code robust against IsUnresolved exceptions.
-
-*)
-
-(**
-
-## Getting symbolic information about whole projects
-
-To check whole projects, create a checker, then call `parseAndCheckScript`. In this case, we just check
-the project for a single script. By specifying a different "projOptions" you can create
-a specification of a larger project.
-*)
-let parseAndCheckScript (file, input) =
- let projOptions, errors =
- checker.GetProjectOptionsFromScript(file, input)
- |> Async.RunSynchronously
-
- checker.ParseAndCheckProject(projOptions) |> Async.RunSynchronously
-
-(**
-Now do it for a particular input:
-*)
-
-let tmpFile = Path.ChangeExtension(System.IO.Path.GetTempFileName() , "fs")
-File.WriteAllText(tmpFile, input2)
-
-let projectResults = parseAndCheckScript(tmpFile, input2)
-
-
-(**
-Now look at the results:
-*)
-
-let assemblySig = projectResults.AssemblySignature
-
-assemblySig.Entities.Count = 1 // one entity
-assemblySig.Entities.[0].Namespace // one entity
-assemblySig.Entities.[0].DisplayName // "Tmp28D0"
-assemblySig.Entities.[0].MembersFunctionsAndValues.Count // 1
-assemblySig.Entities.[0].MembersFunctionsAndValues.[0].DisplayName // "foo"
-
diff --git a/fcs/docsrc/content/tokenizer.fsx b/fcs/docsrc/content/tokenizer.fsx
deleted file mode 100644
index 7a46a3c91f6..00000000000
--- a/fcs/docsrc/content/tokenizer.fsx
+++ /dev/null
@@ -1,131 +0,0 @@
-(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
-(**
-Compiler Services: Using the F# tokenizer
-=========================================
-
-This tutorial demonstrates how to call the F# language tokenizer. Given F#
-source code, the tokenizer generates a list of source code lines that contain
-information about tokens on each line. For each token, you can get the type
-of the token, exact location as well as color kind of the token (keyword,
-identifier, number, operator, etc.).
-
-> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published
-
-
-Creating the tokenizer
----------------------
-
-To use the tokenizer, reference `FSharp.Compiler.Service.dll` and open the
-`SourceCodeServices` namespace:
-*)
-#r "FSharp.Compiler.Service.dll"
-open FSharp.Compiler.SourceCodeServices
-(**
-Now you can create an instance of `FSharpSourceTokenizer`. The class takes two
-arguments - the first is the list of defined symbols and the second is the
-file name of the source code. The defined symbols are required because the
-tokenizer handles `#if` directives. The file name is required only to specify
-locations of the source code (and it does not have to exist):
-*)
-let sourceTok = FSharpSourceTokenizer([], Some "C:\\test.fsx")
-(**
-Using the `sourceTok` object, we can now (repeatedly) tokenize lines of
-F# source code.
-
-Tokenizing F# code
-------------------
-
-The tokenizer operates on individual lines rather than on the entire source
-file. After getting a token, the tokenizer also returns new state (as `int64` value).
-This can be used to tokenize F# code more efficiently. When source code changes,
-you do not need to re-tokenize the entire file - only the parts that have changed.
-
-### Tokenizing single line
-
-To tokenize a single line, we create a `FSharpLineTokenizer` by calling `CreateLineTokenizer`
-on the `FSharpSourceTokenizer` object that we created earlier:
-*)
-let tokenizer = sourceTok.CreateLineTokenizer("let answer=42")
-(**
-Now, we can write a simple recursive function that calls `ScanToken` on the `tokenizer`
-until it returns `None` (indicating the end of line). When the function suceeds, it
-returns `FSharpTokenInfo` object with all the interesting details:
-*)
-/// Tokenize a single line of F# code
-let rec tokenizeLine (tokenizer:FSharpLineTokenizer) state =
- match tokenizer.ScanToken(state) with
- | Some tok, state ->
- // Print token name
- printf "%s " tok.TokenName
- // Tokenize the rest, in the new state
- tokenizeLine tokenizer state
- | None, state -> state
-(**
-The function returns the new state, which is needed if you need to tokenize multiple lines
-and an earlier line ends with a multi-line comment. As an initial state, we can use `0L`:
-*)
-tokenizeLine tokenizer FSharpTokenizerLexState.Initial
-(**
-The result is a sequence of tokens with names LET, WHITESPACE, IDENT, EQUALS and INT32.
-There is a number of interesting properties on `FSharpTokenInfo` including:
-
- - `CharClass` and `ColorClass` return information about the token category that
- can be used for colorizing F# code.
- - `LeftColumn` and `RightColumn` return the location of the token inside the line.
- - `TokenName` is the name of the token (as defined in the F# lexer)
-
-Note that the tokenizer is stateful - if you want to tokenize single line multiple times,
-you need to call `CreateLineTokenizer` again.
-
-### Tokenizing sample code
-
-To run the tokenizer on a longer sample code or an entire file, you need to read the
-sample input as a collection of `string` values:
-*)
-let lines = """
- // Hello world
- let hello() =
- printfn "Hello world!" """.Split('\r','\n')
-(**
-To tokenize multi-line input, we again need a recursive function that keeps the current
-state. The following function takes the lines as a list of strings (together with line number
-and the current state). We create a new tokenizer for each line and call `tokenizeLine`
-using the state from the *end* of the previous line:
-*)
-/// Print token names for multiple lines of code
-let rec tokenizeLines state count lines =
- match lines with
- | line::lines ->
- // Create tokenizer & tokenize single line
- printfn "\nLine %d" count
- let tokenizer = sourceTok.CreateLineTokenizer(line)
- let state = tokenizeLine tokenizer state
- // Tokenize the rest using new state
- tokenizeLines state (count+1) lines
- | [] -> ()
-(**
-The function simply calls `tokenizeLine` (defined earlier) to print the names of all
-the tokens on each line. We can call it on the previous input with `0L` as the initial
-state and `1` as the number of the first line:
-*)
-lines
-|> List.ofSeq
-|> tokenizeLines FSharpTokenizerLexState.Initial 1
-(**
-Ignoring some unimportant details (like whitespace at the beginning of each line and
-the first line which is just whitespace), the code generates the following output:
-
- [lang=text]
- Line 1
- LINE_COMMENT LINE_COMMENT (...) LINE_COMMENT
- Line 2
- LET WHITESPACE IDENT LPAREN RPAREN WHITESPACE EQUALS
- Line 3
- IDENT WHITESPACE STRING_TEXT (...) STRING_TEXT STRING
-
-It is worth noting that the tokenizer yields multiple `LINE_COMMENT` tokens and multiple
-`STRING_TEXT` tokens for each single comment or string (roughly, one for each word), so
-if you want to get the entire text of a comment/string, you need to concatenate the
-tokens.
-*)
\ No newline at end of file
diff --git a/fcs/docsrc/content/untypedtree.fsx b/fcs/docsrc/content/untypedtree.fsx
deleted file mode 100644
index 959e14fb944..00000000000
--- a/fcs/docsrc/content/untypedtree.fsx
+++ /dev/null
@@ -1,241 +0,0 @@
-(*** hide ***)
-#I "../../../artifacts/bin/fcs/net461"
-(**
-Compiler Services: Processing untyped syntax tree
-=================================================
-
-This tutorial demonstrates how to get the untyped abstract syntax tree (AST)
-for F# code and how to walk over the tree. This can be used for creating tools
-such as code formatter, basic refactoring or code navigation tools. The untyped
-syntax tree contains information about the code structure, but does not contain
-types and there are some ambiguities that are resolved only later by the type
-checker. You can also combine the untyped AST information with the API available
-from [editor services](editor.html).
-
-> **NOTE:** The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published
-
-
-Getting the untyped AST
------------------------
-
-To access the untyped AST, you need to create an instance of `FSharpChecker`.
-This type represents a context for type checking and parsing and corresponds either
-to a stand-alone F# script file (e.g. opened in Visual Studio) or to a loaded project
-file with multiple files. Once you have an instance of `FSharpChecker`, you can
-use it to perform "untyped parse" which is the first step of type-checking. The
-second phase is "typed parse" and is used by [editor services](editor.html).
-
-To use the interactive checker, reference `FSharp.Compiler.Service.dll` and open the
-`SourceCodeServices` namespace:
-*)
-#r "FSharp.Compiler.Service.dll"
-open System
-open FSharp.Compiler.SourceCodeServices
-(**
-
-### Performing untyped parse
-
-The untyped parse operation is very fast (compared to type checking, which can
-take notable amount of time) and so we can perform it synchronously. First, we
-need to create `FSharpChecker` - the constructor takes an argument that
-can be used to notify the checker about file changes (which we ignore).
-
-*)
-// Create an interactive checker instance
-let checker = FSharpChecker.Create()
-(**
-
-To get the AST, we define a function that takes file name and the source code
-(the file is only used for location information and does not have to exist).
-We first need to get "interactive checker options" which represents the context.
-For simple tasks, you can use `GetProjectOptionsFromScriptRoot` which infers
-the context for a script file. Then we use the `ParseFile` method and
-return the `ParseTree` property:
-
-*)
-/// Get untyped tree for a specified input
-let getUntypedTree (file, input) =
- // Get compiler options for the 'project' implied by a single script file
- let projOptions, errors =
- checker.GetProjectOptionsFromScript(file, input)
- |> Async.RunSynchronously
-
- let parsingOptions, _errors = checker.GetParsingOptionsFromProjectOptions(projOptions)
-
- // Run the first phase (untyped parsing) of the compiler
- let parseFileResults =
- checker.ParseFile(file, input, parsingOptions)
- |> Async.RunSynchronously
-
- match parseFileResults.ParseTree with
- | Some tree -> tree
- | None -> failwith "Something went wrong during parsing!"
-
-(**
-
-Walking over the AST
---------------------
-
-The abstract syntax tree is defined as a number of discriminated unions that represent
-different syntactical elements (such as expressions, patterns, declarations etc.). The best
-way to understand the AST is to look at the definitions in [`ast.fs` in the source
-code](https://github.com/fsharp/fsharp/blob/master/src/fsharp/ast.fs#L464).
-
-The relevant parts are in the following namespace:
-*)
-open FSharp.Compiler.Ast
-(**
-
-When processing the AST, you will typically write a number of mutually recursive functions
-that pattern match on the different syntactical elements. There is a number of elements
-that need to be supported - the top-level element is module or namespace declaration,
-containing declarations inside a module (let bindings, types etc.). A let declaration inside
-a module then contains expression, which can contain patterns.
-
-### Walking over patterns and expressions
-
-We start by looking at functions that walk over expressions and patterns - as we walk,
-we print information about the visited elements. For patterns, the input is of type
-`SynPat` and has a number of cases including `Wild` (for `_` pattern), `Named` (for
-` as name`) and `LongIdent` (for a `Foo.Bar` name). Note that the parsed pattern
-is occasionally more complex than what is in the source code (in particular, `Named` is
-used more often):
-*)
-/// Walk over a pattern - this is for example used in
-/// let = or in the 'match' expression
-let rec visitPattern = function
- | SynPat.Wild(_) ->
- printfn " .. underscore pattern"
- | SynPat.Named(pat, name, _, _, _) ->
- visitPattern pat
- printfn " .. named as '%s'" name.idText
- | SynPat.LongIdent(LongIdentWithDots(ident, _), _, _, _, _, _) ->
- let names = String.concat "." [ for i in ident -> i.idText ]
- printfn " .. identifier: %s" names
- | pat -> printfn " .. other pattern: %A" pat
-(**
-The function is recursive (for nested patterns such as `(foo, _) as bar`), but it does not
-call any of the functions defined later (because patterns cannot contain other syntactical
-elements).
-
-The next function iterates over expressions - this is where most of the work would be and
-there are around 20 cases to cover (type `SynExpr.` and you'll get completion with other
-options). In the following, we only show how to handle `if .. then ..` and `let .. = ...`:
-*)
-/// Walk over an expression - if expression contains two or three
-/// sub-expressions (two if the 'else' branch is missing), let expression
-/// contains pattern and two sub-expressions
-let rec visitExpression = function
- | SynExpr.IfThenElse(cond, trueBranch, falseBranchOpt, _, _, _, _) ->
- // Visit all sub-expressions
- printfn "Conditional:"
- visitExpression cond
- visitExpression trueBranch
- falseBranchOpt |> Option.iter visitExpression
-
- | SynExpr.LetOrUse(_, _, bindings, body, _) ->
- // Visit bindings (there may be multiple
- // for 'let .. = .. and .. = .. in ...'
- printfn "LetOrUse with the following bindings:"
- for binding in bindings do
- let (Binding(access, kind, inlin, mutabl, attrs, xmlDoc,
- data, pat, retInfo, init, m, sp)) = binding
- visitPattern pat
- visitExpression init
- // Visit the body expression
- printfn "And the following body:"
- visitExpression body
- | expr -> printfn " - not supported expression: %A" expr
-(**
-The `visitExpression` function will be called from a function that visits all top-level
-declarations inside a module. In this tutorial, we ignore types and members, but that would
-be another source of calls to `visitExpression`.
-
-### Walking over declarations
-
-As mentioned earlier, the AST of a file contains a number of module or namespace declarations
-(top-level node) that contain declarations inside a module (let bindings or types) or inisde
-a namespace (just types). The following functions walks over declarations - we ignore types,
-nested modules and all other elements and look only at top-level `let` bindings (values and
-functions):
-*)
-/// Walk over a list of declarations in a module. This is anything
-/// that you can write as a top-level inside module (let bindings,
-/// nested modules, type declarations etc.)
-let visitDeclarations decls =
- for declaration in decls do
- match declaration with
- | SynModuleDecl.Let(isRec, bindings, range) ->
- // Let binding as a declaration is similar to let binding
- // as an expression (in visitExpression), but has no body
- for binding in bindings do
- let (Binding(access, kind, inlin, mutabl, attrs, xmlDoc,
- data, pat, retInfo, body, m, sp)) = binding
- visitPattern pat
- visitExpression body
- | _ -> printfn " - not supported declaration: %A" declaration
-(**
-The `visitDeclarations` function will be called from a function that walks over a
-sequence of module or namespace declarations. This corresponds, for example, to a file
-with multiple `namespace Foo` declarations:
-*)
-/// Walk over all module or namespace declarations
-/// (basically 'module Foo =' or 'namespace Foo.Bar')
-/// Note that there is one implicitly, even if the file
-/// does not explicitly define it..
-let visitModulesAndNamespaces modulesOrNss =
- for moduleOrNs in modulesOrNss do
- let (SynModuleOrNamespace(lid, isRec, isMod, decls, xml, attrs, _, m)) = moduleOrNs
- printfn "Namespace or module: %A" lid
- visitDeclarations decls
-(**
-Now that we have functions that walk over the elements of the AST (starting from declaration,
-down to expressions and patterns), we can get AST of a sample input and run the above function.
-
-Putting things together
------------------------
-
-As already discussed, the `getUntypedTree` function uses `FSharpChecker` to run the first
-phase (parsing) on the AST and get back the tree. The function requires F# source code together
-with location of the file. The location does not have to exist (it is used only for location
-information) and it can be in both Unix and Windows formats:
-*)
-// Sample input for the compiler service
-let input = """
- let foo() =
- let msg = "Hello world"
- if true then
- printfn "%s" msg """
-// File name in Unix format
-let file = "/home/user/Test.fsx"
-
-// Get the AST of sample F# code
-let tree = getUntypedTree(file, input)
-(**
-When you run the code in F# interactive, you can enter `tree;;` in the interactive console and
-see pretty printed representation of the data structure - the tree contains a lot of information,
-so this is not particularly readable, but it gives you good idea about how the tree looks.
-
-The returned `tree` value is again a discriminated union that can be two different cases - one case
-is `ParsedInput.SigFile` which represents F# signature file (`*.fsi`) and the other one is
-`ParsedInput.ImplFile` representing regular source code (`*.fsx` or `*.fs`). The implementation
-file contains a sequence of modules or namespaces that we can pass to the function implemented
-in the previous step:
-*)
-// Extract implementation file details
-match tree with
-| ParsedInput.ImplFile(implFile) ->
- // Extract declarations and walk over them
- let (ParsedImplFileInput(fn, script, name, _, _, modules, _)) = implFile
- visitModulesAndNamespaces modules
-| _ -> failwith "F# Interface file (*.fsi) not supported."
-(**
-Summary
--------
-In this tutorial, we looked at basic of working with the untyped abstract syntax tree. This is a
-comprehensive topic, so it is not possible to explain everything in a single article. The
-[Fantomas project](https://github.com/dungpa/fantomas) is a good example of tool based on the untyped
-AST that can help you understand more. In practice, it is also useful to combine the information here
-with some information you can obtain from the [editor services](editor.html) discussed in the next
-tutorial.
-*)
diff --git a/fcs/download-paket.ps1 b/fcs/download-paket.ps1
deleted file mode 100644
index 4541168012b..00000000000
--- a/fcs/download-paket.ps1
+++ /dev/null
@@ -1,15 +0,0 @@
-$paketurl="https://github.com/fsprojects/Paket/releases/download/5.215.0/paket.exe"
-$paketdir = Join-Path $PSScriptRoot ".paket"
-$paketpath = Join-Path $paketdir "paket.exe"
-
-# Enable TLS 1.2 and TLS 1.1 as Security Protocols
-[Net.ServicePointManager]::SecurityProtocol = `
- [Net.SecurityProtocolType]::Tls12,
- [Net.SecurityProtocolType]::Tls11;
-
-if (-not (Test-Path "$paketpath")) {
- if (-not (Test-Path "$paketdir")) {
- mkdir "$paketdir"
- }
- Invoke-WebRequest -Uri $paketurl -OutFile "$paketpath"
-}
diff --git a/fcs/download-paket.sh b/fcs/download-paket.sh
deleted file mode 100755
index 2825ac4d5ae..00000000000
--- a/fcs/download-paket.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env bash
-
-source="${BASH_SOURCE[0]}"
-
-# resolve $source until the file is no longer a symlink
-while [[ -h "$source" ]]; do
- scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
- source="$(readlink "$source")"
- # if $source was a relative symlink, we need to resolve it relative to the path where the
- # symlink file was located
- [[ $source != /* ]] && source="$scriptroot/$source"
-done
-scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
-
-paketurl=https://github.com/fsprojects/Paket/releases/download/5.215.0/paket.exe
-paketdir=$scriptroot/.paket
-paketpath=$paketdir/paket.exe
-if [ ! -e "$paketpath" ]; then
- if [ ! -e "$paketdir" ]; then
- mkdir "$paketdir"
- fi
- curl -o "$paketpath" -L $paketurl
-fi
diff --git a/fcs/misc/logo.pdn b/fcs/misc/logo.pdn
deleted file mode 100644
index bc47490f6e9..00000000000
Binary files a/fcs/misc/logo.pdn and /dev/null differ
diff --git a/fcs/netfx.props b/fcs/netfx.props
index 064f29b1809..45cd945c14f 100644
--- a/fcs/netfx.props
+++ b/fcs/netfx.props
@@ -20,6 +20,8 @@
$(BaseFrameworkPathOverrideForMono)/4.6.2-api
$(BaseFrameworkPathOverrideForMono)/4.7-api
$(BaseFrameworkPathOverrideForMono)/4.7.1-api
+ $(BaseFrameworkPathOverrideForMono)/4.7.2-api
+ $(BaseFrameworkPathOverrideForMono)/4.8-api
true
diff --git a/fcs/paket.dependencies b/fcs/paket.dependencies
deleted file mode 100644
index d23e0010e76..00000000000
--- a/fcs/paket.dependencies
+++ /dev/null
@@ -1,6 +0,0 @@
-framework: net461
-
-source https://www.nuget.org/api/v2/
-
-nuget FAKE 5.8.4
-nuget FSharp.Formatting
diff --git a/fcs/paket.lock b/fcs/paket.lock
deleted file mode 100644
index 85f5ff5efec..00000000000
--- a/fcs/paket.lock
+++ /dev/null
@@ -1,19 +0,0 @@
-RESTRICTION: == net461
-NUGET
- remote: https://www.nuget.org/api/v2
- FAKE (5.8.4)
- FSharp.Compiler.Service (27.0.1)
- FSharp.Core (>= 4.5.2)
- System.Collections.Immutable (>= 1.5)
- System.Reflection.Metadata (>= 1.6)
- System.ValueTuple (>= 4.4)
- FSharp.Core (4.6.2)
- FSharp.Formatting (3.1)
- FSharp.Compiler.Service (>= 27.0.1 < 28.0)
- Microsoft.AspNet.Razor (>= 3.2.7 < 4.0)
- System.ValueTuple (>= 4.5 < 5.0)
- Microsoft.AspNet.Razor (3.2.7)
- System.Collections.Immutable (1.5)
- System.Reflection.Metadata (1.6)
- System.Collections.Immutable (>= 1.5)
- System.ValueTuple (4.5)
diff --git a/fcs/samples/EditorService/Program.fs b/fcs/samples/EditorService/Program.fs
deleted file mode 100644
index e3ab70185c3..00000000000
--- a/fcs/samples/EditorService/Program.fs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Open the namespace with InteractiveChecker type
-open System
-open FSharp.Compiler
-open FSharp.Compiler.SourceCodeServices
-open FSharp.Compiler.QuickParse
-
-// Create an interactive checker instance (ignore notifications)
-let checker = FSharpChecker.Create()
-
-let parseWithTypeInfo (file, input) =
- let input = FSharp.Compiler.Text.SourceText.ofString input
- let checkOptions, _errors = checker.GetProjectOptionsFromScript(file, input) |> Async.RunSynchronously
- let parsingOptions, _errors = checker.GetParsingOptionsFromProjectOptions(checkOptions)
- let untypedRes = checker.ParseFile(file, input, parsingOptions) |> Async.RunSynchronously
-
- match checker.CheckFileInProject(untypedRes, file, 0, input, checkOptions) |> Async.RunSynchronously with
- | FSharpCheckFileAnswer.Succeeded(res) -> untypedRes, res
- | res -> failwithf "Parsing did not finish... (%A)" res
-
-// ----------------------------------------------------------------------------
-// Example
-// ----------------------------------------------------------------------------
-
-let input =
- """
- let foo() =
- let msg = "Hello world"
- if true then
- printfn "%s" msg.
- """
-let inputLines = input.Split('\n')
-let file = "/home/user/Test.fsx"
-
-let identTokenTag = FSharpTokenTag.Identifier
-let untyped, parsed = parseWithTypeInfo (file, input)
-// Get tool tip at the specified location
-let tip = parsed.GetToolTipText(2, 7, inputLines.[1], [ "foo" ], identTokenTag)
-
-printfn "%A" tip
-
-let partialName = GetPartialLongNameEx(inputLines.[4], 23)
-
-// Get declarations (autocomplete) for a location
-let decls =
- parsed.GetDeclarationListInfo(Some untyped, 5, inputLines.[4], partialName, (fun () -> []))
- |> Async.RunSynchronously
-
-for item in decls.Items do
- printfn " - %s" item.Name
diff --git a/fcs/samples/UntypedTree/Program.fs b/fcs/samples/UntypedTree/Program.fs
deleted file mode 100644
index ba6afb2dd2b..00000000000
--- a/fcs/samples/UntypedTree/Program.fs
+++ /dev/null
@@ -1,94 +0,0 @@
-// Open the namespace with InteractiveChecker type
-open System
-open FSharp.Compiler.SourceCodeServices
-
-
-// Create a checker instance (ignore notifications)
-let checker = FSharpChecker.Create()
-
-// ------------------------------------------------------------------
-
-// Get untyped tree for a specified input
-let getUntypedTree (file, input) =
- let parsingOptions = { FSharpParsingOptions.Default with SourceFiles = [| file |] }
- let untypedRes = checker.ParseFile(file, FSharp.Compiler.Text.SourceText.ofString input, parsingOptions) |> Async.RunSynchronously
- match untypedRes.ParseTree with
- | Some tree -> tree
- | None -> failwith "Something went wrong during parsing!"
-
-// ------------------------------------------------------------------
-
-open FSharp.Compiler.Ast
-
-/// Walk over all module or namespace declarations
-/// (basically 'module Foo =' or 'namespace Foo.Bar')
-/// Note that there is one implicitly, even if the file
-/// does not explicitly define it..
-let rec visitModulesAndNamespaces modulesOrNss =
- for moduleOrNs in modulesOrNss do
- let (SynModuleOrNamespace(lid, isRec, isModule, decls, xmlDoc, attribs, synAccess, m)) = moduleOrNs
- printfn "Namespace or module: %A" lid
- visitDeclarations decls
-
-/// Walk over a pattern - this is for example used in
-/// let = or in the 'match' expression
-and visitPattern = function
- | SynPat.Wild(_) ->
- printfn " .. underscore pattern"
- | SynPat.Named(pat, name, _, _, _) ->
- visitPattern pat
- printfn " .. named as '%s'" name.idText
- | SynPat.LongIdent(LongIdentWithDots(ident, _), _, _, _, _, _) ->
- printfn " identifier: %s" (String.concat "." [ for i in ident -> i.idText ])
- | pat -> printfn " - not supported pattern: %A" pat
-
-/// Walk over an expression - the most interesting part :-)
-and visitExpression = function
- | SynExpr.IfThenElse(cond, trueBranch, falseBranchOpt, _, _, _, _) ->
- printfn "Conditional:"
- visitExpression cond
- visitExpression trueBranch
- falseBranchOpt |> Option.iter visitExpression
-
- | SynExpr.LetOrUse(_, _, bindings, body, _) ->
- printfn "LetOrUse with the following bindings:"
- for binding in bindings do
- let (Binding(access, kind, inlin, mutabl, attrs, xmlDoc, data, pat, retInfo, body, m, sp)) = binding
- visitPattern pat
- printfn "And the following body:"
- visitExpression body
- | expr -> printfn " - not supported expression: %A" expr
-
-/// Walk over a list of declarations in a module. This is anything
-/// that you can write as a top-level inside module (let bindings,
-/// nested modules, type declarations etc.)
-and visitDeclarations decls =
- for declaration in decls do
- match declaration with
- | SynModuleDecl.Let(isRec, bindings, range) ->
- for binding in bindings do
- let (Binding(access, kind, inlin, mutabl, attrs, xmlDoc, data, pat, retInfo, body, m, sp)) = binding
- visitPattern pat
- visitExpression body
- | _ -> printfn " - not supported declaration: %A" declaration
-
-
-// ------------------------------------------------------------------
-
-// Sample input for the compiler service
-let input = """
- let foo() =
- let msg = "Hello world"
- if true then
- printfn "%s" msg """
-let file = "/home/user/Test.fsx"
-
-let tree = getUntypedTree(file, input)
-
-// Testing: Print the AST to see what it looks like
-// tree |> printfn "%A"
-
-match tree with
-| ParsedInput.ImplFile(ParsedImplFileInput(file, isScript, qualName, pragmas, hashDirectives, modules, b)) ->
- visitModulesAndNamespaces modules
-| _ -> failwith "F# Interface file (*.fsi) not supported."
\ No newline at end of file
diff --git a/global.json b/global.json
index 341cf084998..68a4afce807 100644
--- a/global.json
+++ b/global.json
@@ -1,16 +1,18 @@
{
+ "sdk": {
+ "version": "6.0.100"
+ },
"tools": {
- "dotnet": "3.0.100-preview6-012264",
+ "dotnet": "5.0.100",
"vs": {
- "version": "16.1",
+ "version": "16.8",
"components": [
- "Microsoft.Net.Core.Component.SDK.2.1",
"Microsoft.VisualStudio.Component.FSharp"
]
}
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19380.3",
+ "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.20630.2",
"Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19069.2"
}
}
diff --git a/icon.png b/icon.png
new file mode 100644
index 00000000000..8a2b81b9eb6
Binary files /dev/null and b/icon.png differ
diff --git a/mono/FSharp.Build/Makefile b/mono/FSharp.Build/Makefile
deleted file mode 100644
index 4fef5306a1f..00000000000
--- a/mono/FSharp.Build/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-NAME=FSharp.Build
-ASSEMBLY = $(NAME).dll
-TOKEN=$(SIGN_TOKEN)
-
-include ../config.make
-
-install: install-sdk-lib
-
diff --git a/mono/FSharp.Compiler.Interactive.Settings/Makefile b/mono/FSharp.Compiler.Interactive.Settings/Makefile
deleted file mode 100644
index bb894b51662..00000000000
--- a/mono/FSharp.Compiler.Interactive.Settings/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-NAME=FSharp.Compiler.Interactive.Settings
-ASSEMBLY = $(NAME).dll
-TOKEN=$(SIGN_TOKEN)
-
-include ../config.make
-
-install: install-sdk-lib
-
-
-
-
diff --git a/mono/FSharp.Compiler.Private/Makefile b/mono/FSharp.Compiler.Private/Makefile
deleted file mode 100644
index 88a3d797b06..00000000000
--- a/mono/FSharp.Compiler.Private/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-NAME=FSharp.Compiler.Private
-ASSEMBLY = $(NAME).dll
-TOKEN=$(SIGN_TOKEN)
-
-include ../config.make
-
-install: install-sdk-lib
-
-
-
diff --git a/mono/FSharp.Compiler.Server.Shared/Makefile b/mono/FSharp.Compiler.Server.Shared/Makefile
deleted file mode 100644
index 213bc156d3f..00000000000
--- a/mono/FSharp.Compiler.Server.Shared/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-NAME=FSharp.Compiler.Server.Shared
-ASSEMBLY = $(NAME).dll
-TOKEN=$(SIGN_TOKEN)
-
-include ../config.make
-
-install: install-sdk-lib
-
-
-
-
diff --git a/mono/FSharp.Core/Makefile b/mono/FSharp.Core/Makefile
deleted file mode 100644
index 13667a91613..00000000000
--- a/mono/FSharp.Core/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-NAME=FSharp.Core
-ASSEMBLY = $(NAME).dll
-DELAY_SIGN=1
-TOKEN=$(FSCORE_DELAY_SIGN_TOKEN)
-
-include ../config.make
-
-install: install-sdk-lib
-
-
diff --git a/mono/Fsc/Makefile b/mono/Fsc/Makefile
deleted file mode 100644
index 1d55380927a..00000000000
--- a/mono/Fsc/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-NAME=fsc
-ASSEMBLY = $(NAME).exe
-TOKEN=$(SIGN_TOKEN)
-
-include ../config.make
-
-install: install-bin
-
-
-
diff --git a/mono/dependencies/2.1/MonoAndroid/System.Core.dll b/mono/dependencies/2.1/MonoAndroid/System.Core.dll
deleted file mode 100644
index 3ddcf7dbb05..00000000000
Binary files a/mono/dependencies/2.1/MonoAndroid/System.Core.dll and /dev/null differ
diff --git a/mono/dependencies/2.1/MonoAndroid/System.Numerics.dll b/mono/dependencies/2.1/MonoAndroid/System.Numerics.dll
deleted file mode 100644
index 4674335b695..00000000000
Binary files a/mono/dependencies/2.1/MonoAndroid/System.Numerics.dll and /dev/null differ
diff --git a/mono/dependencies/2.1/MonoAndroid/System.dll b/mono/dependencies/2.1/MonoAndroid/System.dll
deleted file mode 100644
index 481cce72ccd..00000000000
Binary files a/mono/dependencies/2.1/MonoAndroid/System.dll and /dev/null differ
diff --git a/mono/dependencies/2.1/MonoAndroid/mscorlib.dll b/mono/dependencies/2.1/MonoAndroid/mscorlib.dll
deleted file mode 100644
index f1b625ddfbf..00000000000
Binary files a/mono/dependencies/2.1/MonoAndroid/mscorlib.dll and /dev/null differ
diff --git a/mono/dependencies/2.1/MonoDroid.FSharp.targets b/mono/dependencies/2.1/MonoDroid.FSharp.targets
deleted file mode 100644
index 540e71418ab..00000000000
--- a/mono/dependencies/2.1/MonoDroid.FSharp.targets
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
- MonoAndroid
- v1.0
- v2.2
- SdkOnly
-
-
-
-
-
\ No newline at end of file
diff --git a/mono/dependencies/2.1/XamarinMac/System.Core.dll b/mono/dependencies/2.1/XamarinMac/System.Core.dll
deleted file mode 100644
index 6e391ff4713..00000000000
Binary files a/mono/dependencies/2.1/XamarinMac/System.Core.dll and /dev/null differ
diff --git a/mono/dependencies/2.1/XamarinMac/System.Numerics.dll b/mono/dependencies/2.1/XamarinMac/System.Numerics.dll
deleted file mode 100644
index 122c785ce2b..00000000000
Binary files a/mono/dependencies/2.1/XamarinMac/System.Numerics.dll and /dev/null differ
diff --git a/mono/dependencies/2.1/XamarinMac/System.dll b/mono/dependencies/2.1/XamarinMac/System.dll
deleted file mode 100644
index 18065042a50..00000000000
Binary files a/mono/dependencies/2.1/XamarinMac/System.dll and /dev/null differ
diff --git a/mono/dependencies/2.1/XamarinMac/mscorlib.dll b/mono/dependencies/2.1/XamarinMac/mscorlib.dll
deleted file mode 100644
index f1a475fffee..00000000000
Binary files a/mono/dependencies/2.1/XamarinMac/mscorlib.dll and /dev/null differ
diff --git a/mono/fsi/Makefile b/mono/fsi/Makefile
deleted file mode 100644
index f188ef02184..00000000000
--- a/mono/fsi/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-NAME=fsi
-ASSEMBLY = $(NAME).exe
-TOKEN=$(SIGN_TOKEN)
-
-include ../config.make
-
-install: install-bin
-
-
-
diff --git a/mono/fsiAnyCpu/Makefile b/mono/fsiAnyCpu/Makefile
deleted file mode 100644
index 11b66f9d477..00000000000
--- a/mono/fsiAnyCpu/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-NAME=fsiAnyCpu
-ASSEMBLY = $(NAME).exe
-TOKEN=$(SIGN_TOKEN)
-
-include ../config.make
-
-install: install-bin
-
-
-
diff --git a/mono/install-sh b/mono/install-sh
deleted file mode 100755
index 6781b987bdb..00000000000
--- a/mono/install-sh
+++ /dev/null
@@ -1,520 +0,0 @@
-#!/bin/sh
-# install - install a program, script, or datafile
-
-scriptversion=2009-04-28.21; # UTC
-
-# This originates from X11R5 (mit/util/scripts/install.sh), which was
-# later released in X11R6 (xc/config/util/install.sh) with the
-# following copyright and license.
-#
-# Copyright (C) 1994 X Consortium
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to
-# deal in the Software without restriction, including without limitation the
-# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-# sell copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
-# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-# Except as contained in this notice, the name of the X Consortium shall not
-# be used in advertising or otherwise to promote the sale, use or other deal-
-# ings in this Software without prior written authorization from the X Consor-
-# tium.
-#
-#
-# FSF changes to this file are in the public domain.
-#
-# Calling this script install-sh is preferred over install.sh, to prevent
-# `make' implicit rules from creating a file called install from it
-# when there is no Makefile.
-#
-# This script is compatible with the BSD install script, but was written
-# from scratch.
-
-nl='
-'
-IFS=" "" $nl"
-
-# set DOITPROG to echo to test this script
-
-# Don't use :- since 4.3BSD and earlier shells don't like it.
-doit=${DOITPROG-}
-if test -z "$doit"; then
- doit_exec=exec
-else
- doit_exec=$doit
-fi
-
-# Put in absolute file names if you don't have them in your path;
-# or use environment vars.
-
-chgrpprog=${CHGRPPROG-chgrp}
-chmodprog=${CHMODPROG-chmod}
-chownprog=${CHOWNPROG-chown}
-cmpprog=${CMPPROG-cmp}
-cpprog=${CPPROG-cp}
-mkdirprog=${MKDIRPROG-mkdir}
-mvprog=${MVPROG-mv}
-rmprog=${RMPROG-rm}
-stripprog=${STRIPPROG-strip}
-
-posix_glob='?'
-initialize_posix_glob='
- test "$posix_glob" != "?" || {
- if (set -f) 2>/dev/null; then
- posix_glob=
- else
- posix_glob=:
- fi
- }
-'
-
-posix_mkdir=
-
-# Desired mode of installed file.
-mode=0755
-
-chgrpcmd=
-chmodcmd=$chmodprog
-chowncmd=
-mvcmd=$mvprog
-rmcmd="$rmprog -f"
-stripcmd=
-
-src=
-dst=
-dir_arg=
-dst_arg=
-
-copy_on_change=false
-no_target_directory=
-
-usage="\
-Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
- or: $0 [OPTION]... SRCFILES... DIRECTORY
- or: $0 [OPTION]... -t DIRECTORY SRCFILES...
- or: $0 [OPTION]... -d DIRECTORIES...
-
-In the 1st form, copy SRCFILE to DSTFILE.
-In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
-In the 4th, create DIRECTORIES.
-
-Options:
- --help display this help and exit.
- --version display version info and exit.
-
- -c (ignored)
- -C install only if different (preserve the last data modification time)
- -d create directories instead of installing files.
- -g GROUP $chgrpprog installed files to GROUP.
- -m MODE $chmodprog installed files to MODE.
- -o USER $chownprog installed files to USER.
- -s $stripprog installed files.
- -t DIRECTORY install into DIRECTORY.
- -T report an error if DSTFILE is a directory.
-
-Environment variables override the default commands:
- CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
- RMPROG STRIPPROG
-"
-
-while test $# -ne 0; do
- case $1 in
- -c) ;;
-
- -C) copy_on_change=true;;
-
- -d) dir_arg=true;;
-
- -g) chgrpcmd="$chgrpprog $2"
- shift;;
-
- --help) echo "$usage"; exit $?;;
-
- -m) mode=$2
- case $mode in
- *' '* | *' '* | *'
-'* | *'*'* | *'?'* | *'['*)
- echo "$0: invalid mode: $mode" >&2
- exit 1;;
- esac
- shift;;
-
- -o) chowncmd="$chownprog $2"
- shift;;
-
- -s) stripcmd=$stripprog;;
-
- -t) dst_arg=$2
- shift;;
-
- -T) no_target_directory=true;;
-
- --version) echo "$0 $scriptversion"; exit $?;;
-
- --) shift
- break;;
-
- -*) echo "$0: invalid option: $1" >&2
- exit 1;;
-
- *) break;;
- esac
- shift
-done
-
-if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
- # When -d is used, all remaining arguments are directories to create.
- # When -t is used, the destination is already specified.
- # Otherwise, the last argument is the destination. Remove it from $@.
- for arg
- do
- if test -n "$dst_arg"; then
- # $@ is not empty: it contains at least $arg.
- set fnord "$@" "$dst_arg"
- shift # fnord
- fi
- shift # arg
- dst_arg=$arg
- done
-fi
-
-if test $# -eq 0; then
- if test -z "$dir_arg"; then
- echo "$0: no input file specified." >&2
- exit 1
- fi
- # It's OK to call `install-sh -d' without argument.
- # This can happen when creating conditional directories.
- exit 0
-fi
-
-if test -z "$dir_arg"; then
- trap '(exit $?); exit' 1 2 13 15
-
- # Set umask so as not to create temps with too-generous modes.
- # However, 'strip' requires both read and write access to temps.
- case $mode in
- # Optimize common cases.
- *644) cp_umask=133;;
- *755) cp_umask=22;;
-
- *[0-7])
- if test -z "$stripcmd"; then
- u_plus_rw=
- else
- u_plus_rw='% 200'
- fi
- cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
- *)
- if test -z "$stripcmd"; then
- u_plus_rw=
- else
- u_plus_rw=,u+rw
- fi
- cp_umask=$mode$u_plus_rw;;
- esac
-fi
-
-for src
-do
- # Protect names starting with `-'.
- case $src in
- -*) src=./$src;;
- esac
-
- if test -n "$dir_arg"; then
- dst=$src
- dstdir=$dst
- test -d "$dstdir"
- dstdir_status=$?
- else
-
- # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
- # might cause directories to be created, which would be especially bad
- # if $src (and thus $dsttmp) contains '*'.
- if test ! -f "$src" && test ! -d "$src"; then
- echo "$0: $src does not exist." >&2
- exit 1
- fi
-
- if test -z "$dst_arg"; then
- echo "$0: no destination specified." >&2
- exit 1
- fi
-
- dst=$dst_arg
- # Protect names starting with `-'.
- case $dst in
- -*) dst=./$dst;;
- esac
-
- # If destination is a directory, append the input filename; won't work
- # if double slashes aren't ignored.
- if test -d "$dst"; then
- if test -n "$no_target_directory"; then
- echo "$0: $dst_arg: Is a directory" >&2
- exit 1
- fi
- dstdir=$dst
- dst=$dstdir/`basename "$src"`
- dstdir_status=0
- else
- # Prefer dirname, but fall back on a substitute if dirname fails.
- dstdir=`
- (dirname "$dst") 2>/dev/null ||
- expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$dst" : 'X\(//\)[^/]' \| \
- X"$dst" : 'X\(//\)$' \| \
- X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
- echo X"$dst" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'
- `
-
- test -d "$dstdir"
- dstdir_status=$?
- fi
- fi
-
- obsolete_mkdir_used=false
-
- if test $dstdir_status != 0; then
- case $posix_mkdir in
- '')
- # Create intermediate dirs using mode 755 as modified by the umask.
- # This is like FreeBSD 'install' as of 1997-10-28.
- umask=`umask`
- case $stripcmd.$umask in
- # Optimize common cases.
- *[2367][2367]) mkdir_umask=$umask;;
- .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
-
- *[0-7])
- mkdir_umask=`expr $umask + 22 \
- - $umask % 100 % 40 + $umask % 20 \
- - $umask % 10 % 4 + $umask % 2
- `;;
- *) mkdir_umask=$umask,go-w;;
- esac
-
- # With -d, create the new directory with the user-specified mode.
- # Otherwise, rely on $mkdir_umask.
- if test -n "$dir_arg"; then
- mkdir_mode=-m$mode
- else
- mkdir_mode=
- fi
-
- posix_mkdir=false
- case $umask in
- *[123567][0-7][0-7])
- # POSIX mkdir -p sets u+wx bits regardless of umask, which
- # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
- ;;
- *)
- tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
- trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
-
- if (umask $mkdir_umask &&
- exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
- then
- if test -z "$dir_arg" || {
- # Check for POSIX incompatibilities with -m.
- # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
- # other-writeable bit of parent directory when it shouldn't.
- # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
- ls_ld_tmpdir=`ls -ld "$tmpdir"`
- case $ls_ld_tmpdir in
- d????-?r-*) different_mode=700;;
- d????-?--*) different_mode=755;;
- *) false;;
- esac &&
- $mkdirprog -m$different_mode -p -- "$tmpdir" && {
- ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
- test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
- }
- }
- then posix_mkdir=:
- fi
- rmdir "$tmpdir/d" "$tmpdir"
- else
- # Remove any dirs left behind by ancient mkdir implementations.
- rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
- fi
- trap '' 0;;
- esac;;
- esac
-
- if
- $posix_mkdir && (
- umask $mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
- )
- then :
- else
-
- # The umask is ridiculous, or mkdir does not conform to POSIX,
- # or it failed possibly due to a race condition. Create the
- # directory the slow way, step by step, checking for races as we go.
-
- case $dstdir in
- /*) prefix='/';;
- -*) prefix='./';;
- *) prefix='';;
- esac
-
- eval "$initialize_posix_glob"
-
- oIFS=$IFS
- IFS=/
- $posix_glob set -f
- set fnord $dstdir
- shift
- $posix_glob set +f
- IFS=$oIFS
-
- prefixes=
-
- for d
- do
- test -z "$d" && continue
-
- prefix=$prefix$d
- if test -d "$prefix"; then
- prefixes=
- else
- if $posix_mkdir; then
- (umask=$mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
- # Don't fail if two instances are running concurrently.
- test -d "$prefix" || exit 1
- else
- case $prefix in
- *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
- *) qprefix=$prefix;;
- esac
- prefixes="$prefixes '$qprefix'"
- fi
- fi
- prefix=$prefix/
- done
-
- if test -n "$prefixes"; then
- # Don't fail if two instances are running concurrently.
- (umask $mkdir_umask &&
- eval "\$doit_exec \$mkdirprog $prefixes") ||
- test -d "$dstdir" || exit 1
- obsolete_mkdir_used=true
- fi
- fi
- fi
-
- if test -n "$dir_arg"; then
- { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
- { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
- { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
- test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
- else
-
- # Make a couple of temp file names in the proper directory.
- dsttmp=$dstdir/_inst.$$_
- rmtmp=$dstdir/_rm.$$_
-
- # Trap to clean up those temp files at exit.
- trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
-
- # Copy the file name to the temp name.
- (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
-
- # and set any options; do chmod last to preserve setuid bits.
- #
- # If any of these fail, we abort the whole thing. If we want to
- # ignore errors from any of these, just make sure not to ignore
- # errors from the above "$doit $cpprog $src $dsttmp" command.
- #
- { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
- { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
- { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
- { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
-
- # If -C, don't bother to copy if it wouldn't change the file.
- if $copy_on_change &&
- old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
- new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
-
- eval "$initialize_posix_glob" &&
- $posix_glob set -f &&
- set X $old && old=:$2:$4:$5:$6 &&
- set X $new && new=:$2:$4:$5:$6 &&
- $posix_glob set +f &&
-
- test "$old" = "$new" &&
- $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
- then
- rm -f "$dsttmp"
- else
- # Rename the file to the real destination.
- $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
-
- # The rename failed, perhaps because mv can't rename something else
- # to itself, or perhaps because mv is so ancient that it does not
- # support -f.
- {
- # Now remove or move aside any old file at destination location.
- # We try this two ways since rm can't unlink itself on some
- # systems and the destination file might be busy for other
- # reasons. In this case, the final cleanup might fail but the new
- # file should still install successfully.
- {
- test ! -f "$dst" ||
- $doit $rmcmd -f "$dst" 2>/dev/null ||
- { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
- { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
- } ||
- { echo "$0: cannot unlink or rename $dst" >&2
- (exit 1); exit 1
- }
- } &&
-
- # Now rename the file to the real destination.
- $doit $mvcmd "$dsttmp" "$dst"
- }
- fi || exit 1
-
- trap '' 0
- fi
-done
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
-# time-stamp-end: "; # UTC"
-# End:
diff --git a/mono/latest-mono-stable.sh b/mono/latest-mono-stable.sh
deleted file mode 100755
index 045b80f8377..00000000000
--- a/mono/latest-mono-stable.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-
-# suitable for Ubuntu 16.04 - get latest Mono stable
-mono --version
-sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-echo "deb http://download.mono-project.com/repo/ubuntu stable-xenial main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
-sudo apt-get update
-ps -A | grep apt
-#sudo rm /var/lib/dpkg/lock
-#sudo dpkg --configure -a
-sudo apt-get -my install mono-devel
-mono --version
diff --git a/mono/launcher b/mono/launcher
deleted file mode 100644
index e61b7bba19d..00000000000
--- a/mono/launcher
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-EXEC="exec "
-
-if test x"$1" = x--debug; then
- DEBUG=--debug
- shift
-fi
-
-if test x"$1" = x--gdb; then
- shift
- EXEC="gdb --eval-command=run --args "
-fi
-
-if test x"$1" = x--valgrind; then
- shift
- EXEC="valgrind $VALGRIND_OPTIONS"
-fi
-
-$EXEC @MONOBINDIR@/mono $DEBUG $MONO_OPTIONS @DIR@/@TOOL@ --exename:$(basename "$0") "$@"
diff --git a/mono/mono.snk b/mono/mono.snk
deleted file mode 100644
index 380116c18fc..00000000000
Binary files a/mono/mono.snk and /dev/null differ
diff --git a/mono/msfinal.pub b/mono/msfinal.pub
deleted file mode 100644
index 110b59c7b0d..00000000000
Binary files a/mono/msfinal.pub and /dev/null differ
diff --git a/mono/prepare-mono.sh b/mono/prepare-mono.sh
deleted file mode 100755
index 229a7eb8492..00000000000
--- a/mono/prepare-mono.sh
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env sh
-
-# OS detection
-
-OSName=$(uname -s)
-case $OSName in
- Darwin)
- OS=OSX
- ;;
-
- Linux)
- OS=Linux
- ;;
-
- *)
- echo "Unsupported OS '$OSName' detected. Cannot continue with build, the scripts must be updated to support this OS."
- exit 1
- ;;
-esac
-
-# On Linux (or at least, Ubuntu), when building with Mono, need to install the mono-devel package first.
-if [ $OS = 'Linux' ]; then
- sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
- echo "deb http://download.mono-project.com/repo/ubuntu trusty main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
- sudo apt-get update
- sudo apt-get -y install mono-devel msbuild
-fi
-
-# The FSharp.Compiler.Tools package doesn't work correctly unless a proper install of F# has been done on the machine.
-# OSX can skip this because the OSX Mono installer includes F#.
-if [ $OS != 'OSX' ]; then
- sudo apt-get -y install fsharp
-fi
-
-# "access to the path /etc/mono/registry/last-time is denied"
-# On non-OSX systems, may need to create Mono's registry folder to avoid exceptions during builds.
-# This doesn't seem to be necessary on OSX, as the folder is created by the installer.
-if [ $OS != 'OSX' ]; then
- # This registry folder path is correct for Linux;
- # on OSX the folder is /Library/Frameworks/Mono.framework/Versions/Current/etc/mono/registry
- # and may be different for *BSD systems.
- __MonoRegistryDir="/etc/mono/registry"
- if [ ! -d "$__MonoRegistryDir" ]; then
- echo "Mono registry directory does not exist (it may not have been created yet)."
- echo "The directory needs to be created now; superuser permissions are required for this."
- { sudo -- sh -c "mkdir -p $__MonoRegistryDir && chmod uog+rw $__MonoRegistryDir"; } || { echo "Unable to create/chmod Mono registry directory '$__MonoRegistryDir'." >&2; }
- fi
-fi
diff --git a/mono/test-mono.sh b/mono/test-mono.sh
deleted file mode 100755
index bbcc8b8705e..00000000000
--- a/mono/test-mono.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-# Run some project building tests
-# Run some a variation of the tests/fsharp suite
-# Run the FSharp.Core.UnitTests suite
-
-# note: expects to run from top directory
-(cd tests/projects; ./build.sh) &&
-(cd tests/fsharp/core; ./run-opt.sh)
-# This currently takes too long in travis
-#&& mono packages/NUnit.Console.3.0.0/tools/nunit3-console.exe --agents=1 Release/net40/bin/FSharp.Core.UnitTests.dll
-
diff --git a/proto.proj b/proto.proj
index 23d7525d13e..bb2f9727045 100644
--- a/proto.proj
+++ b/proto.proj
@@ -7,13 +7,13 @@
- TargetFramework=netcoreapp2.1
+ TargetFramework=netstandard2.0
- TargetFramework=netcoreapp2.1
+ TargetFramework=netcoreapp3.1
- TargetFramework=netcoreapp2.1
+ TargetFramework=netcoreapp3.1
diff --git a/release-notes.md b/release-notes.md
index 88c4c4a3e94..8c4c55dd6e2 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -1,15 +1,503 @@
- Copyright (c) Microsoft Corporation. All Rights Reserved.
- See License.txt in the project root for license information.
+Copyright (c) Microsoft Corporation. All Rights Reserved.
+See License.txt in the project root for license information.
## About the release notes
-We deliver F# and F# tools for Visual Studio and .NET Core releases. These can include bug fixes, new tooling features, new compiler features, performance improvements, infrastructure improvements, and new language versions. The most recent release of F# or any F# component will be at the top of this document.
+This document contains current and historical release notes information. They are preserved in their original form.
-## Visual Studio 15.9
+* [Current Release notes](#Current-release-notes)
+* [Visual Studio 2017-2019 release notes](#visual-studio-2017-2019-update-167-release-notes)
+* [FSharp.Compiler.Service release notes (version 37 and lower)](#FSharp-Compiler-Service-Versions-Release-notes)
+* [Older release notes (pre-F# 4.0)](#older-visual-f-releases)
+
+## Current release notes
+
+These release notes track our current efforts to document changes to the F# project over time. They are split into the language, core library, compiler/tools, and compiler service.
+
+### F# 5 / Visual Studio 16.9
+
+### FSharp.Core 5.0.1
+
+TBD
+
+### FSharp tools 11.0.1
+
+* Add ConvertToAnonymousRecord quick fixeroony [#10493](https://github.com/dotnet/fsharp/pull/10493)
+* Add UseMutationWhenValueIsMutable code fix [#10488](https://github.com/dotnet/fsharp/pull/10488)
+* Add MakeDeclarationMutable code fix [#10480](https://github.com/dotnet/fsharp/pull/10480)
+* Add ChangeToUpcast code fix [#10463](https://github.com/dotnet/fsharp/pull/10463)
+* Add AddMissingEqualsToTypeDefinition code fixer [#10470](https://github.com/dotnet/fsharp/pull/10470)
+* Tag items in tooltips consistenly with respect to document classification. [#9563](https://github.com/dotnet/fsharp/pull/9563)
+* Add ConvertToSingleEqualsEqualityExpression code fix [#10462](https://github.com/dotnet/fsharp/pull/10462)
+* Turn XML doc and Sig<->Impl mismatch warnings on by default [#10457](https://github.com/dotnet/fsharp/pull/10457)
+* Add ChangeRefCellDerefToNotExpression code fixer [#10469](https://github.com/dotnet/fsharp/pull/10469)
+* Add WrapExpressionInParentheses code fix [#10460](https://github.com/dotnet/fsharp/pull/10460)
+* Add ChangePrefixNegationToInfixSubtraction code fixeroo [#10471](https://github.com/dotnet/fsharp/pull/10471)
+* Fix generic overloads with nullable [#10582](https://github.com/dotnet/fsharp/pull/10582)
+* Resolve issue with implicit yields requiring Zero [#10556](https://github.com/dotnet/fsharp/pull/10556), by [Ryan Coy](https://github.com/laenas)
+* Fix issue10550 FSI accessing System.Configuration. [#10572](https://github.com/dotnet/fsharp/pull/10572)
+* Add field names to ILNativeType.Custom. [#10567](https://github.com/dotnet/fsharp/pull/10567), by [Scott Hutchinson](https://github.com/ScottHutchinson)
+* Add field names to the ILExceptionClause.FilterCatch constructor. [#10559](https://github.com/dotnet/fsharp/pull/10559), by [Scott Hutchinson](https://github.com/ScottHutchinson)
+* Fix completion with backticks, underscores, numbers [#10500](https://github.com/dotnet/fsharp/pull/10500), by [zanaptak](https://github.com/zanaptak)
+* Emitting IsReadOnly/In attributes on abstract properties [#10542](https://github.com/dotnet/fsharp/pull/10542)
+* Disable partial type checking when getting full results for a file [#10448](https://github.com/dotnet/fsharp/pull/10448)
+* Fix unused open type declaration detection [#10510](https://github.com/dotnet/fsharp/pull/10510), by [André Slupik](https://github.com/asik)
+
+### FSharp Compiler Service 39.0.0
+
+This is a big update to FCS. There are significant trimmings and renamings of the API as a first step towards getting it under control with aims to eventually have a stable, sane public API surface area.
+
+Renamings:
+
+```diff
+-type FSharp.Compiler.AbstractIL.Internal.Library.IFileSystem
++type FSharp.Compiler.SourceCodeServices.IFileSystem
+
+-module FSharp.Compiler.AbstractIL.Internal.Library.Shim
++FSharp.Compiler.SourceCodeServices.FileSystemAutoOpens
+
+-type FSharp.Compiler.AbstractIL.Internal.Layout
++type FSharp.Compiler.TextLayout.Layout
+
+-type FSharp.Compiler.AbstractIL.Internal.TaggedText
++type FSharp.Compiler.TextLayout.TaggedText
+
+-type FSharp.Compiler.Layout.layout
++type FSharp.Compiler.TextLayout.layout
+
+-type FSharp.Compiler.Layout.Layout
++FSharp.Compiler.TextLayout.Layout
+
+-module FSharp.Compiler.Layout
++module FSharp.Compiler.TextLayout.LayoutRender
+
+-module FSharp.Compiler.LayoutOps
++module FSharp.Compiler.TextLayout.Layout
+
+-module FSharp.Compiler.Layout.TaggedText
++module FSharp.Compiler.TextLayout.TaggedText
+
+-module FSharp.Compiler.Layout.TaggedTextOps
++FSharp.Compiler.TextLayout.TaggedText
+
+-module FSharp.Compiler.Layout.TaggedTextOps.Literals
++FSharp.Compiler.TextLayout.TaggedText
+
+-type FSharp.Compiler.Range.range
++FSharp.Compiler.Text.Range
+
+-type FSharp.Compiler.Range.pos
++FSharp.Compiler.Text.Pos
+
+-module FSharp.Compiler.Range.Range
++module FSharp.Compiler.Text.Pos
++module FSharp.Compiler.Text.Range
+
+-module FSharp.Compiler.QuickParse
++module FSharp.Compiler.SourceCodeServices.QuickParse
+
+-module FSharp.Compiler.PrettyNaming
++FSharp.Compiler.SourceCodeServices.PrettyNaming
+
+-val FSharpKeywords.PrettyNaming.KeywordNames
++FSharp.Compiler.SourceCodeServices.FSharpKeywords.KeywordNames
+
+-val FSharpKeywords.PrettyNaming.QuoteIdentifierIfNeeded
++FSharp.Compiler.SourceCodeServices.FSharpKeywords.QuoteIdentifierIfNeeded
+
+-val FSharpKeywords.PrettyNaming.FormatAndOtherOverloadsString
++FSharp.Compiler.SourceCodeServices.FSharpKeywords.FormatAndOtherOverloadsString
+```
+
+Renamings in `FSharp.Compiler.SourceCodeServices`:
+
+```diff
+-Lexer.*
++FSharp.Compiler.SourceCodeServices.*
+
+-FSharpSyntaxToken*
++FSharpToken*
+
+-FSharpErrorInfo
++FSharpDiagnostic
+
+-FSharpErrorSeverity
++FSharpDiagnosticSeverity
+
+-ExternalSymbol
++FSharpExternalSymbol
+
+-UnresolvedSymbol
++FSharpUnresolvedSymbol
+
+-CompletionKind
++FSharpCompletionKind
+
+-module Keywords
++module FSharpKeywords
+
+-module Tooltips
++module FSharpTooltip
+```
+
+* Extension methods in `ServiceAssemblyContent.fsi` are now now intrinsic methods on the symbol types themselves.
+
+The following namespaces have been made internal
+
+* `FSharp.Compiler.AbstractIL.*`, aside from a small hook for JetBrains Rider
+* `FSharp.Compiler.ErrorLogger.*`
+
+New functions in the `SourceCodeServices` API:
+
+* `FSharpDiagnostic.NewlineifyErrorString`
+* `FSharpDiagnostic.NormalizeErrorString`
+
+### F# 5 / Visual Studio 16.8 / .NET 5
+
+This release covers three important milestones: F# 5, Visual Studio 16.8, and .NET 5.
+
+### FSharpLanguage 5.0.0
+
+* Package references in scripts via `#r "nuget:..."`
+* String interpolation
+* Support for `nameof` and the `nameof` pattern by Microsoft and [Loïc Denuzière](https://github.com/Tarmil)
+* `open type` declarations
+* Applicative computation expressions via `let! ... and!`
+* Overloads for custom operations in computation expressions (in preview), by [Ryan Riley](https://github.com/panesofglass) and [Diego Esmerio](https://github.com/Nhowka)
+* Interfaces can now be implemented at different generic instantiations
+* Default interface member consumption
+* Better interop with nullable value types
+
+### FSharp Core 5.0.0
+
+* [Performance improvement](https://github.com/dotnet/fsharp/pull/10188) to core collections Set and Map by [Victor Baybekov](https://github.com/buybackoff)
+* Consistent behavior for empty/non-existent slices for lists, strings, arrays, 2D arrays, 3D arrays, and 4D arrays
+* Support for fixed-index slices in 3D and 4D arrays
+* Support for negative indexes (in preview)
+* Reverted a change where the %A and %O and `ToString`/`string` result of a union with `RequireQualifiedAccess` gave the fully-qualified union case name in response to user feedback
+* Significantly improved XML documentation for all APIs
+* Optimized reflection for F# types by [kerams](https://github.com/kerams)
+
+### FSharp Tools 11.0.0
+
+* Improved batch compilation performance (up to 30% faster depending on the project type)
+* Support for editing `#r "nuget:..."` scripts in Visual Studio
+* Various fixes for F# script editing performance, especially for scripts with significant dependencies getting loaded
+* Support for compiling against .NET Core on Windows when no STAThread is availble
+* Support for validating signatures against XML doc comments when compiling via `/warnon:3390`
+* Fixed a bug where FSharp.Core XML doc contents were not displayed in F# scripts in Visual Studio
+* Support for strong name signing against F# projects when compiling using the .NET SDK
+* Fixed a bug where manually referencing `Akkling.Cluster.Sharding.0.9.3` in FSI would not work
+* Bring back the custom colorization options that were missed in the 16.7 update
+* Support coloring disposable values independently from disposable types
+* Fix a bug where emitting an `inref<_>` could cause a value to no longer be consumable by C#
+* Support displaying `Some x` when debugging F# options in Visual Studio, by [Friedrich von Never](https://github.com/ForNeVeR)
+* Fix a bug where compiling large anonymous records could fail in release mode
+* Support for considering struct tuples and struct anonymous records as subtypes of `System.ValueTuple`
+* Fix several internal errors in the compiler when compiling various niche scenarios
+* Various performance enhancements when editing large files by Microsoft and [Daniel Svensson](https://github.com/Daniel-Svensson)
+* Optimized output for the `string` function, by [Abel Braaksma](https://github.com/abelbraaksma)
+* Various fixes for some display regressions for Find all References in Visual Studio
+* Fix duplicate symbol output when renaming constructs in a project with multiple TFMs
+* Support for `Int64.MinValue` as a `nativeint` literal, by [Abel Braaksma](https://github.com/abelbraaksma)
+* Prevent assignment to `const` fields, by [Chet Husk](https://github.com/baronfel)
+* Compiler message improvements (especially for overload resolution) by [Gauthier Segay](https://github.com/smoothdeveloper), [Vladimir Shchur](https://github.com/Lanayx), and Microsoft
+
+### FSharp Compiler Service 38.0.2
+
+* Add FSharp.DependencyManager.Nuget as a project reference and ensure it is in the package, allowing other editors to consume `#r "nuget:..."` references at design-time [#10784](https://github.com/dotnet/fsharp/pull/10784)
+
+### FSharp Compiler Service 38.0.1
+* Add check for system assemblies completion [#10575](https://github.com/dotnet/fsharp/pull/10575)
+* Fix net sdk references discovery [#10569](https://github.com/dotnet/fsharp/pull/10569)
+* Fix FSC nuget package dependencies [#10588](https://github.com/dotnet/fsharp/pull/10588)
+
+### FSharp Compiler Service 38.0.0
+
+The most notable change for FSharp.Compiler.Service is that it is now built and deployed as a part of the dotnet/fsharp codebase. Builds are produced nightly, matching exactly the nightly builds of the F# compiler, FSharp.Core, and F# tools.
+
+* Support for Witness information [#9510](https://github.com/dotnet/fsharp/pull/95100) in `FSharpExpr` and `FSharpMemberOrFunctionOrValue`
+* Support for Jupyter Notebooks and VSCode notebooks via `FSharp.Compiler.Private.Scripting` and .NET Interactive
+* Improvements to the F# syntax tree represtation by [Eugene Auduchinok](https://github.com/auduchinok)
+* Support for `const` in keyword completion info by [Alex Berezhnykh](https://github.com/DedSec256)
+* Support for passing in a `PrimaryAssembly` for AST compilation routines by [Eirik Tsarpalis](https://github.com/eiriktsarpalis)
+* Support for `ToString` in `FSharp.Compiler.SourceCodeServices.StringText` by [Asti](https://github.com/deviousasti)
+* Fix an issue with equality comparisons for `StringText` by [Asti](https://github.com/deviousasti)
+
+Significant changes for consumers:
+
+* Several APIs no longer require the Reactor thread
+* `GetAllUsesOfAllSymbolsInFile` now returns `seq` instead of `FSharpSymbol[]`
+* All four `Get*UsesOfAllSymbolsIn*` APIs are no longer asynchronous
+* `StructuredDescriptionTextAsync` and `DescriptionTextAsync` are now deprecated, please use `StructuredDescriptionText` and `DescriptionText` instead
+* The `hasTextChangedSinceLastTypecheck` optional argument has been removed (it has been unused in Visual Studio since VS 2017)
+* The `textSnapshotInfo` optional argument is removed as it only made sense in tandem with `hasTextChangedSinceLastTypecheck`
+* `userOpName` is removed from all APIs that are no longer asynchronous
+
+## Visual Studio 2017-2019 Update 16.7 release notes
+
+These release notes contain release notes for all F# product release delivered alongside Visual Studio since Visual Studio 2017 and up until Visual Studio 2019 update 16.7.
+
+### Visual Studio 16.7
+
+This release is focused on closing out F# 5 feature development and making Visual Studio tooling improvements.
+
+#### F# language
+
+The following features were added to F# 5 preview:
+
+* String interpolation
+* Complete `nameof` design implementation
+* `nameof` support for patterns
+* `open type` declarations
+* Overloads of custom keywords in computation expressions
+* Interfaces can be implemented at different generic instantiation
+
+#### F# compiler and tools
+
+* Various bug fixes
+* Updated semantic classification to better distinguish various F# constructs from one another
+* Improvements to performance of various array-based operations in FSharp.Core by [Abel Braaksma](https://github.com/abelbraaksma)
+* Various improvements to the F# compiler service by [Eugene Auduchinok](https://github.com/auduchinok)
+* Improvements to SourceLink support by [Chet Husk](https://github.com/baronfel)
+* Support for `Map.change` by [Fraser Waters](https://github.com/Frassle)
+
+### Visual Studio 16.6
+
+This release is focused on more F# 5 preview features and Visual Studio tooling improvements.
+
+#### F# language
+
+The following features were added to F# 5 preview:
+
+* Support for interop with Default Interface Methods
+* Improvements for `#r "nuget"` - allow packages with native dependencies
+* Improvements for `#r "nuget"` - allow packages like FParsec that require `.dll`s to be referenced in a particular order
+* Improved interop with Nullable Value Types
+
+#### F# compiler and tools
+
+* Various bug fixes
+* Significant improvements to memory usage for symbol-based operations such as Find All References and Rename, especially for large codebases
+* 15% or higher reduction in compile times (as measured by compiling [`FSharpPlus.dll`](https://github.com/fsprojects/FSharpPlus/))
+* Performance improvements for design-time builds by [Saul Rennison](https://github.com/saul)
+* Improved stack traces in F# async and other computations, thanks to [Nino Floris](https://github.com/NinoFloris)
+* All new F# project types now use the .NET SDK
+* Descriptions in completion lists for tooltips
+* Improved UI for completion for unimported types
+* Bug fix for adding a needed `open` declaration when at the top of a file (such as a script)
+* Various improvements to error recovery and data shown in tooltips have been contributed by [Eugene Auduchinok](https://github.com/auduchinok) and [Matt Constable](https://github.com/mcon).
+* Various compiler performance improvements by [Steffen Forkmann](https://github.com/forki/)
+* Improvements to F# CodeLenses by [Victor Peter Rouven Muller](https://github.com/realvictorprm)
+* Better emitted IL for `uint64` literals by [Teo Tsirpanis](https://github.com/teo-tsirpanis)
+
+### Visual Studio 16.5
+
+The primary focus of this release has been improving the [performance and scalability of large F# codebases in Visual Studio](https://github.com/dotnet/fsharp/issues/8255). This work was influenced by working directly with customers who have very large codebases. The performance work is [still ongoing](https://github.com/dotnet/fsharp/issues/6866), but if you have a medium-to-large sized codebase, you should see reduced memory usage.
+
+Beyond performance enhancements, this release includes a variety of other fixes, many of which were contributed by our wonderful F# OSS community.
+
+#### F# language
+
+Several F# preview language features have been merged. You can try them out by setting your `LangVersion` to `preview` in your project file.
+
+* [F# RFC FS-1076 - From the end slicing and indexing for collections](https://github.com/fsharp/fslang-design/blob/master/preview/FS-1076-from-the-end-slicing.md) has been completed for F# preview
+* [F# RFC FS-1077 - Tolerant Slicing](https://github.com/fsharp/fslang-design/blob/master/preview/FS-1077-tolerant-slicing.md) has been completed for F# preview
+* [F# RFC FS-1077 - Slicing for 3D/4D arrays with fixed index](https://github.com/fsharp/fslang-design/blob/master/preview/FS-1077-3d-4d-fixed-index-slicing.md) has been completed for F# preview
+* [F# RFC FS-1080 - Float32 without dot](https://github.com/fsharp/fslang-design/blob/master/preview/FS-1080-float32-without-dot.md) has been completed for F# preview, contributed by [Grzegorz Dziadkiewicz](https://github.com/gdziadkiewicz)
+
+#### F# compiler
+
+* [Support for `--standalone`](https://github.com/dotnet/fsharp/issues/3924) has been added for .NET Core
+* Various improvements to error recovery have been contributed by [Eugene Auduchinok](https://github.com/auduchinok)
+* [Support for generating an AssemblyInfo from a project file](https://github.com/dotnet/fsharp/issues/3113) has been added
+* [Better error reporting for mismatched Anonymous Records](https://github.com/dotnet/fsharp/issues/8091) was contributed by [Isaac Abraham](https://github.com/isaacabraham)
+* A bug where [use of type abbreviations could bypass `byref` analysis](https://github.com/dotnet/fsharp/issues/7934) in the compiler has been resolved
+* It is now possible to [specify the `[]` attribute](https://github.com/dotnet/fsharp/issues/7897) in F# signature files
+* A bug where the [`LangVersion` flag was culture-dependent](https://github.com/dotnet/fsharp/issues/7757) has been resolved
+* A bug where [large types and expressions defined in source would lead to a stack overflow](https://github.com/dotnet/fsharp/issues/7673) has been resolved
+* A bug where [arbitrary, nonsense attributes could be defined on F# type extesions](https://github.com/dotnet/fsharp/issues/7394) was resolved
+* A bug where [exhaustive matches on SByte and Byte literal values emitted a warning](https://github.com/dotnet/fsharp/issues/6928) was resolved
+* A bug where [invalid type abbreviations with `byref`s and `byref`-like values](https://github.com/dotnet/fsharp/issues/6133) could be defined was resolved
+* A bug where [invalid binary and octal literals would be accepted by the compiler](https://github.com/dotnet/fsharp/issues/5729) was resolved, contributed by [Grzegorz Dziadkiewicz](https://github.com/gdziadkiewicz)
+* A bug where [`P/Invoke to "kernel32.dll"` was getting called in a FreeBSD source build of .NET Core](https://github.com/dotnet/fsharp/pull/7858) has been resolved by [Adeel Mujahid](https://github.com/am11)
+* Various smaller performance improvements have been added by [Eugene Auduchinok](https://github.com/auduchinok) and [Steffen Formann](https://github.com/forki/)
+
+#### F# core library
+
+* A bug where [calling `string` or `.ToString` on `ValueNone` would throw an exception](https://github.com/dotnet/fsharp/issues/7693) has been resolved
+* A bug where calling `Async.Sleep` within a sequentially processed set of async expressions wouldn't process sequentially has been resolved, contributed by [Fraser Waters](https://github.com/Frassle)
+* An issue in [`Async.Choice` that could lead to memory leaks](https://github.com/dotnet/fsharp/pull/7892) has been resolved, contributed by [Fraser Waters](https://github.com/Frassle)
+
+#### F# tools for Visual Studio
+
+* A bug where the Product Version in the About Visual Studio window [mistakenly displayed F# 4.6](https://github.com/dotnet/fsharp/issues/8018) has been resolved
+* A bug where the `fsi` type in F# scripts was [incorrectly treated as not defined](https://github.com/dotnet/fsharp/issues/7950) has been resolved
+
+#### F# open source development experience
+
+* The FSharp.Compiler.Service build in the F# repository has been moved to use the .NET SDK, contributed by [Chet Husk](https://github.com/baronfel)
+
+### Visual Studio 16.3
+
+This release includes support for F# 4.7, the newest version of the F# language!
+
+Much of F# 4.7 was dedicated to underlying infrastructural changes that allow us to deliver preview of F# language functionality more effectively. That said, there are still some nice new features delivered as well.
+
+#### F# language and core library
+
+We added support for F# 4.7, a minor language release that comes with compiler infrastructure to enable preview features so that we can get feedback on feature designs earlier in the development process.
+
+The full F# 4.7 feature set is:
+
+* Support for the `LangVersion` flag, which allows for configuring the F# language version used by the compiler to be F# 4.6 or higher
+* Support for [implicit yields](https://github.com/fsharp/fslang-design/blob/master/FSharp-4.7/FS-1069-implicit-yields.md) in array, list, and sequence expressions
+* [Indentation requirement relaxations](https://github.com/fsharp/fslang-design/blob/master/FSharp-4.7/FS-1070-offside-relaxations.md) for static members and constructors
+* [Relaxing the need for a double-underscore (`__`)](https://github.com/fsharp/fslang-design/blob/master/FSharp-4.7/FS-1046-wildcard-self-identifiers.md) in [member declarations](https://github.com/dotnet/fsharp/pull/6829) and [`for` loops](https://github.com/dotnet/fsharp/pull/6867), contributed by [Gustavo Leon](https://github.com/gusty)
+* FSharp.Core now targets `netstandard2.0` instead of `netstandard1.6`, following the deprecation of support for .NET Core 1.x
+* FSharp.Core on .NET Core now supports `FSharpFunc.FromConverter`, `FSharpFunc.ToConverter`, and `FuncConvert.ToFSharpFunc`
+* FSharp.Core now supports [`Async.Sequential` and an optional `maxDegreeOfParallelism` parameter for `Async.Parallel`](https://github.com/fsharp/fslang-design/blob/master/FSharp.Core-4.7.0/FS-1067-Async-Sequential.md), contributed by [Fraser Waters](https://github.com/Frassle)
+
+In addition to the F# 4.7 feature set, this release includes support for the following preview F# language features:
+
+* Support for [`nameof` expressions](https://github.com/fsharp/fslang-design/blob/master/preview/FS-1003-nameof-operator.md)
+* Support for opening of static classes
+
+You can enable this by seeting `preview` in your project file.
+
+This release also contains the following bug fixes and improvements to the F# compiler:
+
+* A longstanding issue where the F# compiler could stack overflow with massive records, structs, or other types has been resolved ([#7070](https://github.com/dotnet/fsharp/issues/7070))
+* An issue where specifying invalid inline IL could crash Visual Studio has been resolved ([#7164](https://github.com/dotnet/fsharp/issues/7164)
+* Resolution of an issue where copying of a struct would not occur if it was defined in C# and mutated in a member call ([#7406](https://github.com/dotnet/fsharp/issues/7406))
+* A crypto hash of the portable PDB content created by the compiler is not included in the PE debug directory, with a configurable hash set to SHA-256 by default ([#4259](https://github.com/dotnet/fsharp/issues/4259), [#1223](https://github.com/dotnet/fsharp/issues/1223))
+* A bug where `LeafExpressionConverter` ignored `ValueType` and assumed `System.Tuple` has been fixed ([#6515](https://github.com/dotnet/fsharp/issues/6515)) by [Kevin Malenfant](https://github.com/kevmal)
+* A bug where `List.transpose` discaded data instead of throwing an exception has been resolved ([#6908](https://github.com/dotnet/fsharp/issues/6908)) by [Patrick McDonald](https://github.com/PatrickMcDonald)
+* A bug where `List.map3` gave a misleading error when used on lists of different lengths has been resolved ([#6897](https://github.com/dotnet/fsharp/issues/6897)) by [reacheight](https://github.com/reacheight)
+
+#### F# tools
+
+This release also includes a few improvements to the F# tools for Visual Studio:
+
+* Records are formatted more to look more like canonical declarations and values in tooltips and F# interactive ([#7163](https://github.com/dotnet/fsharp/issues/7163))
+* Properties in tooltips now specify whether or not that are `get`-only, `set`-only, or `get` and `set` ([#7007](https://github.com/dotnet/fsharp/issues/7007))
+* An issue where Go to Definition and other features could not always work across projects when files use forward slashes ([#4446](https://github.com/dotnet/fsharp/issues/4446), [#5521](https://github.com/dotnet/fsharp/issues/5521), [#4016](https://github.com/dotnet/fsharp/issues/4016)) has been fixed, with help from [chadunit](https://github.com/chadunit)
+* Issues with anonymous records and debugging have been resolved ([#6728](https://github.com/dotnet/fsharp/issues/6728), [#6512](https://github.com/dotnet/fsharp/issues/6512))
+* A bug where empty hash directives in source could make source text coloring seem random has been resolved ([#6400](https://github.com/dotnet/fsharp/issues/6400), [#7000](https://github.com/dotnet/fsharp/issues/7000))
+
+### Visual Studio 16.1
+
+This is a relatively minor release for the F# language and tools, but it's not without some goodies! As with the VS 16.0 update, this release also focused on performance of editor tooling.
+
+#### F# compiler and F# interactive
+
+* Added `P/Invoke` support to F# interactive on .NET Core ([#6544](https://github.com/Microsoft/visualfsharp/issues/6544))
+* Added a compiler optimization for `Span<'T>` when used in a `for` loop ([#6195](https://github.com/Microsoft/visualfsharp/issues/6195))
+* Added an optimization to avoid an extraneous `Some` allocations for F# options in various scenarios ([#6532](https://github.com/Microsoft/visualfsharp/issues/6532))
+* Changed the execution order of expressions used in the instantiation of Anonymous Records to be top-to-bottom, rather than alphabetical, to match the current experience with normal Records ([#6487](https://github.com/Microsoft/visualfsharp/issues/6487))
+* A bug where very large literal expressions or very large struct declarations could cause the compiler to stack overflow on build has been resolved ([#6258](https://github.com/Microsoft/visualfsharp/issues/6258))
+* A bug where breakpoints would no longer trigger when debugging a function with an Anonymous Records has been fixed ([#6512](https://github.com/Microsoft/visualfsharp/issues/6512))
+* A bug where Anonymous Records passed to constructs expecting an `obj` parameter caused a compiler crash has been fixed ([#6434](https://github.com/Microsoft/visualfsharp/issues/6434))
+* A bug where `for var expr1 to expr2 do ...` loops could result in bizarrely valid (and discarded) syntax has been fixed ([#6586](https://github.com/Microsoft/visualfsharp/issues/6586))
+* A bug where Anonymous Records could not be used properly with events has been fixed ([#6572](https://github.com/Microsoft/visualfsharp/issues/6572))
+* A longstanding bug where extremely large generated parsers in FsLexYacc (over 100 million lines) has been resolved ([#5967](https://github.com/Microsoft/visualfsharp/issues/5976])
+* A longstanding issue in the Type Provider plugin component of the compiler that could leave the door open for a memory leak caused by a type provider has been resolved ([#6409](https://github.com/Microsoft/visualfsharp/issues/6409))
+* Support for `--pathmap` was added to the F# compiler by [Saul Rennison](https://github.com/saul), which resolves an issue where the resulting executable from a compilation would include absolute paths to source files in the embedded F# signature file resource ([#5213](https://github.com/Microsoft/visualfsharp/issues/5213))
+* An optimization to the F# AST that improves its consumption via other tools and enviroments (e.g., [Fable](https://fable.io/)) has been added by [ncave](https://github.com/ncave) ([#6333](https://github.com/Microsoft/visualfsharp/pull/6333))
+* An optimization around traversing information when resolving members has been added by [Steffen Forkmann](https://github.com/forki) ([#4457](https://github.com/Microsoft/visualfsharp/pull/4457))
+* An improvement to error messages such that when a type implementation is missing necessary overrides a list of those missing overrides is reported has been added by [Gauthier Segay](https://github.com/smoothdeveloper) ([#4982](https://github.com/Microsoft/visualfsharp/issues/4982))
+
+#### F# tools
+
+* The Target Framework dropdown for F# projects in the .NET SDK will now include values for all available .NET Core, .NET Standard, and .NET Framework values to ease migrating to .NET Core from .NET Framework on the .NET SDK
+* A bug where renaming generic type parameters produces double backtick-escaped names has been fixed ([#5389](https://github.com/Microsoft/visualfsharp/issues/5389))
+* A longstanding problem where Type Providers were redundantly reinstantiated, causing massive allocations over time, has been resolved ([#5929](https://github.com/Microsoft/visualfsharp/issues/5929))
+* A longstanding issue where reading IL needlessly allocated 20MB over a short period of time was been resolved ([#6403](https://github.com/Microsoft/visualfsharp/issues/6403))
+* A bug where the method `GetToolTipText` in the F# compiler service could show the same XML signature for several member overloads has been resolved by [Vasily Kirichenko](https://github.com/vasily-kirichenko) ([#6244](https://github.com/Microsoft/visualfsharp/issues/6244))
+
+#### F# open source infrastructure
+
+Finally, we improved the contribution experience by doing the following:
+
+* Completed our build from source process so that the F# compiler and core library can be built with the .NET Core source build repository
+* Removed our dependency on `netstandard1.6` so that the entire codebase uniformly targets `netstandard2.0` and `net472`
+* Added a `.vsconfig` file to the root of the repository so that contributors using Visual Studio don't have to know everything that needs installing up front
+* Rewrote our project's [README](https://github.com/microsoft/visualfsharp) to remove potentially confusing information, include a quickstart for getting started with contributing, and attempting to be more inclusive in our messaging about the kinds of changes we'd love to take
+
+### Visual Studio 16.0
+
+F# improvements in Visual Studio 2019 are in three major areas:
+
+* F# 4.6
+* Major performance improvements for medium and larger solutions
+* Lots of open source work by our excellent open source community
+
+#### F# 4.6
+
+This release contains the F# 4.6 language:
+
+* [Anonymous Record types](https://github.com/fsharp/fslang-design/blob/master/FSharp-4.6/FS-1030-anonymous-records.md) have been added to the language, including full tooling support and the ability to emit them types into JavaScript objects via the [Fable](https://fable.io/) compiler.
+* [ValueOption type and ValueOption module function parity with Option type](https://github.com/fsharp/fslang-design/blob/master/FSharp.Core-4.6.0/FS-1065-valueoption-parity.md).
+* [tryExactlyOne function for arrays, lists, and sequences](https://github.com/fsharp/fslang-design/blob/master/FSharp.Core-4.6.0/FS-1065-valueoption-parity.md), contributed by [Grzegorz Dziadkiewicz](https://github.com/gdziadkiewicz).
+
+#### F# compiler and FSharp.Core improvements
+
+The F# and compiler and FSharp.Core have seen numerous improvements, especially from open source contributors:
+
+* **fsi.exe** and **fsc.exe** now defaults to .NET Framework 4.7.2, allowing the loading of components targeting this framework or lower ([#4946](https://github.com/Microsoft/visualfsharp/issues/4946)).
+* We optimized methods on structs and struct records to perform as well as methods on classes and class-based records (#3057).
+* We optimized the emitted IL for combined Boolean logic in F# code (#635).
+* We've optimized the use of `+` with strings in F# to call the minimal amount of `String.Concat` calls as possible ([#5560](https://github.com/Microsoft/visualfsharp/issues/5560)).
+* We fixed an issue in the FSharp.Core package where some extra directories with test assets were included. FSharp.Core 4.5.5 and 4.6.1 should have the fix ([#5814](https://github.com/Microsoft/visualfsharp/issues/5814)).
+* When a user-defined attribute does not inherit from the `Attribute` class, you will now receive a warning, by [Vasily Kirichenko](https://github.com/vasily-kirichenko).
+* The `AssemblyInformationVersionAttribute` value in a project file now supports arbitrary values to support scenarios such as SourceLink (#4822).
+* A bug where illegal syntax with Active Patterns would cause an internal compiler error has been fixed by Steffen Forkmann (#5745).
+* A bug where the `Module` suffix was erroneously added to a module in a recursive module to match a type where the only difference is a generic parameter was fixed by BooksBaum (#5794).
+* An improvement to the error message when type parameters are not adjacent to a type name has been improved by Alan Ball (#4183).
+* The `uint16` literal suffix is listed correctly in the error messages for invalid numeric literals, by Teo Tsirpanis (#5712).
+* Error messages for computation expressions no longer state `async` in the message and instead refer to "computation expression(s)", by John Wostenberg (#5343).
+* An error message when incorrectly referencing `.dll`s in F# interactive was fixed by Bartoz Sypytkowski (#5416).
+* A bug where Statically Resolved Type Parameters couldn't handle calling a member that hides an inherited member was fixed by [Victor Peter Rouven Müller](https://github.com/realvictorprm) ([#5531](https://github.com/Microsoft/visualfsharp/issues/5531)).
+* Various smaller performance improvements to the compiler have been added by Steffen Forkmann and Robert Jeppesen.
+
+#### F# performance improvements
+
+Another big focus area for F# in Visual Studio 2019 has been performance for medium and large solutions. We addressed some very long-standing issues, some of which dating back to the very first edition of F# tools for Visual Studio. We also got some help from the excellent F# open source community.
+
+* We've revamped how the F# language service is initialized by Roslyn. Type colorization for larger solutions should generally appear sooner.
+* We changed our representation of source text to avoid large allocations over time, especially with bigger files ([#5935](https://github.com/Microsoft/visualfsharp/issues/5935), [#5936](https://github.com/Microsoft/visualfsharp/issues/5936), [#5937](https://github.com/Microsoft/visualfsharp/issues/5937), [#4881](https://github.com/Microsoft/visualfsharp/issues/4881)).
+* We changed our build caches for small edits to files to use significantly less memory ([#6028](https://github.com/Microsoft/visualfsharp/issues/6028)).
+* We modified a compiler feature that suggests names when unrecognized tokens are typed to only compute these suggestions on-demand, resulting in significant CPU and memory reductions when typing slowly in larger solutions ([#6044](https://github.com/Microsoft/visualfsharp/issues/6044)).
+* We changed IntelliSense so that it will no longer show symbols from unopened namespaces by default. This notably improves performance for IntelliSense in projects with many references. This feature can be turned back on in the settings via **Tools > Options > Text Editor > F# > IntelliSense**.
+* We improved memory usage when using Type Providers to generate very large amounts of provided types in a completion list (#5599).
+* A reduction to CPU and memory usage to an internal string comparison algorithm for suggesting unrecognized names has been fixed by [Avi Avni](https://github.com/aviavni) ([#6050](https://github.com/Microsoft/visualfsharp/pull/6050)).
+* A notable source of large string allocations, particularly for IDE tooling, was fixed by [Avi Avni](https://github.com/aviavni) ([#5922](https://github.com/Microsoft/visualfsharp/issues/5922)).
+* A notable source of Large Object Heap allocations coming from computing IntelliSense has been fixed by [Chet Husk](https://github.com/baronfel) ([#6084](https://github.com/Microsoft/visualfsharp/issues/6084))
+
+#### F# tooling improvements
+
+In addition to performance improvements, various other improvements to F# tooling for Visual Studio 2019 have been made:
+
+* The Add `open` statement code fix will now default to adding the `open` statement at the top of the file.
+* We fixed a bug where `match!` in user code invalidated structure guidelines and code outlining nodes for subsequent scopes (#5456).
+* The editor will now correctly color `byref`, `outref`, and `ref` values as record fields with the mutable value colorization (#5579).
+* We fixed a bug where the rename refactoring did not recognize the `'` character in symbol names (#5604).
+* We've fixed a longstanding bug where renaming F# script files resulted in a loss of colorization data ([#1944](https://github.com/Microsoft/visualfsharp/issues/1944)).
+* We cleaned up IntelliSense so that it doesn't show unrelated items in the list when pressing backspace.
+* With "Smart" indentation on, pasting F# code into the editor will now format it to match an appropriate scope based on the current cursor position, implemented by Saul Rennison (#4702).
+* An issue where F# editor options weren't syncing has been fixed by [Jakob Majocha](https://github.com/majocha) ([#5997](https://github.com/Microsoft/visualfsharp/issues/5997), [#5998](https://github.com/Microsoft/visualfsharp/issues/5998)).
+* A bug where IntelliSense in a constructor within an `inherit` clause wouldn't show the primary constructor has been fixed by [Eugene Auduchinok](https://github.com/auduchinok) ([#3699](https://github.com/Microsoft/visualfsharp/issues/3699))
+* Various smaller improvements to the F# language service have been made by [Eugene Auduchinok](https://github.com/auduchinok)
+
+##### F# open source infrastructure
+
+We've fully migrated the F# and F# tools codebase to use the .NET SDK. This dramatically simplifies the contribution process for developers, especially if they are not using Windows. Additionally, [Jakob Majocha](https://github.com/majocha) has helped in cleaning up documents for new contributors in light of the changes to the codebase.
+
+### Visual Studio 15.9
You can find all tracked VS 15.9 items in the [15.9 milestone](https://github.com/Microsoft/visualfsharp/milestone/24).
-### F# Compiler
+#### F# Compiler
* Fix (#4637) - Can't debug FCS when compiled with portable pdb debug symbols, by [Jason Imison](https://github.com/nosami).
* Fix (#5355) - We fixed a bug where extension methods that take `byref` values could mutate an immutable value.
@@ -22,7 +510,7 @@ You can find all tracked VS 15.9 items in the [15.9 milestone](https://github.co
* Fix (#5536) - We fixed a bug where your program could crash at runtime when partially applying a `byref` type to a method or function. An error message will now display.
* Fix (#5459) - We fixed an issue where an invalid combination of a `byref` and a reference type (such as `byref option`) would fail at runtime and not emit an error message. We now emit an error message.
-### F# Tools for Visual Studio
+#### F# Tools for Visual Studio
* Fix (#5657) - We resolved an issue where metadata for F# assemblies built with the .NET Core SDK was not shown in file properties on Windows. You can now see this metadata by right-clicking an assembly on Windows and selecting **Properties**.
* Fix (#5615) - We fixed a bug where use of `module global` in F# source could cause Visual Studio to become unresponsive.
@@ -30,11 +518,11 @@ You can find all tracked VS 15.9 items in the [15.9 milestone](https://github.co
* Fix (#5514) - We fixed a bug where the TargetFramework dropdown in Project Properties for .NET Framework F# projects was empty.
* Fix (#5507) - We fixed a bug where File | New Project on a .NET Framework 4.0 project would fail.
-### F# OSS Build
+#### F# OSS Build
* Feature (#5027) - Set VisualFSharpFull as the default startup project, by [Robert Jeppesen](https://github.com/rojepp).
-## Visual Studio 15.8.5
+### Visual Studio 15.8.5
* Fix (#5504) - Internal MSBuild Error when building non-.NET SDK projects with MSBuild parallelism
* Fix (#5518) - Visual Studio-deployed components are not NGEN'd
@@ -42,16 +530,16 @@ You can find all tracked VS 15.9 items in the [15.9 milestone](https://github.co
All other closed issues for the VS 15.8 release can be found [here](https://github.com/Microsoft/visualfsharp/milestone/14).
-## F# 4.5
+### F# 4.5
We introduced the F# language version 4.5 with this release. This also corresponds with the new 4.5.x family of FSharp.Core (the F# core library). You can read the specs for each of these changes in the [F# RFC repository](https://github.com/fsharp/fslang-design). There are also many improvements to F# tools for Visual Studio with this release.
-### Releases
+#### Releases
* Visual Studio 2017 update 15.8
* .NET Core SDK version 2.1.400 or higher
-### Language features
+#### Language features
* Support for `voidptr`
* `NativePtr.ofVoidPtr` and `NativePtr.toVoidPtr` support
@@ -66,14 +554,14 @@ We introduced the F# language version 4.5 with this release. This also correspon
* Enumeration cases emitted as public
* Various bug fixes with `byref` programming
-### FSharp.Core features
+#### FSharp.Core features
* Version aligned to 4.5.x for the NuGet package and 4.5.0.0 for the binary
* Improved strack traces for `async { }` so that user code can now be seen
* Support for `ValueOption<'T>`
* Support for `TryGetValue` on Map
-### Compiler improvements
+#### Compiler improvements
Improvements to the F# compiler in addition to the previously-mentioned language features are in F# 4.5. These include:
@@ -85,7 +573,7 @@ Improvements to the F# compiler in addition to the previously-mentioned language
* Respecting `#nowarn "2003"`
* Other smaller performance improvements and many bug fixes
-### Tooling improvements
+#### Tooling improvements
Significant improvements in the F# tools, such as performance enhancements and some new editor features are included this release. As always, with a large number of contributions from the F# open source community. Here are the highlights:
@@ -111,9 +599,9 @@ Significant improvements in the F# tools, such as performance enhancements and s
There is now an experimental CodeLens implementation, contributed by [Victor Peter Rouven Müller](https://github.com/realvictorprm). You can turn it on in **Options > Text Editor > F# > Code Lens**.
* A bug where the F# compiler service would incorrectly elide the module names in XML documentation has been fixed by [Sebastian Urban](https://github.com/surban).
* Code that uses `Dictionary` with `ContainsKey` and subsequent `Item` calls has been changed to use `TryGetValue`, by [Eugene Auduchinok](https://github.com/auduchinok).
-* [Jakob Majoka](https://github.com/majocha) also contributed in the process of consuming a different API for Tooltips.
+* [Jakob Majoka](https://github.com/majocha) also contributed in the process of consuming a different API for FSharpToolTip.
-### Infrastructure, Packaging, and Open Source Improvements
+#### Infrastructure, Packaging, and Open Source Improvements
We made the following enhancements to infrastructure, packaging, and our open source contribution experience:
@@ -125,14 +613,14 @@ We made the following enhancements to infrastructure, packaging, and our open so
* We removed Newtonsoft.json from our codebase, and you now have one less package downloaded for OSS contributors.
* We now use the latest versions of System.Collections.Immutable and System.Reflection.Metadata.
-## F# 4.1
+### F# 4.1
-### Releases
+#### Releases
* Visual Studio 2017 updates 15.0 to 15.8 (exclusive)
* .NET Core SDK versions 1.0 to 2.1.400 (exclusive)
-### Language and Core Library features
+#### Language and Core Library features
* Struct tuples
* Initial support for consuming C#-style `ref` returns
@@ -146,7 +634,7 @@ We made the following enhancements to infrastructure, packaging, and our open so
* Implicit "Module" suffix added to modules that share the same name as a type
* Tuple equality for F# tuples and `System.Tuple`
-### Compiler improvements
+#### Compiler improvements
* Support for generating Portable PDBs
* Significant improvements to error messages, particularly to aid with suggestions
@@ -159,7 +647,7 @@ We made the following enhancements to infrastructure, packaging, and our open so
* Support for emitting an enum-specific warning when pattern matching over one
* Many smaller bug fixes
-### FSharp.Core features
+#### FSharp.Core features
* Support for `NativePtr.ByRef`
* Support for `Async.StartImmediateAsTask`
@@ -167,7 +655,7 @@ We made the following enhancements to infrastructure, packaging, and our open so
* `IsSerializable` support for `Option` and `Async<'T>`
* Many smaller bug fixes
-### IDE features for F# tools in Visual Studio
+#### IDE features for F# tools in Visual Studio
Most items here contributed by community members.
@@ -208,11 +696,1031 @@ Most items here contributed by community members.
* Support for Optimization APIs in the compiler service
* Support for `IsNameGenerated` in the F# symbols API
-## Older F# releases
+## FSharp Compiler Service Versions Release notes
+
+## 37.0.0
+
+This release bring a number of new changes, including a massive enhancement to SemanticClassification types thanks to @cartermp.
+
+From dotnet/fsharp:333eb82c8..d9e070a9d:
+
+* now allows for multiple implementations of generic interfaces (preview feature) (thanks @0x53A!)
+* the default assembly set for script resolution now includes System.Numerics (thanks @KevinRansom)
+* #r nuget package resolution is now committed eagerly, instead of delayed (thanks @KevinRansom)
+* reduced allocations for some strings in the compiler (thanks @kerams)
+* better printing for SRTP constraints (thanks @abelbraaksma/@realvictorprm)
+* more expressive DUs for semantic classification (thanks @cartermp)
+* remove legacymsbuildreferenceresolver (thanks @KevinRandom)
+* supply witnesses for op_UnaryPlus (thanks @TIHan)
+* clean up CE classifications (thanks @cartermp)
+* Fixed tostring/equality for StringText (thanks @deviousasti)
+* Fixed error text for FS0874
+* Disallow assignment to C# Const/Readonly properties (thanks @baronfel)
+* Allow Int64.MinValue as a valid nativeint literal (thanks @abelbraaksma)
+* Enhancements to the nameof feature (preview feature)
+* String interpolation (preview feature)
+
+### 36.0.3
+
+This is a small bugfix release that fixes a nuspec package dependency issue with Sourcelink
+
+### 36.0.2
+
+This is a small bugfix release that I'm making primarily to publish a version
+of FCS with sourcelink enabled, so that tooling users can make use of that information.
+
+From dotnet/fsharp:079276b4b..37d0cccec:
+
+* Fixes for `do!` handling in computation expressions (thanks @baronfel)
+* Add missing versions in FCS' Interactive header (thanks @nightroman)
+* Support `Source`-translation in `match!` expressions (thanks @baronfel)
+* Ensure stack traces from uncaught exceptions in CEs are maintained (thanks @NinoFloris)
+* Better handling of `inline` in witness-passing codepaths (thanks @dsyme)
+* Enable publishing of FCS with sourcelink (thanks @baronfel)
+* Extend `nameof` to support naming generic parameters (`nameof<'t>`) and instance members (`nameof(Unchecked.defaultof.Property)`) (thanks @dsyme)
+
+### 36.0.1
+
+From dotnet/fsharp:522dd906c..16bca5aef:
+
+* Fixes to attribute range parsing (thanks @auduchinok)
+* Added nested exception details to Type Provider load errors (thanks @dsyme)
+* Improved error messages around unknown identifiers in patterns (thanks @jbeeko)
+* Better dependency probing behavior with Facade assemblies (thanks @KevinRansom)
+* APIs for programmatically adding and retrieving bindings in an FSI session (thanks @TIHan)
+* Optional parameter on `FSharpChecker.FindBackgroundReferencesInFile` API to allow for stale results (thanks @TIHan)
+* Better tooltips for function arguments (thanks @mcon)
+* Many performance tweaks to various compiler function implementations (thanks @forki)
+* Typo fixes in the AST (thanks @auduchinok)
+* Better IL emitted for usages of static members as System.Action (thanks @MoFtZ)
+* Allow for indexers to specify a type annotation (thanks @TIHan)
+* Allow languages/scripts that have no notion of upper-case to use their characters for DU identifiers (thanks @KevinRansom)
+* more optimized comparison/equality for DateTime (thanks @cartermp)
+* add support for `char` for the `GenericZero/GenericOne` mechanisms (thanks @Happypig375)
+* enhancements for the dependencymanager's resolution for native scripts (thanks @KevinRansom)
+* more consistent support for type-directed nullable parameters (thanks @dsyme)
+* fix FSI's ordering of out-of-order dlls in nuget packages (thanks @KevinRansom)
+* New SyntaxTree.Paren syntax node (thanks @auduchinok)
+* add SRTP witness solutions (via the new `CallWithWitnesses` pattern) (thanks @dsyme)
+
+### 35.0.0
+
+This version bumps the major due to API surface area changes in the AST and TAST. In addition, there's a new package for the
+built-in Nuget dependency manager for FSI: FSharp.DependencyManager.Nuget
+
+Members are now in SyntaxTree/SyntaxTreeOps and TypedTree/TypedTreeBasics/TypedTreeOps/TypedTreePickle.
+
+From dotnet/fsharp:d1a3d0705..522dd906c:
+
+* Improved error recovery from patterns (thanks @auduchinok)
+* Smaller IL Emit for unsigned 64-bit constants (thanks @teo-tsirpanis)
+* Improved ProvidedTypes Type generation (thanks @DedSec256)
+* Improved CodeLenses provided (thanks @realvictorprm)
+* Optimize internal member calculations in PrettyNaming and items lookup (thanks @auduchinok)
+* More fixes to compiler internals, ranges, etc (thanks @auduchinok)
+* Support for consumption of C# Default Interfaces
+* Better encapsulation of ProvidedExpr members (thanks @DedSec256)
+
+### 34.1.1
+
+From dotnet/fsharp:3777cd4d8..836da28c0:
+
+* Slight tweaks to error messages around numeric literals (Thanks @Happypig375)
+* Deny taking native address of an immutable local value (Thanks @TIHan)
+* Fixes to reported ranges for wildcard self-identifiers, module abbreviations, nested modules, attributes, nested types, and fields (Thanks @auduchinok)
+* Better compiler error recovery for errors in constructor expressions (Thanks @auduchinok)
+* Fix handling of F# Options in C# members with regards to nullable type interop (Thanks @TIHan)
+* Move dependency handling of native dlls to the DependencyManager (Thanks @KevinRansom)
+
+### 34.1.0
+
+From dotnet/fsharp:3af8959b6..9d69b49b7:
+
+* set default script TFM to netcoreapp3.1 if none found
+* improve C#-nullable and optional interop (RFC FS-1075)
+* Add type name to `undefined name error` if known
+* improve printing via %A/fsi
+* misc. improvements to DependencyManager
+* improve type provider support for .netcoreapp3.1 target frameworks.
+* New, optimized find-all-references API with reduced memory usage.
+* better error messages for failed overload resolution
+
+### 34.0.1
+
+Contains commits from 32b124966 to d7018737c from dotnet/fsharp. Notable changes include:
+
+* lowered allocations for large strings and char arrays (notably source file texts)
+* improved support for byref-like rules with regards to type abbreviations
+* better support for scopes in recursive modules
+* better location of .net core reference assemblies
+* lowered allocations for several internal compiler structures
+* better error messages for anonymous record mismatches
+* FSharpChecker learned how to keep background symbol uses
+* Project cracker/project cracker tool were removed
+* Better support for consuming C# in-ref parameters
+* new services around simplifying names and finding unused declarations
+* package management in scripts (in preview)
+* and-bang syntax support (in preview)
+
+### 33.0.1
+
+Integrate dotnet/fsharp from 4f5f08320 to 7b25d7f82. Notable changes include:
+
+* Addition of the FsharpUnionCase.HasFields property
+* FCS builds entirely on .Net Core now
+* Better debug information for ranges
+* Support for Literal values in signature files
+* Using memory-mapped files cross-platform to read IL.
+
+### 33.0.0
+
+Integrate dotnet/fsharp from 48f932cf8 to 085985140. Notable changes include:
+
+ allowing '_' as a self-identifier
+ events for FSI evaluation lifecycle events
+ enhancements to FSI return-values
+ fixed parsing for langversion CLI arguments
+ allow cancellation of FSI interactions
+ ToString fixes for value options
+ Fixes for code generation in autogenerated members for very large records
+ make ranges of member declarations capture the entire member
+ improve error recovery in the parser
+ improve logic for auto-detecting framework assemblies for FSI
+
+### 32.0.0
+
+* integrate dotnet/fsharp from e1b8537ee to 48f932cf8
+* notable changes include:
+* (preview) nameof
+* (preview) open static classes
+* Fixed 64-bit integer literal parsing
+* Better exhaustiveness checking for byte and sbyte pattern matches
+* Better native resource handling
+* Script-host assembly load events
+
+### 31.0.0
+
+* Integrate dotnet/fsharp from 5a8f454a1 to 05c558a61
+* Notable changes include:
+ * Removal of the `Microsoft.FSharp.Compiler.SourceCodeServices` namespace
+ * A new API for determining if an identifier needs to be quoted is available: `FSharp.Compiler.LexHelp.FSharpKeywords.DoesIdentifierNeedQuotation`
+ * Enhancements to the correctness of PDBs
+ * Better string formatting of records and values
+ * More stack overflow fixes in the compiler
+ * Inline IL parsing error handling
+ * `LeafExpressionConverter` handles struct tuples
+ * `FSharpChecker` now can parse a file without caching: `ParseFileNoCache`
+
+### 30.0.0
+
+* Integrate dotnet/fsharp from 25560f477 to 5a8f454a1
+* Notable improvements include:
+ * performance improvements
+ * FCS APIs for FSComp and Implement Interface
+ * line directive handling
+ * improved performance when computing quick fix suggestions
+
+### 29.0.1
+
+* Fix versioning of the assembly
+
+### 29.0.0
+
+* Integrate visualfsharp master from 165b736b9 (2019-03-29) to 25560f477 (2019-05-24)
+* Notable improvements include:
+ * Improved Portable PDB debugging
+ * Misc IL generation fixes
+ * Representing inlined mutable variables in the AST
+ * Moving on from net46 targeting
+ * Fixes for anonymous record generation
+ * Dependency updates
+ * Checking for constructors in FSharpMemberOrFunctionOrValue
+ * Fix unused opens false positive for record fields
+
+### 28.0.0
+
+* Integrate visualfsharp master from efb57cf56 to 8dfc02feb
+* Notable improvements include:
+ * XmlDoc fixes for overloads
+ * Fixes for deterministic compilation
+ * Improved tail-recursion when processing large expressions
+ * Better tooltip detection for operators with constraints
+ * FSharp.Compiler.Service nuget now uses net461, netstandard2.0 and FSharp.Core 4.6.2
+ * updated lexer and parser implementations to reduce stackoverflow likelihood on .net core
+
+### 27.0.1
+
+* Integrate visualfsharp master from 5a5ca976ec296d02551e79c3eb8e8db809e4304d to 2c8497bb097d5c5d3ef12f355594873838a48494
+* Notable improvements include:
+ * Anonymous Record support for expressions
+ * Union Case Naming fixes
+ * Trimming of the nuget package dependencies from 26.0.1
+
+### 26.0.1
+
+* Integrate visualfsharp master to 99e307f3a3ef2109ba6542ffc58affe76fc0e2a0
+
+### 25.0.1
+
+* Integrate visualfsharp master to 15d9391e78c554f91824d2be2e69938cd811df68
+
+### 24.0.1
+
+* Integrate visualfsharp master to 59156db2d0a744233d1baffee7088ca2d9f959c7
+
+### 23.0.3
+
+* Clarify package authors
+
+### 23.0.1
+
+* Integrate visualfsharp master to ee938a7a5cfdf4849b091087efbf64605110541f
+
+### 22.0.3
+
+* [Add entity.DeclaringEntity](https://github.com/Microsoft/visualfsharp/pull/4633), [FCS feature request](https://github.com/fsharp/FSharp.Compiler.Service/issues/830)
+
+### 22.0.2
+
+* Use correct version number in DLLs (needed until https://github.com/Microsoft/visualfsharp/issues/3113 is fixed)
+
+### 22.0.1
+
+* Integrate visualfsharp master
+* Includes recent memory usage reduction work for ByteFile and ILAttributes
+
+### 21.0.1
+
+* Use new .NET SDK project files
+* FSharp.Compiler.Service nuget now uses net461 and netstandard2.0
+* FSharp.Compiler.Service netstandard2.0 now supports type providers
+
+### 20.0.1
+
+* Integrate visualfsharp master
+
+### 19.0.1
+
+* Rename ``LogicalEnclosingEntity`` to ``ApparentEnclosingEntity`` for consistency int he F# codebase terminology.
+* Rename ``EnclosingEntity`` to ``DeclaringEntity``. In the case of extension properties, ``EnclosingEntity`` was incorrectly returning the logical enclosing entity (i.e. the type the property appears to extend), and in this case ``ApparentEnclosingEntity`` should be used instead.
+
+### 18.0.1
+
+* Integrate visualfsharp master
+
+### 17.0.2
+
+* Integrate visualfsharp master
+
+### 16.0.3
+
+* [File name deduplication not working with ParseAndCheckFileInProject](https://github.com/fsharp/FSharp.Compiler.Service/issues/819)
+
+### 16.0.2
+
+* [ProjectCracker returns *.fsi files in FSharpProjectOptions.SourceFiles array](https://github.com/fsharp/FSharp.Compiler.Service/pull/812)
+* [Fix line endings in the Nuget packages descriptions](https://github.com/fsharp/FSharp.Compiler.Service/pull/811)
+
+### 16.0.1
+
+* FSharpChecker provides non-reactor ParseFile instead of ParseFileInProject
+* Add FSharpParsingOptions, GetParsingOptionsFromProjectOptions, GetParsingOptionsFromCommandLine
+
+### 15.0.1
+
+* Integrate latest changes from visualfsharp
+* Add implementation file contents to CheckFileResults
+* Fix non-public API in .NET Standard 1.6 version
+
+### 14.0.1
+
+* Integrate latest changes from visualfsharp
+* Trial release for new build in fcs\...
+
+### 13.0.1
+
+* Move docs --> docssrc
+
+### 13.0.0
+
+* Move FSharp.Compiler.Service.MSBuild.v12.dll to a separate nuget package
+
+### 12.0.8
+
+* Set bit on output executables correctly
+
+### 12.0.7
+
+* Integrate visualfsharp master
+
+### 12.0.6
+
+* [758: Fix project cracker when invalid path given](https://github.com/fsharp/FSharp.Compiler.Service/pull/758)
+
+### 12.0.5
+
+* Remove dependency on System.ValueTuple
+
+### 12.0.3
+
+* [De-duplicate module names again](https://github.com/fsharp/FSharp.Compiler.Service/pull/749)
+
+### 12.0.2
+
+* De-duplicate module names
+
+### 12.0.1
+
+* [Integrate visualfsharp and fsharp](https://github.com/fsharp/fsharp/pull/696)
+
+### 11.0.10
+
+* [Fix F# Interactive on Mono 4.0.9+](https://github.com/fsharp/fsharp/pull/696)
+
+### 11.0.9
+
+* [Make incremental builder counter atomic](https://github.com/fsharp/FSharp.Compiler.Service/pull/724)
+* [Add IsValCompiledAsMethod to FSharpMemberOrFunctionOrValue](https://github.com/fsharp/FSharp.Compiler.Service/pull/727)
+* [Check before ILTypeInfo.FromType](https://github.com/fsharp/FSharp.Compiler.Service/issues/734)
+* [Transition over to dotnet cli Fsproj](https://github.com/fsharp/FSharp.Compiler.Service/issues/700)
+
+### 11.0.8
+
+* Depend on FSharp.Core package
+
+### 11.0.6
+
+* Fix [stack overflow exception](https://github.com/fsharp/FSharp.Compiler.Service/issues/672)
+
+### 11.0.4
+
+* Fix [out of range exception](https://github.com/fsharp/FSharp.Compiler.Service/issues/709)
+
+### 11.0.2
+
+* Integrate fsharp\fsharp and Microsoft\visualfsharp to 262deb017cfcd0f0d4138779ff42ede7dbf44c46
+
+### 11.0.1
+
+* Integrate fsharp\fsharp and Microsoft\visualfsharp to d0cc249b951374257d5a806939e42714d8a2f4c6
+
+### 10.0.3
+
+* [Expose assumeDotNetFramework in FSharpChecker.GetProjectOptionsFromScript](https://github.com/fsharp/FSharp.Compiler.Service/pull/699)
+* [SemanticClassificationType should not be internal](https://github.com/fsharp/FSharp.Compiler.Service/pull/696)
+
+### 10.0.1
+
+* [Adds FormatValue to FsiEvaluationSession, using the fsi object values for formatting](https://github.com/fsharp/FSharp.Compiler.Service/pull/686)
+
+### 10.0.0
+
+* Integrate fsharp\fsharp and Microsoft\visualfsharp to c3e55bf0b10bf08790235dc585b8cdc75f71618e
+* Integrate fsharp\fsharp and Microsoft\visualfsharp to 11c0a085c96a91102cc881145ce281271ac159fe
+* Some API changes for structured text provision for tagged structured text
+
+### 9.0.0
+
+* Update names of union fields in AST API
+* Fix load closure for ParseAndCheckInteraction
+* [Fix #631 compiler dependency on MSBuild](https://github.com/fsharp/FSharp.Compiler.Service/pull/657)
+* Fixed netcore codegen on Linux
+* Explicit error when cracker exe is missing
+
+### 8.0.0
+
+* Integrate fsharp\fsharp and Microsoft\visualfsharp to c494a9cab525dbd89585f7b733ea5310471a8001
+* Then integrate to 2002675f8aba5b3576a924a2e1e47b18e4e9a83d
+* [Add module values to navigable items](https://github.com/fsharp/FSharp.Compiler.Service/pull/650)
+* Optionally remove dependency on MSBuild reference resolution https://github.com/fsharp/FSharp.Compiler.Service/pull/649
+* [Compiler api harmonise](https://github.com/fsharp/FSharp.Compiler.Service/pull/639)
+* Various bits of work on .NET Core version (buildable from source but not in nuget package)
+
+### 7.0.0
+
+* Integrate fsharp\fsharp and Microsoft\visualfsharp to 835b79c041f9032fceeceb39f680e0662cba92ec
+
+### 6.0.2
+
+* [Fix #568: recognize provided expressions](https://github.com/fsharp/FSharp.Compiler.Service/pull/568)
+
+### 6.0.1
+
+* [Fix ProjectFileNames order when getting project options from script](https://github.com/fsharp/FSharp.Compiler.Service/pull/594)
+
+### 6.0.0
+
+* Switch to new major version on assumption integrated F# compiler changes induce API change
+
+### 5.0.2
+
+* Integrate Microsoft\visualfsharp to 688c26bdbbfc766326fc45e4d918f87fcba1e7ba. F# 4.1 work
+
+### 5.0.1
+
+* [Fixed dependencies in nuget package](https://github.com/fsharp/FSharp.Compiler.Service/pull/608)
+
+### 5.0.0
+
+* Fixed empty symbol declared pdb #564 from kekyo/fix-empty-pdb
+* .NET Core ProjectCracker - updated version and dependencies
+* Properly embed 'FSIstrings' resource, fixes #591
+* make build.sh work on windows (git bash).
+* Added default script references for .NET Core
+* Store useMonoResolution flag
+* Updated MSBuild version
+* Assume FSharp.Core 4.4.0.0
+
+### 4.0.1
+
+* Integrate Microsoft\visualfsharp and fsharp\fsharp to master (including portable PDB)
+* Remove .NET Framework 4.0 support (now needs .NET Framework 4.5)
+
+### 4.0.0
+
+* Integrate Microsoft\visualfsharp and fsharp\fsharp to master
+
+### 3.0.0.0
+
+* #538 - BackgroundCompiler takes a very long time on a big solution with a very connected project dependency graph
+* #544 - Losing operator call when one of operands is application of a partially applied function
+* #534 - Function valued property erasing calls
+* #495 - Detupling missing when calling a module function value
+* #543 - Tuple not being destructured in AST
+* #541 - Results of multiple calls to active pattern are always bound to variable with same name
+* #539 - BasicPatterns.NewDelegate shows same value for different arguments
+
+### 2.0.0.6
+
+* #530 - Adjust ProjectCracker NuGet for VS/NuGet
+
+### 2.0.0.5
+
+* #527 - Provide API that includes printf specifier arities along with ranges
+
+### 2.0.0.4
+
+* #519 - Change nuget layout for ProjectCracker package
+* #523 - Project cracking: spaces in file paths
+
+### 2.0.0.3
+
+* #508 - Integrate visualfsharp/master removal of Silverlight #if
+* #513 - Make CrackerTool `internal` to prevent accidental usage
+* #515 - Add simple Visual Studio version detection for project cracker
+
+### 2.0.0.2
+
+* Integrate visualfsharp/master and fsharp/master --> master
+* Expose QualifiedName and FileName of FSharpImplementationFileContents
+* Add FSharpDiagnostic.ErrorNumber
+
+### 2.0.0.1-beta
+
+* Fix 452 - FSharpField.IsMutable = true for BCL enum cases
+* Fix 414 - Add IsInstanceMemberInCompiledCode
+
+### 2.0.0.0-beta
+
+* Feature #470, #478, #479 - Move ProjectCracker to separate nuget package and DLL, used ProjectCrackerTool.exe to run
+* Feature #463 - Expose slot signatures of members in object expressions
+* Feature #469, #475 - Add EvalExpressionNonThrowing, EvalInteractionNonThrowing, EvalScriptNonThrowing
+* Fix #456 - FCS makes calls to kernel32.dll when running on OSX
+* Fix #473 - stack overflow in resolution logic
+* Fix #460 - Failure getting expression for a provided method call
+
+### 1.4.2.3 -
+
+* Fix bug in loop optimization, apply https://github.com/Microsoft/visualfsharp/pull/756/
+
+### 1.4.2.2 -
+
+* #488 - Performance problems with project references
+
+### 1.4.2.1 -
+
+* #450 - Correct generation of ReferencedProjects
+
+### 1.4.2.0 -
+
+* Fix bug in double lookup of cache, see https://github.com/fsharp/FSharp.Compiler.Service/pull/447
+
+### 1.4.1 -
+
+* Add pause before backgrounnd work starts. The FCS request queue must be empty for 1 second before work will start
+* Write trace information about the reactor queue to the event log
+* Rewrite reactor to consistently prioritize queued work
+* Implement cancellation for queued work if it is cancelled prior to being executed
+* Adjust caching to check cache correctly if there is a gap before the request is executed
+
+### 1.4.0.9 -
+
+* FSharpType.Format fix
+* Disable maximum-memory trigger by default until use case ironed out
+
+### 1.4.0.8 -
+
+* FSharpType.Format now prettifies type variables. If necessary, FSharpType.Prettify can also be called
+* Add maximum-memory trigger to downsize FCS caches. Defaults to 1.7GB of allocaed memory in the system
+ process for a 32-bit process, and 2x this for a 64-bit process
+
+### 1.4.0.7 -
+
+* fix 427 - Make event information available for properties which represent first-class uses of F#-declared events
+* fix 410 - Symbols for C# fields (and especially enum fields)
+* Expose implemented abstract slots
+* Fix problem with obscure filenames caught by Microsoft\visualfsharp tests
+* Integrate with visualfsharp master
+
+### 1.4.0.6 -
+
+* fix 423 - Symbols for non-standard C# events
+* fix 235 - XmlDocSigs for references assemblies
+* fix 177 - GetAllUsesOfAllSymbolsInFile returns nothing for C# nested enum
+* make Internal.Utilities.Text.Lexing.Position a struct
+* Exposing assembly attributes on FSharpAssemblySignature
+* clean up IncrementalFSharpBuild.frameworkTcImportsCache
+
+### 1.4.0.5 -
+
+* add more entries to FSharpTokenTag
+
+### 1.4.0.4 -
+
+* add more entries to FSharpTokenTag
+* add PrettyNaming.QuoteIdentifierIfNeeded and PrettyNaming.KeywordNames
+
+### 1.4.0.3 -
+
+* integrate Microsoft/visualfsharp OOB cleanup via fsharp/fsharp
+* Make Parser and Lexer private
+
+### 1.4.0.2 -
+
+* #387 - types and arrays in F# attribute contructor arguments
+
+### 1.4.0.1 - F# 4.0 support
+
+* Use FSharp.Core 4.4.0.0 by default for scripting scenarios if not FSharp.Core referenced by host process
+
+### 1.4.0.0-beta - F# 4.0 support
+
+* Integrate F# 4.0 support into FSharp.Compiler.Service
+
+### 1.3.1.0 -
+
+* simplified source indexing with new SourceLink
+* Add noframework option in AST compiler methods
+
+### 0.0.90 -
+
+* Add fix for #343 Use ResolveReferences task
+* Expose BinFolderOfDefaultFSharpCompiler to editors
+* Fix the registry checking on mono to avoid unnecessary exceptions being thrown
+
+### 0.0.89 -
+
+* Fix output location of referenced projects
+
+### 0.0.88 -
+* Added Fix to al
+* low implicit PCL references to be retrieved
+
+### 0.0.87 -
+
+* Don't report fake symbols in indexing #325
+* Add EnclosingEntity for an active pattern group #327
+* Add ImmediateSubExpressions #284
+* integrate fsharp/fsharp master into master
+
+### 0.0.85 -
+
+* Fix for FSharpSymbolUse for single case union type #301
+* Added supprt for ReturnParameter in nested functions
+
+### 0.0.84 -
+
+* Added curried parameter groups for nested functions
+
+### 0.0.83 -
+
+* Add Overloads to the symbols signature so it is publicly visible
+* Update OnEvaluation event to have FSharpSymbolUse information available
+
+### 0.0.82 -
+
+* Better support for Metadata of C# (and other) Assemblies.
+* Expose the DefaultFileSystem as a type instead of anonymous
+
+### 0.0.81 -
+
+* Update GetDeclarationListSymbols to expose FSharpSymbolUse
+* Improve reporting of format specifiers
+
+### 0.0.80 -
+
+* Update to latest F# 3.1.3 (inclunding updated FsLex/FsYacc used in build of FCS)
+* Report printf specifiers from Service API
+* Improve Accessibility of non-F# symbols
+
+### 0.0.79 -
+
+* Do not use memory mapped files when cracking a DLL to get an assembly reference
+* Fix for multilanguage projects in project cracker
+
+### 0.0.78 -
+
+* Reduce background checker memory usage
+* add docs on FSharp.Core
+* docs on caches and queues
+
+### 0.0.77 -
+
+* Update to github.com/fsharp/fsharp 05f426cee85609f2fe51b71473b07d7928bb01c8
+
+### 0.0.76 -
+
+* Fix #249 - Fix TryFullName when used on namespaces of provided erased type definitions
+* Add OnEvaluation event to FCS to allow detailed information to be exposed
+
+### 0.0.75 -
+
+* Do not use shared cursor for IL binaries (https://github.com/fsprojects/VisualFSharpPowerTools/issues/822)
+
+### 0.0.74 -
+
+* Extension members are returned as members of current modules
+* Fix exceptions while cross-reference a type provider project
+
+### 0.0.73 -
+
+* Add AssemblyContents and FSharpExpr to allow access to resolved, checked expression trees
+* Populate ReferencedProjects using ProjectFileInfo
+* Fix finding symbols declared in signature files
+* Add logging to project cracking facility
+
+### 0.0.72 -
+
+* Allow project parser to be used on project file with relative paths
+* Expose attributes for non-F# symbols
+
+### 0.0.71 -
+
+* More renamings in SourceCodeServices API for more consistent use of 'FSharp' prefix
+
+### 0.0.70 -
+
+* Make FSharpProjectFileParser public
+* Fixes to project parser for Mono (.NET 4.0 component)
+* Renamings in SourceCodeServices API for more consistent use of 'FSharp' prefix
+
+### 0.0.67 -
+
+* Fixes to project parser for Mono
+
+### 0.0.66 -
+
+* Fixes to project parser for Mono
+* Use MSBuild v12.0 for reference resolution on .NET 4.5+
+
+### 0.0.65 -
+
+* Fixes to project parser
+
+### 0.0.64 -
+
+* Add project parser, particularly GetProjectOptionsFromProjectFile
+
+### 0.0.63 -
+
+* #221 - Normalize return types of .NET events
+
+### 0.0.62 -
+
+* Integrate to latest https://github.com/fsharp/fsharp (#80f9221f811217bd890b3a670d717ebc510aeeaf)
+
+### 0.0.61 -
+
+* #216 - Return associated getters/setters from F# properties
+* #214 - Added missing XmlDocSig for FSharpMemberOrFunctionOrValue's Events, Methods and Properties
+* #213 - Retrieve information for all active pattern cases
+* #188 - Fix leak in file handles when using multiple instances of FsiEvaluationSession, and add optionally collectible assemblies
+
+### 0.0.60 -
+
+* #207 - Add IsLiteral/LiteralValue to FSharpField
+* #205 - Add IsOptionalArg and related properties to FSharpParameter
+* #210 - Check default/override members via 'IsOverrideOrExplicitMember'
+* #209 - Add TryFullName to FSharpEntity
+
+### 0.0.59 -
+
+* Fix for #184 - Fix EvalScript by using verbatim string for #Load
+* Fix for #183 - The line no. reporting is still using 0-based indexes in errors. This is confusing.
+
+### 0.0.58 -
+
+* Fix for #156 - The FSharp.Core should be retrieved from the hosting environment
+
+### 0.0.57 -
+
+* Second fix for #160 - Nuget package now contains .NET 4.0 and 4.5
+
+### 0.0.56 -
+
+* Fix for #160 - Nuget package contains .NET 4.0 and 4.5
+
+### 0.0.55 -
+
+* Integrate changes for F# 3.1.x, Fix #166
+
+### 0.0.54 -
+
+* Fix for #159 - Unsubscribe from TP Invalidate events when disposing builders
+
+### 0.0.53 -
+
+* Add queue length to InteractiveChecker
+
+### 0.0.52 -
+
+* Fix caches keeping hold of stale entries
+
+### 0.0.51 -
+
+* Add IsAccessible to FSharpSymbol, and ProjectContext.AccessibilityRights to give the context of an access
+
+### 0.0.50 -
+
+* Fix #79 - FindUsesOfSymbol returns None at definition of properties with explicit getters and setters
+
+### 0.0.49 -
+
+* Fix #138 - Fix symbol equality for provided type members
+* Fix #150 - Return IsGetterMethod = true for declarations of F# properties (no separate 'property' symbol is yet returned, see #79)
+* Fix #132 - Add IsStaticInstantiation on FSharpEntity to allow clients to detect fake symbols arising from application of static parameters
+* Fix #154 - Add IsArrayType on FSharpEntity to allow clients to detect the symbols for array types
+* Fix #96 - Return resolutions of 'Module' and 'Type' in "Module.field" and "Type.field"
+
+### 0.0.48 -
+
+* Allow own fsi object without referencing FSharp.Compiler.Interactive.Settings.dll (#127)
+
+### 0.0.47 -
+
+* Adjust fix for #143 for F# types with abstract+default events
+
+### 0.0.46 -
+
+* Fix multi-project analysis when referenced projects have changed (#141)
+* Fix process exit on bad arguments to FsiEvaluationSession (#126)
+* Deprecate FsiEvaluationSession constructor and add FsiEvaluationSession.Create static method to allow for future API that can return errors
+* Return additional 'property' and 'event' methods for F#-defined types to regularize symbols (#108, #143)
+* Add IsPropertySetterMethod and IsPropertyGetterMethod which only return true for getter/setter methods, not properties. Deprecate IsSetterMethod and IsGetterMethod in favour of these.
+* Add IsEventAddMethod and IsEventRemoveMethod which return true for add/remove methods with an associated event
+* Change IsProperty and IsEvent to only return true for the symbols for properties and events, rather than the methods associated with these
+* Fix value of Assembly for some symbols (e.g. property symbols)
+
+### 0.0.45 -
+
+* Add optional project cache size parameter to InteractiveChecker
+* Switch to openBinariesInMemory for SimpleSourceCodeServices
+* Cleanup SimpleSourceCodeServices to avoid code duplication
+
+### 0.0.44 -
+
+* Integrate latest changes from visualfsharp.codeplex.com via github.com/fsharp/fsharp
+* Fix problem with task that generates description text of declaration
+* Add AllInterfaceTypes to FSharpEntity and FSharpType
+* Add BaseType to FSharpType to propagate instantiation
+* Add Instantiate to FSharpType
+
+### 0.0.43 -
+
+* Fix #109 - Duplicates in GetUsesOfSymbolInFile
+
+### 0.0.42 -
+
+* Fix #105 - Register enum symbols in patterns
+* Fix #107 - Return correct results for inheritance chain of .NET types
+* Fix #101 - Add DeclaringEntity property
+
+### 0.0.41 -
+
+* Fixed #104 - Make all operations that may utilize the FCS reactor async
+* Add FSharpDisplayContext and FSharpType.Format
+* Replace GetSymbolAtLocationAlternate by GetSymbolUseAtLocation
+
+### 0.0.40 -
+
+* Fixed #86 - Expose Microsoft.FSharp.Compiler.Interactive.Shell.Settings.fsi
+* Fixed #99 - Add IsNamespace property to FSharpEntity
+
+### 0.0.39 -
+
+* Fixed #79 - Usage points for symbols in union patterns
+
+### 0.0.38 -
+
+* Fixed #94 and #89 by addition of new properties to the FSharpSymbolUse type
+* Fixed #93 by addition of IsOpaque to FSharpEntity type
+* Fixed #92 - Issue with nested classes
+* Fixed #87 - Allow analysis of members from external assemblies
+
+### 0.0.37 -
+
+* Obsolete HasDefaultValue - see https://github.com/fsharp/FSharp.Compiler.Service/issues/77
+
+### 0.0.36 -
+
+* Fix #71 - Expose static parameters and xml docs of type providers
+* Fix #63 - SourceCodeServices: #r ignores include paths passed as command-line flags
+
+### 0.0.35 -
+
+* Fix #38 - FSharp.Compiler.Services should tolerate an FSharp.Core without siginfo/optdata in the search path
+
+
+### 0.0.34 -
+
+* Add StaticParameters property to entities, plus FSharpStaticParameter symbol
+* Fix #65
+
+### 0.0.33 -
+
+* Add FullName and Assembly properties for symbols
+* Fix #76
+* Add Japanese documentation
+
+### 0.0.32 -
+
+* Make ParseFileInProject asynchronous
+* Add ParseAndCheckFileInProject
+* Use cached results in ParseAndCheckFileInProject if available
+
+### 0.0.31 -
+
+* Fix performance problem with CheckFileInProject
+
+### 0.0.30 -
+
+* Add initial prototype version of multi-project support, through optional ProjectReferences in ProjectOptions. Leave this empty
+ to use DLL/file-based references to results from other projects.
+
+### 0.0.29 -
+
+* Fix symbols for named union fields in patterns
+
+### 0.0.28 -
+
+* Fix symbols for named union fields
+* Add FSharpActivePatternCase to refine FSharpSymbol
+
+### 0.0.27 -
+
+* Fix exception tag symbol reporting
+
+### 0.0.26 -
+
+* Fix off-by-one in reporting of range for active pattern name
+
+### 0.0.25 -
+
+* Add optional source argument to TryGetRecentTypeCheckResultsForFile to specify that source must match exactly
+
+### 0.0.24 -
+
+* Update version number as nuget package may not have published properly
+
+### 0.0.23 -
+
+* Move to one-based line numbering everywhere
+* Provide better symbol information for active patterns
+
+### 0.0.22 -
+
+* Provide symbol location for type parameters
+
+### 0.0.21 -
+
+* Add GetUsesOfSymbolInFile
+* Better symbol resolution results for type parameter symbols
+
+### 0.0.20 -
+
+* Update version number as nuget package may not have published properly
+
+### 0.0.19 -
+
+* Change return type of GetAllUsesOfSymbol, GetAllUsesOfAllSymbols and GetAllUsesOfAllSymbolsInFile to FSharpSymbolUse
+* Add symbol uses when an abstract member is implemented.
+
+### 0.0.18 -
+
+* Add GetAllUsesOfAllSymbols and GetAllUsesOfAllSymbolsInFile
+
+### 0.0.17 -
+
+* Improvements to symbol accuracy w.r.t. type abbreviations
+
+### 0.0.16 -
+
+* Make FSharpEntity.BaseType return an option
+* FsiSesion got a new "EvalScript" method which allows to evaluate .fsx files
+
+### 0.0.15 -
+
+* Update version number as nuget package may not have published properly
+
+### 0.0.14 -
+
+* Update version number as nuget package may not have published properly
+
+### 0.0.13-alpha -
+
+* Fix #39 - Constructor parameters are mistaken for record fields in classes
+
+### 0.0.12-alpha -
+
+* Make the parts of the lexer/parser used by 'XmlDoc' tools in F# VS Power tools public
+
+### 0.0.11-alpha -
+
+* Add 'IsUnresolved'
+
+### 0.0.10-alpha -
+
+* Fix bug where 'multiple references to FSharp.Core' was given as error for scripts
+
+### 0.0.9-alpha -
+
+* Fix fsc corrupting assemblies when generating pdb files (really)
+* Give better error messages for missing assemblies
+* Report more information about symbols returned by GetSymbolAtLocation (through subtypes)
+* Fix typos in docs
+* Return full project results from ParseAndCheckInteraction
+* Be more robust to missing assembly references by default.
+
+### 0.0.8-alpha -
+
+* Fix fsc corrupting assemblies when generating pdb files
+
+### 0.0.7-alpha -
+
+* Fix docs
+* Make symbols more robust to missing assemblies
+* Be robust to failures on IncrementalBuilder creation
+* Allow use of MSBuild resolution by IncrementalBuilder
+
+### 0.0.6-alpha -
+
+* Fix version number
+
+### 0.0.5-alpha -
+
+* Added GetUsesOfSymbol(), FSharpSymbol type, GetSymbolAtLocation(...)
+
+### 0.0.4-alpha -
+
+* Added documentation of file system API
+* Reporte errors correctly from ParseAndCheckProject
+
+### 0.0.3-alpha -
+
+* Integrate FSharp.PowerPack.Metadata as the FSharp* symbol API
+* Renamed Param --> MethodGroupItemParameter and hid record from view, made into an object
+* Renamed Method --> MethodGroupItem and hid record from view, made into an object
+* Renamed Methods --> MethodGroup and hid record from view, made into an object
+* Renamed MethodGroup.Name --> MethodGroup.MethodName
+* Renamed DataTip --> ToolTip consistently across all text
+* Renamed CheckOptions --> ProjectOptions
+* Renamed TypeCheckAnswer --> CheckFileAnswer
+* Renamed UntypedParseInfo --> ParseFileResults
+* Removed GetCheckOptionsFromScriptRoot member overload in favour of optional argument
+* Renamed GetCheckOptionsFromScriptRoot --> GetProjectOptionsFromScript
+* Renamed UntypedParse --> ParseFileInProject
+* Renamed TypeCheckSource --> CheckFileInProjectIfReady
+* Added numerous methods to API including CheckFileInProject
+* Added experimental GetBackgroundCheckResultsForFileInProject, GetBackgroundParseResultsForFileInProject
+* Added PartialAssemblySignature to TypeCheckResults/CheckFileResults
+* Added CurrentPartialAssemblySignature to FsiEvaluationSession
+* Added ParseAndCheckInteraction to FsiEvaluationSession to support intellisense implementation against a script fragment
+* Added initial testing in tests/service
+* Added ParseAndCheckProject to SourceCodeServices API. This will eventually return "whole project" information such as symbol tables.
+* Added GetDefaultConfiguration to simplify process of configuring FsiEvaluationSession
+* Added PartialAssemblySignatureUpdated event to FsiEvaluationSession
+* Added travis build
+
+### 0.0.2-alpha -
+
+* Integrate hosted FSI configuration, SimpleSourceCodeServices, cleanup to SourceCodeServices API
+
+## Older Visual F# releases
### [4.0.0] - Visual Studio 2015 Update 1 - 30 November 2015
#### Enhancements
+
* Perf: `for i in expr do body` optimization [#219](https://github.com/Microsoft/visualfsharp/pull/219)
* Remove type provider security dialog and use custom icon for type provider assembly reference [#448](https://github.com/Microsoft/visualfsharp/pull/448)
* Perf: Enable parallel build inside Visual Studio [#487](https://github.com/Microsoft/visualfsharp/pull/487)
@@ -221,6 +1729,7 @@ Most items here contributed by community members.
* Add a compiler warning for lower case literals in patterns [#666](https://github.com/Microsoft/visualfsharp/pull/666)
#### Bug fixes
+
* Fix scope of types for named values in attributes improperly set [#437](https://github.com/Microsoft/visualfsharp/pull/437)
* Add general check for escaping typars to check phase [#442](https://github.com/Microsoft/visualfsharp/pull/442)
* Fix AccessViolationException on obfuscated assemblies [#519](https://github.com/Microsoft/visualfsharp/pull/519)
@@ -239,15 +1748,15 @@ Includes commits up to `dd8252eb8d20aaedf7b1c7576cd2a8a82d24f587`
#### Language, compiler, runtime, interactive
* Normalization and expansion of `Array`, `List`, and `Seq` modules
- * New APIs for 4.0: `chunkBySize`, `contains`, `except`, `findBack`, `findInstanceBack`, `indexed`, `item`, `mapFold`, `mapFoldBack`, `sortByDescending`, `sortDescending`, `splitInto`, `tryFindBack`, `tryFindIndexBack`, `tryHead`, `tryItem`, `tryLast`
+* New APIs for 4.0: `chunkBySize`, `contains`, `except`, `findBack`, `findInstanceBack`, `indexed`, `item`, `mapFold`, `mapFoldBack`, `sortByDescending`, `sortDescending`, `splitInto`, `tryFindBack`, `tryFindIndexBack`, `tryHead`, `tryItem`, `tryLast`

* Other new APIs
- * `Option.filter`, `Option.toObj`, `Option.ofObj`, `Option.toNullable`, `Option.ofNullable`
- * `String.filter`
- * `Checked.int8`, `Checked.uint8`
- * `Async.AwaitTask` (non-generic)
- * `WebClient.AsyncDownloadFile`, `WebClient.AsyncDownloadData`
- * `tryUnbox`, `isNull`
+* `Option.filter`, `Option.toObj`, `Option.ofObj`, `Option.toNullable`, `Option.ofNullable`
+* `String.filter`
+* `Checked.int8`, `Checked.uint8`
+* `Async.AwaitTask` (non-generic)
+* `WebClient.AsyncDownloadFile`, `WebClient.AsyncDownloadData`
+* `tryUnbox`, `isNull`
* New active pattern to match constant `Decimal` in quotations
* Slicing support for lists
* Support for consuming high-rank (> 4) arrays
@@ -409,7 +1918,6 @@ Includes commits up to `3385e58aabc91368c8e1f551650ba48705aaa285`
* Bugfix: Typos in tutorial project script
* Bugfix: Required C# event members do not appear in intellisense when signature is (object, byref)
-
### [3.1.1] - 24 January 2014
#### Language, compiler, runtime, interactive
@@ -431,3 +1939,111 @@ Includes commits up to `3385e58aabc91368c8e1f551650ba48705aaa285`
[3.1.2]: http://blogs.msdn.com/b/fsharpteam/archive/2014/08/20/announcing-the-release-of-visual-f-tools-3-1-2.aspx
[3.1.1]: http://blogs.msdn.com/b/fsharpteam/archive/2014/01/22/announcing-visual-f-3-1-1-and-support-for-desktop-express.aspx
+
+Features Added in F# Language Versions
+======================================
+
+# [F# 4.7](https://docs.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-47)
+
+- Compiler support for `LangVersion`
+- Implicit `yield`s
+- No more required double underscore (wildcard identifier)
+- Indentation relaxations for parameters passed to constructors and static methods
+
+# [F# 4.6](https://docs.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-46)
+
+- Anonymous records
+- `ValueOption` module functions
+
+# [F# 4.5](https://docs.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-45)
+
+- Versioning alignment of binary, package, and language
+- Support for `Span<'T>` and related types
+- Ability to produce `byref` returns
+- The `voidptr` type
+- The `inref<'T>` and `outref<'T>` types to represent readonly and write-only `byref`s
+- `IsByRefLike` structs
+- `IsReadOnly` structs
+- Extension method support for `byref<'T>`/`inref<'T>`/`outref<'T>`
+- `match!` keyword in computation expressions
+- Relaxed upcast with `yield` in F# sequence/list/array expressions
+- Relaxed indentation with list and array expressions
+- Enumeration cases emitted as public
+
+# [F# 4.1](https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf)
+
+- Struct tuples which inter-operate with C# tuples
+- Struct annotations for Records
+- Struct annotations for Single-case Discriminated Unions
+- Underscores in numeric literals
+- Caller info argument attributes
+- Result type and some basic Result functions
+- Mutually referential types and modules within the same file
+- Implicit `Module` syntax on modules with shared name as type
+- Byref returns, supporting consuming C# `ref`-returning methods
+- Error message improvements
+- Support for `fixed`
+
+# [F# 4.0](https://fsharp.org/specs/language-spec/4.0/FSharpSpec-4.0-final.pdf)
+
+- `printf` on unitized values
+- Extension property initializers
+- Non-null provided types
+- Primary constructors as functions
+- Static parameters for provided methods
+- `printf` interpolation
+- Extended `#if` grammar
+- Multiple interface instantiations
+- Optional type args
+- Params dictionaries
+
+# [F# 3.1](https://fsharp.org/specs/language-spec/3.1/FSharpSpec-3.1-final.pdf)
+
+- Named union type fields
+- Extensions to array slicing
+- Type inference enhancements
+
+# [F# 3.0](https://fsharp.org/specs/language-spec/3.0/FSharpSpec-3.0-final.pdf)
+
+- Type providers
+- LINQ query expressions
+- CLIMutable attribute
+- Triple-quoted strings
+- Auto-properties
+- Provided units-of-measure
+
+# [F# 2.0](https://fsharp.org/specs/language-spec/2.0/FSharpSpec-2.0-April-2012.pdf)
+
+- Active patterns
+- Units of measure
+- Sequence expressions
+- Asynchronous programming
+- Agent programming
+- Extension members
+- Named arguments
+- Optional arguments
+- Array slicing
+- Quotations
+- Native interoperability
+- Computation expressions
+
+# [F# 1.1](https://docs.microsoft.com/en-us/archive/blogs/dsyme/a-taste-of-whats-new-in-f-1-1)
+
+- Interactive environment
+- Object programming
+- Encapsulation Extensions
+
+# [F# 1.0](https://docs.microsoft.com/en-us/archive/blogs/dsyme/welcome-to-dons-f-blog)
+
+- Discriminated unions
+- Records
+- Tuples
+- Pattern matching
+- Type abbreviations
+- Object expressions
+- Structs
+- Signature files
+- Imperative programming
+- Modules (no functors)
+- Nested modules
+- .NET Interoperability
diff --git a/scripts/dotnet-install.ps1 b/scripts/dotnet-install.ps1
index 9da0947d958..3dc96520540 100644
--- a/scripts/dotnet-install.ps1
+++ b/scripts/dotnet-install.ps1
@@ -188,7 +188,7 @@ function GetHTTPResponse([Uri] $Uri)
}
# Default timeout for HttpClient is 100s. For a 50 MB download this assumes 500 KB/s average, any less will time out
# 10 minutes allows it to work over much slower connections.
- $HttpClient.Timeout = New-TimeSpan -Minutes 20
+ $HttpClient.Timeout = New-TimeSpan -Minutes 40
$Response = $HttpClient.GetAsync($Uri).Result
if (($Response -eq $null) -or (-not ($Response.IsSuccessStatusCode)))
{
diff --git a/scripts/init-tools.sh b/scripts/init-tools.sh
index 67067dd4867..178d1bca003 100644
--- a/scripts/init-tools.sh
+++ b/scripts/init-tools.sh
@@ -9,7 +9,7 @@ __DOTNET_PATH=$__TOOLRUNTIME_DIR/dotnetcli
__DOTNET_CMD=$__DOTNET_PATH/dotnet
__DOTNET_VERSION=$(cat $__scriptpath/../DotnetCLIVersion.txt)
-if [ -z "$__BUILDTOOLS_SOURCE" ]; then __BUILDTOOLS_SOURCE=https://dotnet.myget.org/F/dotnet-buildtools/api/v3/index.json; fi
+if [ -z "$__BUILDTOOLS_SOURCE" ]; then __BUILDTOOLS_SOURCE=https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json; fi
__BUILD_TOOLS_PACKAGE_VERSION=$(cat $__scriptpath/../BuildToolsVersion.txt)
diff --git a/setup/Swix/Directory.Build.targets b/setup/Swix/Directory.Build.targets
index 7e50ced3f2b..5e826e8da63 100644
--- a/setup/Swix/Directory.Build.targets
+++ b/setup/Swix/Directory.Build.targets
@@ -15,7 +15,7 @@
+ Condition="'$(DotNetBuildFromSource)' != 'true' AND '$(ArcadeBuildFromSource)' != 'true'">
diff --git a/setup/Swix/Microsoft.FSharp.Compiler.MSBuild/Microsoft.FSharp.Compiler.MSBuild.csproj b/setup/Swix/Microsoft.FSharp.Compiler.MSBuild/Microsoft.FSharp.Compiler.MSBuild.csproj
index cc9d75a2887..f0bdb3b4b18 100644
--- a/setup/Swix/Microsoft.FSharp.Compiler.MSBuild/Microsoft.FSharp.Compiler.MSBuild.csproj
+++ b/setup/Swix/Microsoft.FSharp.Compiler.MSBuild/Microsoft.FSharp.Compiler.MSBuild.csproj
@@ -15,10 +15,6 @@
-
-
-
-
+
@@ -58,6 +59,7 @@
+
diff --git a/src/buildtools/fslex/Parsing.fsi b/src/buildtools/fslex/Parsing.fsi
index 2fef45975a8..f4d12606462 100644
--- a/src/buildtools/fslex/Parsing.fsi
+++ b/src/buildtools/fslex/Parsing.fsi
@@ -100,7 +100,7 @@ type Tables<'tok> =
/// Interpret the parser table taking input from the given lexer, using the given lex buffer, and the given start state.
/// Returns an object indicating the final synthesized value for the parse.
- member Interpret : lexer:(LexBuffer<'char> -> 'tok) * lexbuf:LexBuffer<'char> * startState:int -> obj
+ member Interpret : lexer:(LexBuffer<'char> -> 'tok) * lexbuf:LexBuffer<'char> * initialState:int -> obj
#if INTERNALIZED_FSLEXYACC_RUNTIME
exception internal Accept of obj
diff --git a/src/buildtools/fslex/fslex.fsproj b/src/buildtools/fslex/fslex.fsproj
index 349d981c4a1..180448b3841 100644
--- a/src/buildtools/fslex/fslex.fsproj
+++ b/src/buildtools/fslex/fslex.fsproj
@@ -3,7 +3,9 @@
Exe
net472
- INTERNALIZED_FSLEXYACC_RUNTIME;$(DefineConstant)
+ netcoreapp3.0
+ netcoreapp3.1
+ INTERNALIZED_FSLEXYACC_RUNTIME;$(DefineConstants)
true
diff --git a/src/buildtools/fsyacc/fsyacc.fsproj b/src/buildtools/fsyacc/fsyacc.fsproj
index a52a70c96da..9139a2e8986 100644
--- a/src/buildtools/fsyacc/fsyacc.fsproj
+++ b/src/buildtools/fsyacc/fsyacc.fsproj
@@ -3,7 +3,9 @@
Exe
net472
- INTERNALIZED_FSLEXYACC_RUNTIME;$(DefineConstant)
+ netcoreapp3.0
+ netcoreapp3.1
+ INTERNALIZED_FSLEXYACC_RUNTIME;$(DefineConstants)
true
diff --git a/src/fsharp/AccessibilityLogic.fs b/src/fsharp/AccessibilityLogic.fs
index 4070ea9b402..bda68abc118 100644
--- a/src/fsharp/AccessibilityLogic.fs
+++ b/src/fsharp/AccessibilityLogic.fs
@@ -7,9 +7,10 @@ open FSharp.Compiler.AbstractIL.IL
open FSharp.Compiler
open FSharp.Compiler.ErrorLogger
open FSharp.Compiler.Infos
-open FSharp.Compiler.Tast
-open FSharp.Compiler.Tastops
open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.TypedTree
+open FSharp.Compiler.TypedTreeBasics
+open FSharp.Compiler.TypedTreeOps
#if !NO_EXTENSIONTYPING
open FSharp.Compiler.ExtensionTyping
@@ -18,11 +19,9 @@ open FSharp.Compiler.ExtensionTyping
/// Represents the 'keys' a particular piece of code can use to access other constructs?.
[]
type AccessorDomain =
- /// AccessibleFrom(cpaths, tyconRefOpt)
- ///
/// cpaths: indicates we have the keys to access any members private to the given paths
/// tyconRefOpt: indicates we have the keys to access any protected members of the super types of 'TyconRef'
- | AccessibleFrom of CompilationPath list * TyconRef option
+ | AccessibleFrom of cpaths: CompilationPath list * tyconRefOpt: TyconRef option
/// An AccessorDomain which returns public items
| AccessibleFromEverywhere
@@ -45,6 +44,7 @@ type AccessorDomain =
| AccessibleFromEverywhere -> 2
| AccessibleFromSomeFSharpCode -> 3
| AccessibleFromSomewhere -> 4
+
static member CustomEquals(g:TcGlobals, ad1:AccessorDomain, ad2:AccessorDomain) =
match ad1, ad2 with
| AccessibleFrom(cs1, tc1), AccessibleFrom(cs2, tc2) -> (cs1 = cs2) && (match tc1, tc2 with None, None -> true | Some tc1, Some tc2 -> tyconRefEq g tc1 tc2 | _ -> false)
@@ -207,12 +207,13 @@ and IsTypeInstAccessible g amap m ad tinst =
/// Indicate if a provided member is accessible
let IsProvidedMemberAccessible (amap:Import.ImportMap) m ad ty access =
let g = amap.g
- let isTyAccessible = IsTypeAccessible g amap m ad ty
- if not isTyAccessible then false
+ if IsTypeAccessible g amap m ad ty then
+ match tryTcrefOfAppTy g ty with
+ | ValueNone -> true
+ | ValueSome tcrefOfViewedItem ->
+ IsILMemberAccessible g amap m tcrefOfViewedItem ad access
else
- not (isAppTy g ty) ||
- let tcrefOfViewedItem = tcrefOfAppTy g ty
- IsILMemberAccessible g amap m tcrefOfViewedItem ad access
+ false
/// Compute the accessibility of a provided member
let ComputeILAccess isPublic isFamily isFamilyOrAssembly isFamilyAndAssembly =
@@ -222,7 +223,6 @@ let ComputeILAccess isPublic isFamily isFamilyOrAssembly isFamilyAndAssembly =
elif isFamilyAndAssembly then ILMemberAccess.FamilyAndAssembly
else ILMemberAccess.Private
-/// IndiCompute the accessibility of a provided member
let IsILFieldInfoAccessible g amap m ad x =
match x with
| ILFieldInfo (tinfo, fd) -> IsILTypeAndMemberAccessible g amap m ad ad tinfo fd.Access
@@ -247,12 +247,53 @@ let private IsILMethInfoAccessible g amap m adType ad ilminfo =
let GetILAccessOfILPropInfo (ILPropInfo(tinfo, pdef)) =
let tdef = tinfo.RawMetadata
let ilAccess =
- match pdef.GetMethod with
- | Some mref -> (resolveILMethodRef tdef mref).Access
- | None ->
- match pdef.SetMethod with
- | None -> ILMemberAccess.Public
- | Some mref -> (resolveILMethodRef tdef mref).Access
+ match pdef.GetMethod, pdef.SetMethod with
+ | Some mref, None
+ | None, Some mref -> (resolveILMethodRef tdef mref).Access
+
+ | Some mrefGet, Some mrefSet ->
+ //
+ // Dotnet properties have a getter and a setter method, each of which can have a separate visibility public, protected, private etc ...
+ // This code computes the visibility for the property by choosing the most visible method. This approximation is usefull for cases
+ // where the compiler needs to know the visibility of the property.
+ // The specific ordering for choosing the most visible is:
+ // ILMemberAccess.Public,
+ // ILMemberAccess.FamilyOrAssembly
+ // ILMemberAccess.Assembly
+ // ILMemberAccess.Family
+ // ILMemberAccess.FamilyAndAssembly
+ // ILMemberAccess.Private
+ // ILMemberAccess.CompilerControlled
+ //
+ let getA = (resolveILMethodRef tdef mrefGet).Access
+ let setA = (resolveILMethodRef tdef mrefSet).Access
+
+ // Use the accessors to determine the visibility of the property.
+ // N.B. It is critical to keep the ordering in decreasing visibility order in the following match expression
+ match getA, setA with
+ | ILMemberAccess.Public, _
+ | _, ILMemberAccess.Public -> ILMemberAccess.Public
+
+ | ILMemberAccess.FamilyOrAssembly, _
+ | _, ILMemberAccess.FamilyOrAssembly -> ILMemberAccess.FamilyOrAssembly
+
+ | ILMemberAccess.Assembly, _
+ | _, ILMemberAccess.Assembly -> ILMemberAccess.Assembly
+
+ | ILMemberAccess.Family, _
+ | _, ILMemberAccess.Family -> ILMemberAccess.Family
+
+ | ILMemberAccess.FamilyAndAssembly, _
+ | _, ILMemberAccess.FamilyAndAssembly -> ILMemberAccess.FamilyAndAssembly
+
+ | ILMemberAccess.Private, _
+ | _, ILMemberAccess.Private -> ILMemberAccess.Private
+
+ | ILMemberAccess.CompilerControlled, _
+ | _, ILMemberAccess.CompilerControlled -> ILMemberAccess.CompilerControlled
+
+ | None, None -> ILMemberAccess.Public
+
ilAccess
let IsILPropInfoAccessible g amap m ad pinfo =
@@ -321,8 +362,11 @@ let IsMethInfoAccessible amap m ad minfo = IsTypeAndMethInfoAccessible amap m ad
let IsPropInfoAccessible g amap m ad = function
| ILProp ilpinfo -> IsILPropInfoAccessible g amap m ad ilpinfo
- | FSProp (_, _, Some vref, _)
- | FSProp (_, _, _, Some vref) -> IsValAccessible ad vref
+ | FSProp (_, _, Some vref, None)
+ | FSProp (_, _, None, Some vref) -> IsValAccessible ad vref
+ | FSProp (_, _, Some vrefGet, Some vrefSet) ->
+ // pick most accessible
+ IsValAccessible ad vrefGet || IsValAccessible ad vrefSet
#if !NO_EXTENSIONTYPING
| ProvidedProp (amap, tppi, m) as pp->
let access =
@@ -341,4 +385,3 @@ let IsPropInfoAccessible g amap m ad = function
let IsFieldInfoAccessible ad (rfref:RecdFieldInfo) =
IsAccessible ad rfref.RecdField.Accessibility
-
diff --git a/src/fsharp/AccessibilityLogic.fsi b/src/fsharp/AccessibilityLogic.fsi
new file mode 100644
index 00000000000..7169ce9774e
--- /dev/null
+++ b/src/fsharp/AccessibilityLogic.fsi
@@ -0,0 +1,100 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+/// The basic logic of private/internal/protected/InternalsVisibleTo/public accessibility
+module internal FSharp.Compiler.AccessibilityLogic
+
+open FSharp.Compiler.AbstractIL.IL
+open FSharp.Compiler
+open FSharp.Compiler.Import
+open FSharp.Compiler.Infos
+open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.Text
+open FSharp.Compiler.TypedTree
+
+/// Represents the 'keys' a particular piece of code can use to access other constructs?.
+[]
+type AccessorDomain =
+ /// cpaths: indicates we have the keys to access any members private to the given paths
+ /// tyconRefOpt: indicates we have the keys to access any protected members of the super types of 'TyconRef'
+ | AccessibleFrom of cpaths: CompilationPath list * tyconRefOpt: TyconRef option
+
+ /// An AccessorDomain which returns public items
+ | AccessibleFromEverywhere
+
+ /// An AccessorDomain which returns everything but .NET private/internal items.
+ /// This is used
+ /// - when solving member trait constraints, which are solved independently of accessibility
+ /// - for failure paths in error reporting, e.g. to produce an error that an F# item is not accessible
+ /// - an adhoc use in service.fs to look up a delegate signature
+ | AccessibleFromSomeFSharpCode
+
+ /// An AccessorDomain which returns all items
+ | AccessibleFromSomewhere
+
+ // Hashing and comparison is used for the memoization tables keyed by an accessor domain.
+ // It is dependent on a TcGlobals because of the TyconRef in the data structure
+ static member CustomEquals: g:TcGlobals * ad1:AccessorDomain * ad2:AccessorDomain -> bool
+
+ // Hashing and comparison is used for the memoization tables keyed by an accessor domain.
+ // It is dependent on a TcGlobals because of the TyconRef in the data structure
+ static member CustomGetHashCode: ad:AccessorDomain -> int
+
+/// Indicates if an F# item is accessible
+val IsAccessible: ad:AccessorDomain -> taccess:TypedTree.Accessibility -> bool
+
+/// Indicates if an entity is accessible
+val IsEntityAccessible: amap:ImportMap -> m:range -> ad:AccessorDomain -> tcref:TypedTree.TyconRef -> bool
+
+/// Check that an entity is accessible
+val CheckTyconAccessible: amap:ImportMap -> m:range -> ad:AccessorDomain -> tcref:TypedTree.TyconRef -> bool
+
+/// Indicates if a type definition and its representation contents are accessible
+val IsTyconReprAccessible: amap:ImportMap -> m:range -> ad:AccessorDomain -> tcref:TypedTree.TyconRef -> bool
+
+/// Check that a type definition and its representation contents are accessible
+val CheckTyconReprAccessible: amap:ImportMap -> m:range -> ad:AccessorDomain -> tcref:TypedTree.TyconRef -> bool
+
+/// Indicates if a type is accessible (both definition and instantiation)
+val IsTypeAccessible: g:TcGlobals -> amap:ImportMap -> m:range -> ad:AccessorDomain -> ty:TypedTree.TType -> bool
+
+val IsTypeInstAccessible: g:TcGlobals -> amap:ImportMap -> m:range -> ad:AccessorDomain -> tinst:TypedTree.TypeInst -> bool
+
+/// Indicate if a provided member is accessible
+val IsProvidedMemberAccessible: amap:ImportMap -> m:range -> ad:AccessorDomain -> ty:TypedTree.TType -> access:ILMemberAccess -> bool
+
+/// Compute the accessibility of a provided member
+val ComputeILAccess: isPublic:bool -> isFamily:bool -> isFamilyOrAssembly:bool -> isFamilyAndAssembly:bool -> ILMemberAccess
+
+val IsILFieldInfoAccessible: g:TcGlobals -> amap:ImportMap -> m:range -> ad:AccessorDomain -> x:ILFieldInfo -> bool
+
+val GetILAccessOfILEventInfo: ILEventInfo -> ILMemberAccess
+
+val IsILEventInfoAccessible: g:TcGlobals -> amap:ImportMap -> m:range -> ad:AccessorDomain -> einfo:ILEventInfo -> bool
+
+val GetILAccessOfILPropInfo: ILPropInfo -> ILMemberAccess
+
+val IsILPropInfoAccessible: g:TcGlobals -> amap:ImportMap -> m:range -> ad:AccessorDomain -> pinfo:ILPropInfo -> bool
+
+val IsValAccessible: ad:AccessorDomain -> vref:TypedTree.ValRef -> bool
+
+val CheckValAccessible: m:range -> ad:AccessorDomain -> vref:TypedTree.ValRef -> unit
+
+val IsUnionCaseAccessible: amap:ImportMap -> m:range -> ad:AccessorDomain -> ucref:TypedTree.UnionCaseRef -> bool
+
+val CheckUnionCaseAccessible: amap:ImportMap -> m:range -> ad:AccessorDomain -> ucref:TypedTree.UnionCaseRef -> bool
+
+val IsRecdFieldAccessible: amap:ImportMap -> m:range -> ad:AccessorDomain -> rfref:TypedTree.RecdFieldRef -> bool
+
+val CheckRecdFieldAccessible: amap:ImportMap -> m:range -> ad:AccessorDomain -> rfref:TypedTree.RecdFieldRef -> bool
+
+val CheckRecdFieldInfoAccessible: amap:ImportMap -> m:range -> ad:AccessorDomain -> rfinfo:RecdFieldInfo -> unit
+
+val CheckILFieldInfoAccessible: g:TcGlobals -> amap:ImportMap -> m:range -> ad:AccessorDomain -> finfo:ILFieldInfo -> unit
+
+val IsTypeAndMethInfoAccessible: amap:ImportMap -> m:range -> accessDomainTy:AccessorDomain -> ad:AccessorDomain -> _arg1:MethInfo -> bool
+
+val IsMethInfoAccessible: amap:ImportMap -> m:range -> ad:AccessorDomain -> minfo:MethInfo -> bool
+
+val IsPropInfoAccessible: g:TcGlobals ->amap:ImportMap -> m:range -> ad:AccessorDomain -> _arg1:PropInfo -> bool
+
+val IsFieldInfoAccessible: ad:AccessorDomain -> rfref:RecdFieldInfo -> bool
diff --git a/src/fsharp/AttributeChecking.fs b/src/fsharp/AttributeChecking.fs
index 07ac05faa82..6f4d7a5f60c 100644
--- a/src/fsharp/AttributeChecking.fs
+++ b/src/fsharp/AttributeChecking.fs
@@ -4,21 +4,22 @@
/// on items from name resolution
module internal FSharp.Compiler.AttributeChecking
+open System
open System.Collections.Generic
open FSharp.Compiler.AbstractIL.IL
open FSharp.Compiler.AbstractIL.Internal.Library
open FSharp.Compiler
-open FSharp.Compiler.Range
open FSharp.Compiler.ErrorLogger
open FSharp.Compiler.Infos
-open FSharp.Compiler.Tast
-open FSharp.Compiler.Tastops
open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.Text
+open FSharp.Compiler.TypedTree
+open FSharp.Compiler.TypedTreeOps
#if !NO_EXTENSIONTYPING
open FSharp.Compiler.ExtensionTyping
-open Microsoft.FSharp.Core.CompilerServices
+open FSharp.Core.CompilerServices
#endif
exception ObsoleteWarning of string * range
@@ -78,6 +79,11 @@ type AttribInfo =
| FSAttribInfo of TcGlobals * Attrib
| ILAttribInfo of TcGlobals * Import.ImportMap * ILScopeRef * ILAttribute * range
+ member x.Range =
+ match x with
+ | FSAttribInfo(_, attrib) -> attrib.Range
+ | ILAttribInfo (_, _, _, _, m) -> m
+
member x.TyconRef =
match x with
| FSAttribInfo(_g, Attrib(tcref, _, _, _, _, _, _)) -> tcref
@@ -173,29 +179,6 @@ let GetAttribInfosOfEvent amap m einfo =
| ProvidedEvent _ -> []
#endif
-/// Analyze three cases for attributes declared on type definitions: IL-declared attributes, F#-declared attributes and
-/// provided attributes.
-//
-// This is used for AttributeUsageAttribute, DefaultMemberAttribute and ConditionalAttribute (on attribute types)
-let TryBindTyconRefAttribute g m (AttribInfo (atref, _) as args) (tcref:TyconRef) f1 f2 f3 =
- ignore m; ignore f3
- match metadataOfTycon tcref.Deref with
-#if !NO_EXTENSIONTYPING
- | ProvidedTypeMetadata info ->
- let provAttribs = info.ProvidedType.PApply((fun a -> (a :> IProvidedCustomAttributeProvider)), m)
- match provAttribs.PUntaint((fun a -> a.GetAttributeConstructorArgs(provAttribs.TypeProvider.PUntaintNoFailure(id), atref.FullName)), m) with
- | Some args -> f3 args
- | None -> None
-#endif
- | ILTypeMetadata (TILObjectReprData(_, _, tdef)) ->
- match TryDecodeILAttribute g atref tdef.CustomAttrs with
- | Some attr -> f1 attr
- | _ -> None
- | FSharpOrArrayOrByrefOrTupleOrExnTypeMetadata ->
- match TryFindFSharpAttribute g args tcref.Attribs with
- | Some attr -> f2 attr
- | _ -> None
-
/// Analyze three cases for attributes declared on methods: IL-declared attributes, F#-declared attributes and
/// provided attributes.
let BindMethInfoAttributes m minfo f1 f2 f3 =
@@ -210,9 +193,8 @@ let BindMethInfoAttributes m minfo f1 f2 f3 =
/// Analyze three cases for attributes declared on methods: IL-declared attributes, F#-declared attributes and
/// provided attributes.
-let TryBindMethInfoAttribute g m (AttribInfo(atref, _) as attribSpec) minfo f1 f2 f3 =
-#if !NO_EXTENSIONTYPING
-#else
+let TryBindMethInfoAttribute g (m: range) (AttribInfo(atref, _) as attribSpec) minfo f1 f2 f3 =
+#if NO_EXTENSIONTYPING
// to prevent unused parameter warning
ignore f3
#endif
@@ -231,7 +213,7 @@ let TryBindMethInfoAttribute g m (AttribInfo(atref, _) as attribSpec) minfo f1 f
/// Try to find a specific attribute on a method, where the attribute accepts a string argument.
///
/// This is just used for the 'ConditionalAttribute' attribute
-let TryFindMethInfoStringAttribute g m attribSpec minfo =
+let TryFindMethInfoStringAttribute g (m: range) attribSpec minfo =
TryBindMethInfoAttribute g m attribSpec minfo
(function ([ILAttribElem.String (Some msg) ], _) -> Some msg | _ -> None)
(function (Attrib(_, _, [ AttribStringArg msg ], _, _, _, _)) -> Some msg | _ -> None)
@@ -246,7 +228,6 @@ let MethInfoHasAttribute g m attribSpec minfo =
|> Option.isSome
-
/// Check IL attributes for 'ObsoleteAttribute', returning errors and warnings as data
let private CheckILAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs m =
let (AttribInfo(tref,_)) = g.attrib_SystemObsolete
@@ -265,11 +246,19 @@ let private CheckILAttributes (g: TcGlobals) isByrefLikeTyconRef cattrs m =
| _ ->
CompleteD
+let langVersionPrefix = "--langversion:preview"
+
/// Check F# attributes for 'ObsoleteAttribute', 'CompilerMessageAttribute' and 'ExperimentalAttribute',
/// returning errors and warnings as data
-let CheckFSharpAttributes g attribs m =
- if isNil attribs then CompleteD
- else
+let CheckFSharpAttributes (g:TcGlobals) attribs m =
+ let isExperimentalAttributeDisabled (s:string) =
+ if g.compilingFslib then
+ true
+ else
+ g.langVersion.IsPreviewEnabled && (s.IndexOf(langVersionPrefix, StringComparison.OrdinalIgnoreCase) >= 0)
+
+ if isNil attribs then CompleteD
+ else
(match TryFindFSharpAttribute g g.attrib_SystemObsolete attribs with
| Some(Attrib(_, _, [ AttribStringArg s ], _, _, _, _)) ->
WarnD(ObsoleteWarning(s, m))
@@ -283,28 +272,34 @@ let CheckFSharpAttributes g attribs m =
| None ->
CompleteD
) ++ (fun () ->
-
+
match TryFindFSharpAttribute g g.attrib_CompilerMessageAttribute attribs with
- | Some(Attrib(_, _, [ AttribStringArg s ; AttribInt32Arg n ], namedArgs, _, _, _)) ->
+ | Some(Attrib(_, _, [ AttribStringArg s ; AttribInt32Arg n ], namedArgs, _, _, _)) ->
let msg = UserCompilerMessage(s, n, m)
let isError =
match namedArgs with
| ExtractAttribNamedArg "IsError" (AttribBoolArg v) -> v
| _ -> false
- if isError && (not g.compilingFslib || n <> 1204) then ErrorD msg else WarnD msg
-
+ // If we are using a compiler that supports nameof then error 3501 is always suppressed.
+ // See attribute on FSharp.Core 'nameof'
+ if n = 3501 then CompleteD
+ elif isError && (not g.compilingFslib || n <> 1204) then ErrorD msg
+ else WarnD msg
| _ ->
CompleteD
) ++ (fun () ->
-
+
match TryFindFSharpAttribute g g.attrib_ExperimentalAttribute attribs with
- | Some(Attrib(_, _, [ AttribStringArg(s) ], _, _, _, _)) ->
- WarnD(Experimental(s, m))
- | Some _ ->
+ | Some(Attrib(_, _, [ AttribStringArg(s) ], _, _, _, _)) ->
+ if isExperimentalAttributeDisabled s then
+ CompleteD
+ else
+ WarnD(Experimental(s, m))
+ | Some _ ->
WarnD(Experimental(FSComp.SR.experimentalConstruct (), m))
- | _ ->
+ | _ ->
CompleteD
- ) ++ (fun () ->
+ ) ++ (fun () ->
match TryFindFSharpAttribute g g.attrib_UnverifiableAttribute attribs with
| Some _ ->
@@ -419,7 +414,7 @@ let CheckMethInfoAttributes g m tyargsOpt minfo =
/// Indicate if a method has 'Obsolete', 'CompilerMessageAttribute' or 'TypeProviderEditorHideMethodsAttribute'.
/// Used to suppress the item in intellisense.
-let MethInfoIsUnseen g m ty minfo =
+let MethInfoIsUnseen g (m: range) (ty: TType) minfo =
let isUnseenByObsoleteAttrib () =
match BindMethInfoAttributes m minfo
(fun ilAttribs -> Some(CheckILAttributesForUnseen g ilAttribs m))
diff --git a/src/fsharp/AttributeChecking.fsi b/src/fsharp/AttributeChecking.fsi
new file mode 100644
index 00000000000..3f7acb14653
--- /dev/null
+++ b/src/fsharp/AttributeChecking.fsi
@@ -0,0 +1,80 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+/// Logic associated with checking "ObsoleteAttribute" and other attributes
+/// on items from name resolution
+module internal FSharp.Compiler.AttributeChecking
+
+open System.Collections.Generic
+open FSharp.Compiler.AbstractIL.IL
+open FSharp.Compiler
+open FSharp.Compiler.ErrorLogger
+open FSharp.Compiler.Infos
+open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.Text
+open FSharp.Compiler.TypedTree
+
+exception ObsoleteWarning of string * range
+exception ObsoleteError of string * range
+
+type AttribInfo =
+ | FSAttribInfo of TcGlobals * Attrib
+ | ILAttribInfo of TcGlobals * Import.ImportMap * ILScopeRef * ILAttribute * range
+ member ConstructorArguments: (TType * obj) list
+ member NamedArguments: (TType * string * bool * obj) list
+ member Range: range
+ member TyconRef: TyconRef
+
+val AttribInfosOfIL: g:TcGlobals -> amap:Import.ImportMap -> scoref:ILScopeRef -> m:range -> attribs:ILAttributes -> AttribInfo list
+
+val GetAttribInfosOfEntity: g:TcGlobals -> amap:Import.ImportMap -> m:range -> tcref:TyconRef -> AttribInfo list
+
+val GetAttribInfosOfMethod: amap:Import.ImportMap -> m:range -> minfo:MethInfo -> AttribInfo list
+
+val GetAttribInfosOfProp: amap:Import.ImportMap -> m:range -> pinfo:PropInfo -> AttribInfo list
+
+val GetAttribInfosOfEvent: amap:Import.ImportMap -> m:range -> einfo:EventInfo -> AttribInfo list
+
+#if NO_EXTENSIONTYPING
+val TryBindMethInfoAttribute: g:TcGlobals -> m:range -> BuiltinAttribInfo -> minfo:MethInfo -> f1:(ILAttribElem list * ILAttributeNamedArg list -> 'a option) -> f2:(Attrib -> 'a option) -> f3: _ -> 'a option
+#else
+val TryBindMethInfoAttribute: g:TcGlobals -> m:range -> BuiltinAttribInfo -> minfo:MethInfo -> f1:(ILAttribElem list * ILAttributeNamedArg list -> 'a option) -> f2:(Attrib -> 'a option) -> f3:(obj option list * (string * obj option) list -> 'a option) -> 'a option
+#endif
+
+val TryFindMethInfoStringAttribute: g:TcGlobals -> m:range -> attribSpec:BuiltinAttribInfo -> minfo:MethInfo -> string option
+
+val MethInfoHasAttribute: g:TcGlobals -> m:range -> attribSpec:BuiltinAttribInfo -> minfo:MethInfo -> bool
+
+val CheckFSharpAttributes: g:TcGlobals -> attribs:Attrib list -> m:range -> OperationResult
+
+val CheckILAttributesForUnseen: g:TcGlobals -> cattrs:ILAttributes -> _m:'a -> bool
+
+val CheckFSharpAttributesForHidden: g:TcGlobals -> attribs:Attrib list -> bool
+
+val CheckFSharpAttributesForObsolete: g:TcGlobals -> attribs:Attrib list -> bool
+
+val CheckFSharpAttributesForUnseen: g:TcGlobals -> attribs:Attrib list -> _m:'a -> bool
+
+val CheckPropInfoAttributes: pinfo:PropInfo -> m:range -> OperationResult
+
+val CheckILFieldAttributes: g:TcGlobals -> finfo:ILFieldInfo -> m:range -> unit
+
+val CheckMethInfoAttributes: g:TcGlobals -> m:range -> tyargsOpt:'a option -> minfo:MethInfo -> OperationResult
+
+val MethInfoIsUnseen: g:TcGlobals -> m:range -> ty:TType -> minfo:MethInfo -> bool
+
+val PropInfoIsUnseen: m:'a -> pinfo:PropInfo -> bool
+
+val CheckEntityAttributes: g:TcGlobals -> x:TyconRef -> m:range -> OperationResult
+
+val CheckUnionCaseAttributes: g:TcGlobals -> x:UnionCaseRef -> m:range -> OperationResult
+
+val CheckRecdFieldAttributes: g:TcGlobals -> x:RecdFieldRef -> m:range -> OperationResult
+
+val CheckValAttributes: g:TcGlobals -> x:ValRef -> m:range -> OperationResult
+
+val CheckRecdFieldInfoAttributes: g:TcGlobals -> x:RecdFieldInfo -> m:range -> OperationResult
+
+val IsSecurityAttribute: g:TcGlobals -> amap:Import.ImportMap -> casmap:Dictionary -> Attrib -> m:range -> bool
+
+val IsSecurityCriticalAttribute: g:TcGlobals -> Attrib -> bool
+
diff --git a/src/fsharp/AugmentWithHashCompare.fs b/src/fsharp/AugmentWithHashCompare.fs
index ce562dedaa4..0e00a302720 100644
--- a/src/fsharp/AugmentWithHashCompare.fs
+++ b/src/fsharp/AugmentWithHashCompare.fs
@@ -6,12 +6,14 @@ module internal FSharp.Compiler.AugmentWithHashCompare
open FSharp.Compiler.AbstractIL
open FSharp.Compiler.AbstractIL.IL
open FSharp.Compiler.AbstractIL.Internal.Library
-open FSharp.Compiler.Tast
-open FSharp.Compiler.Tastops
-open FSharp.Compiler.Ast
open FSharp.Compiler.ErrorLogger
-open FSharp.Compiler.TcGlobals
open FSharp.Compiler.Infos
+open FSharp.Compiler.SyntaxTree
+open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.TypedTree
+open FSharp.Compiler.TypedTreeBasics
+open FSharp.Compiler.TypedTreeOps
+open FSharp.Compiler.XmlDoc
let mkIComparableCompareToSlotSig (g: TcGlobals) =
TSlotSig("CompareTo", g.mk_IComparable_ty, [], [], [[TSlotParam(Some("obj"), g.obj_ty, false, false, false, [])]], Some g.int_ty)
@@ -156,10 +158,10 @@ let mkCompareTestConjuncts g m exprs =
(a, b) ||> List.foldBack (fun e acc ->
let nv, ne = mkCompGenLocal m "n" g.int_ty
mkCompGenLet m nv e
- (mkCond NoSequencePointAtStickyBinding SuppressSequencePointAtTarget m g.int_ty
+ (mkCond NoDebugPointAtStickyBinding DebugPointForTarget.No m g.int_ty
(mkClt g m ne (mkZero g m))
ne
- (mkCond NoSequencePointAtStickyBinding SuppressSequencePointAtTarget m g.int_ty
+ (mkCond NoDebugPointAtStickyBinding DebugPointForTarget.No m g.int_ty
(mkCgt g m ne (mkZero g m))
ne
acc)))
@@ -170,7 +172,7 @@ let mkEqualsTestConjuncts g m exprs =
| [h] -> h
| l ->
let a, b = List.frontAndBack l
- List.foldBack (fun e acc -> mkCond NoSequencePointAtStickyBinding SuppressSequencePointAtTarget m g.bool_ty e acc (mkFalse g m)) a b
+ List.foldBack (fun e acc -> mkCond NoDebugPointAtStickyBinding DebugPointForTarget.No m g.bool_ty e acc (mkFalse g m)) a b
let mkMinimalTy (g: TcGlobals) (tcref: TyconRef) =
if tcref.Deref.IsExceptionDecl then [], g.exn_ty
@@ -217,7 +219,6 @@ let mkRecdCompare g tcref (tycon: Tycon) =
let thatv, expr = mkThatVarBind g m ty thataddrv expr
thisv, thatv, expr
-
/// Build the comparison implementation for a record type when parameterized by a comparer
let mkRecdCompareWithComparer g tcref (tycon: Tycon) (_thisv, thise) (_, thate) compe =
let m = tycon.Range
@@ -243,7 +244,6 @@ let mkRecdCompareWithComparer g tcref (tycon: Tycon) (_thisv, thise) (_, thate)
let expr = mkCompGenLet m tcv thate expr
expr
-
/// Build the .Equals(that) equality implementation wrapper for a record type
let mkRecdEquality g tcref (tycon: Tycon) =
let m = tycon.Range
@@ -301,18 +301,17 @@ let mkExnEquality (g: TcGlobals) exnref (exnc: Tycon) =
(mkExnCaseFieldGet(thate, exnref, i, m))
let expr = mkEqualsTestConjuncts g m (List.mapi mkTest exnc.AllInstanceFieldsAsList)
let expr =
- let mbuilder = new MatchBuilder(NoSequencePointAtInvisibleBinding, m )
+ let mbuilder = new MatchBuilder(NoDebugPointAtInvisibleBinding, m )
let cases =
[ mkCase(DecisionTreeTest.IsInst(g.exn_ty, mkAppTy exnref []),
- mbuilder.AddResultTarget(expr, SuppressSequencePointAtTarget)) ]
- let dflt = Some(mbuilder.AddResultTarget(mkFalse g m, SuppressSequencePointAtTarget))
+ mbuilder.AddResultTarget(expr, DebugPointForTarget.No)) ]
+ let dflt = Some(mbuilder.AddResultTarget(mkFalse g m, DebugPointForTarget.No))
let dtree = TDSwitch(thate, cases, dflt, m)
mbuilder.Close(dtree, m, g.bool_ty)
let expr = mkBindThatNullEquals g m thise thate expr
thisv, thatv, expr
-
/// Build the equality implementation for an exception definition when parameterized by a comparer
let mkExnEqualityWithComparer g exnref (exnc: Tycon) (_thisv, thise) thatobje (thatv, thate) compe =
let m = exnc.Range
@@ -325,11 +324,11 @@ let mkExnEqualityWithComparer g exnref (exnc: Tycon) (_thisv, thise) thatobje (t
(mkExnCaseFieldGet(thataddre, exnref, i, m))
let expr = mkEqualsTestConjuncts g m (List.mapi mkTest exnc.AllInstanceFieldsAsList)
let expr =
- let mbuilder = new MatchBuilder(NoSequencePointAtInvisibleBinding, m )
+ let mbuilder = new MatchBuilder(NoDebugPointAtInvisibleBinding, m )
let cases =
[ mkCase(DecisionTreeTest.IsInst(g.exn_ty, mkAppTy exnref []),
- mbuilder.AddResultTarget(expr, SuppressSequencePointAtTarget)) ]
- let dflt = mbuilder.AddResultTarget(mkFalse g m, SuppressSequencePointAtTarget)
+ mbuilder.AddResultTarget(expr, DebugPointForTarget.No)) ]
+ let dflt = mbuilder.AddResultTarget(mkFalse g m, DebugPointForTarget.No)
let dtree = TDSwitch(thate, cases, Some dflt, m)
mbuilder.Close(dtree, m, g.bool_ty)
let expr = mkBindThatAddr g m g.exn_ty thataddrv thatv thate expr
@@ -348,7 +347,7 @@ let mkUnionCompare g tcref (tycon: Tycon) =
let compe = mkILCallGetComparer g m
let expr =
- let mbuilder = new MatchBuilder(NoSequencePointAtInvisibleBinding, m )
+ let mbuilder = new MatchBuilder(NoDebugPointAtInvisibleBinding, m )
let mkCase ucase =
let cref = tcref.MakeNestedUnionCaseRef ucase
let m = cref.Range
@@ -368,19 +367,19 @@ let mkUnionCompare g tcref (tycon: Tycon) =
mkCompGenLet m thisucv (mkUnionCaseProof (thise, cref, tinst, m))
(mkCompGenLet m thatucv (mkUnionCaseProof (thataddre, cref, tinst, m))
(mkCompareTestConjuncts g m (List.mapi (mkTest thisucve thatucve) rfields)))
- Some (mkCase(DecisionTreeTest.UnionCase(cref, tinst), mbuilder.AddResultTarget(test, SuppressSequencePointAtTarget)))
+ Some (mkCase(DecisionTreeTest.UnionCase(cref, tinst), mbuilder.AddResultTarget(test, DebugPointForTarget.No)))
let nullary, nonNullary = List.partition Option.isNone (List.map mkCase ucases)
if isNil nonNullary then mkZero g m else
let cases = nonNullary |> List.map (function (Some c) -> c | None -> failwith "mkUnionCompare")
- let dflt = if isNil nullary then None else Some (mbuilder.AddResultTarget(mkZero g m, SuppressSequencePointAtTarget))
+ let dflt = if isNil nullary then None else Some (mbuilder.AddResultTarget(mkZero g m, DebugPointForTarget.No))
let dtree = TDSwitch(thise, cases, dflt, m)
mbuilder.Close(dtree, m, g.int_ty)
let expr =
if ucases.Length = 1 then expr else
let tagsEqTested =
- mkCond NoSequencePointAtStickyBinding SuppressSequencePointAtTarget m g.int_ty
+ mkCond NoDebugPointAtStickyBinding DebugPointForTarget.No m g.int_ty
(mkILAsmCeq g m thistage thattage)
expr
(mkAsmExpr ([ IL.AI_sub ], [], [thistage; thattage], [g.int_ty], m))in
@@ -406,7 +405,7 @@ let mkUnionCompareWithComparer g tcref (tycon: Tycon) (_thisv, thise) (_thatobjv
let thattagv, thattage = mkCompGenLocal m "thatTag" g.int_ty
let expr =
- let mbuilder = new MatchBuilder(NoSequencePointAtInvisibleBinding, m )
+ let mbuilder = new MatchBuilder(NoDebugPointAtInvisibleBinding, m )
let mkCase ucase =
let cref = tcref.MakeNestedUnionCaseRef ucase
let m = cref.Range
@@ -429,19 +428,19 @@ let mkUnionCompareWithComparer g tcref (tycon: Tycon) (_thisv, thise) (_thatobjv
(mkCompGenLet m thatucv (mkUnionCaseProof (thataddre, cref, tinst, m))
(mkCompareTestConjuncts g m (List.mapi (mkTest thisucve thatucve) rfields)))
- Some (mkCase(DecisionTreeTest.UnionCase(cref, tinst), mbuilder.AddResultTarget(test, SuppressSequencePointAtTarget)))
+ Some (mkCase(DecisionTreeTest.UnionCase(cref, tinst), mbuilder.AddResultTarget(test, DebugPointForTarget.No)))
let nullary, nonNullary = List.partition Option.isNone (List.map mkCase ucases)
if isNil nonNullary then mkZero g m else
let cases = nonNullary |> List.map (function (Some c) -> c | None -> failwith "mkUnionCompare")
- let dflt = if isNil nullary then None else Some (mbuilder.AddResultTarget(mkZero g m, SuppressSequencePointAtTarget))
+ let dflt = if isNil nullary then None else Some (mbuilder.AddResultTarget(mkZero g m, DebugPointForTarget.No))
let dtree = TDSwitch(thise, cases, dflt, m)
mbuilder.Close(dtree, m, g.int_ty)
let expr =
if ucases.Length = 1 then expr else
let tagsEqTested =
- mkCond NoSequencePointAtStickyBinding SuppressSequencePointAtTarget m g.int_ty
+ mkCond NoDebugPointAtStickyBinding DebugPointForTarget.No m g.int_ty
(mkILAsmCeq g m thistage thattage)
expr
(mkAsmExpr ([ IL.AI_sub ], [], [thistage; thattage], [g.int_ty], m))
@@ -467,7 +466,7 @@ let mkUnionEquality g tcref (tycon: Tycon) =
let thattagv, thattage = mkCompGenLocal m "thatTag" g.int_ty
let expr =
- let mbuilder = new MatchBuilder(NoSequencePointAtInvisibleBinding, m )
+ let mbuilder = new MatchBuilder(NoDebugPointAtInvisibleBinding, m )
let mkCase ucase =
let cref = tcref.MakeNestedUnionCaseRef ucase
let m = cref.Range
@@ -489,19 +488,19 @@ let mkUnionEquality g tcref (tycon: Tycon) =
(mkCompGenLet m thatucv (mkUnionCaseProof (thataddre, cref, tinst, m))
(mkEqualsTestConjuncts g m (List.mapi (mkTest thisucve thatucve) rfields)))
- Some (mkCase(DecisionTreeTest.UnionCase(cref, tinst), mbuilder.AddResultTarget(test, SuppressSequencePointAtTarget)))
+ Some (mkCase(DecisionTreeTest.UnionCase(cref, tinst), mbuilder.AddResultTarget(test, DebugPointForTarget.No)))
let nullary, nonNullary = List.partition Option.isNone (List.map mkCase ucases)
if isNil nonNullary then mkTrue g m else
let cases = List.map (function (Some c) -> c | None -> failwith "mkUnionEquality") nonNullary
- let dflt = (if isNil nullary then None else Some (mbuilder.AddResultTarget(mkTrue g m, SuppressSequencePointAtTarget)))
+ let dflt = (if isNil nullary then None else Some (mbuilder.AddResultTarget(mkTrue g m, DebugPointForTarget.No)))
let dtree = TDSwitch(thise, cases, dflt, m)
mbuilder.Close(dtree, m, g.bool_ty)
let expr =
if ucases.Length = 1 then expr else
let tagsEqTested =
- mkCond NoSequencePointAtStickyBinding SuppressSequencePointAtTarget m g.bool_ty
+ mkCond NoDebugPointAtStickyBinding DebugPointForTarget.No m g.bool_ty
(mkILAsmCeq g m thistage thattage)
expr
(mkFalse g m)
@@ -526,7 +525,7 @@ let mkUnionEqualityWithComparer g tcref (tycon: Tycon) (_thisv, thise) thatobje
let thataddrv, thataddre = mkThatAddrLocal g m ty
let expr =
- let mbuilder = new MatchBuilder(NoSequencePointAtInvisibleBinding, m )
+ let mbuilder = new MatchBuilder(NoDebugPointAtInvisibleBinding, m )
let mkCase ucase =
let cref = tcref.MakeNestedUnionCaseRef ucase
let m = cref.Range
@@ -551,19 +550,19 @@ let mkUnionEqualityWithComparer g tcref (tycon: Tycon) (_thisv, thise) thatobje
(mkCompGenLet m thatucv (mkUnionCaseProof (thataddre, cref, tinst, m))
(mkEqualsTestConjuncts g m (List.mapi (mkTest thisucve thatucve) rfields)))
- Some (mkCase(DecisionTreeTest.UnionCase(cref, tinst), mbuilder.AddResultTarget (test, SuppressSequencePointAtTarget)))
+ Some (mkCase(DecisionTreeTest.UnionCase(cref, tinst), mbuilder.AddResultTarget (test, DebugPointForTarget.No)))
let nullary, nonNullary = List.partition Option.isNone (List.map mkCase ucases)
if isNil nonNullary then mkTrue g m else
let cases = List.map (function (Some c) -> c | None -> failwith "mkUnionEquality") nonNullary
- let dflt = if isNil nullary then None else Some (mbuilder.AddResultTarget(mkTrue g m, SuppressSequencePointAtTarget))
+ let dflt = if isNil nullary then None else Some (mbuilder.AddResultTarget(mkTrue g m, DebugPointForTarget.No))
let dtree = TDSwitch(thise, cases, dflt, m)
mbuilder.Close(dtree, m, g.bool_ty)
let expr =
if ucases.Length = 1 then expr else
let tagsEqTested =
- mkCond NoSequencePointAtStickyBinding SuppressSequencePointAtTarget m g.bool_ty
+ mkCond NoDebugPointAtStickyBinding DebugPointForTarget.No m g.bool_ty
(mkILAsmCeq g m thistage thattage)
expr
(mkFalse g m)
@@ -626,7 +625,7 @@ let mkUnionHashWithComparer g tcref (tycon: Tycon) compe =
let ucases = tycon.UnionCasesAsList
let tinst, ty = mkMinimalTy g tcref
let thisv, thise = mkThisVar g m ty
- let mbuilder = new MatchBuilder(NoSequencePointAtInvisibleBinding, m )
+ let mbuilder = new MatchBuilder(NoDebugPointAtInvisibleBinding, m )
let accv, acce = mkMutableCompGenLocal m "i" g.int_ty
let mkCase i ucase1 =
let c1ref = tcref.MakeNestedUnionCaseRef ucase1
@@ -650,7 +649,7 @@ let mkUnionHashWithComparer g tcref (tycon: Tycon) compe =
(mkCompGenSequential m
(mkValSet m (mkLocalValRef accv) (mkInt g m i))
(mkCombineHashGenerators g m (List.mapi (mkHash ucve) ucase1.RecdFields) (mkLocalValRef accv) acce))
- Some(mkCase(DecisionTreeTest.UnionCase(c1ref, tinst), mbuilder.AddResultTarget(test, SuppressSequencePointAtTarget)))
+ Some(mkCase(DecisionTreeTest.UnionCase(c1ref, tinst), mbuilder.AddResultTarget(test, DebugPointForTarget.No)))
let nullary, nonNullary = ucases
|> List.mapi mkCase
@@ -659,7 +658,7 @@ let mkUnionHashWithComparer g tcref (tycon: Tycon) compe =
let dflt = if isNil nullary then None
else
let tag = mkUnionCaseTagGetViaExprAddr (thise, tcref, tinst, m)
- Some(mbuilder.AddResultTarget(tag, SuppressSequencePointAtTarget))
+ Some(mbuilder.AddResultTarget(tag, DebugPointForTarget.No))
let dtree = TDSwitch(thise, cases, dflt, m)
let stmt = mbuilder.Close(dtree, m, g.int_ty)
let expr = mkCompGenLet m accv (mkZero g m) stmt
@@ -744,10 +743,9 @@ let CheckAugmentationAttribs isImplementation g amap (tycon: Tycon) =
// [] on anything
| _, _, Some true, None, None, None, Some true, None, None ->
-
()
- (* THESE ARE THE ERROR CASES *)
+ // THESE ARE THE ERROR CASES
// []
| _, _, Some true, _, _, _, None, _, _ ->
@@ -883,15 +881,19 @@ let nonVirtualMethod c : ValMemberInfo =
let unitArg = ValReprInfo.unitArgData
let unaryArg = [ ValReprInfo.unnamedTopArg ]
let tupArg = [ [ ValReprInfo.unnamedTopArg1; ValReprInfo.unnamedTopArg1 ] ]
-let mkValSpec g (tcref: TyconRef) tmty vis slotsig methn ty argData =
+let mkValSpec g (tcref: TyconRef) tmty vis slotsig methn ty argData =
let m = tcref.Range
let tps = tcref.Typars m
- let final = isUnionTy g tmty || isRecdTy g tmty || isStructTy g tmty
- let membInfo = match slotsig with None -> nonVirtualMethod tcref | Some slotsig -> slotImplMethod(final, tcref, slotsig)
+ let membInfo =
+ match slotsig with
+ | None -> nonVirtualMethod tcref
+ | Some slotsig ->
+ let final = isUnionTy g tmty || isRecdTy g tmty || isStructTy g tmty
+ slotImplMethod(final, tcref, slotsig)
let inl = ValInline.Optional
let args = ValReprInfo.unnamedTopArg :: argData
let topValInfo = Some (ValReprInfo (ValReprInfo.InferTyparInfo tps, args, ValReprInfo.unnamedRetVal))
- NewVal (methn, m, None, ty, Immutable, true, topValInfo, vis, ValNotInRecScope, Some membInfo, NormalVal, [], inl, XmlDoc.Empty, true, false, false, false, false, false, None, Parent tcref)
+ Construct.NewVal (methn, m, None, ty, Immutable, true, topValInfo, vis, ValNotInRecScope, Some membInfo, NormalVal, [], inl, XmlDoc.Empty, true, false, false, false, false, false, None, Parent tcref)
let MakeValsForCompareAugmentation g (tcref: TyconRef) =
let m = tcref.Range
@@ -899,8 +901,8 @@ let MakeValsForCompareAugmentation g (tcref: TyconRef) =
let tps = tcref.Typars m
let vis = tcref.TypeReprAccessibility
- mkValSpec g tcref tmty vis (Some(mkIComparableCompareToSlotSig g)) "CompareTo" (tps +-> (mkCompareObjTy g tmty)) unaryArg,
- mkValSpec g tcref tmty vis (Some(mkGenericIComparableCompareToSlotSig g tmty)) "CompareTo" (tps +-> (mkCompareTy g tmty)) unaryArg
+ mkValSpec g tcref tmty vis (Some(mkIComparableCompareToSlotSig g)) "CompareTo" (tps +-> (mkCompareObjTy g tmty)) unaryArg,
+ mkValSpec g tcref tmty vis (Some(mkGenericIComparableCompareToSlotSig g tmty)) "CompareTo" (tps +-> (mkCompareTy g tmty)) unaryArg
let MakeValsForCompareWithComparerAugmentation g (tcref: TyconRef) =
let m = tcref.Range
@@ -915,15 +917,15 @@ let MakeValsForEqualsAugmentation g (tcref: TyconRef) =
let vis = tcref.TypeReprAccessibility
let tps = tcref.Typars m
- let objEqualsVal = mkValSpec g tcref tmty vis (Some(mkEqualsSlotSig g)) "Equals" (tps +-> (mkEqualsObjTy g tmty)) unaryArg
- let nocEqualsVal = mkValSpec g tcref tmty vis (if tcref.Deref.IsExceptionDecl then None else Some(mkGenericIEquatableEqualsSlotSig g tmty)) "Equals" (tps +-> (mkEqualsTy g tmty)) unaryArg
+ let objEqualsVal = mkValSpec g tcref tmty vis (Some(mkEqualsSlotSig g)) "Equals" (tps +-> (mkEqualsObjTy g tmty)) unaryArg
+ let nocEqualsVal = mkValSpec g tcref tmty vis (if tcref.Deref.IsExceptionDecl then None else Some(mkGenericIEquatableEqualsSlotSig g tmty)) "Equals" (tps +-> (mkEqualsTy g tmty)) unaryArg
objEqualsVal, nocEqualsVal
let MakeValsForEqualityWithComparerAugmentation g (tcref: TyconRef) =
let _, tmty = mkMinimalTy g tcref
let vis = tcref.TypeReprAccessibility
let tps = tcref.Typars tcref.Range
- let objGetHashCodeVal = mkValSpec g tcref tmty vis (Some(mkGetHashCodeSlotSig g)) "GetHashCode" (tps +-> (mkHashTy g tmty)) unitArg
+ let objGetHashCodeVal = mkValSpec g tcref tmty vis (Some(mkGetHashCodeSlotSig g)) "GetHashCode" (tps +-> (mkHashTy g tmty)) unitArg
let withcGetHashCodeVal = mkValSpec g tcref tmty vis (Some(mkIStructuralEquatableGetHashCodeSlotSig g)) "GetHashCode" (tps +-> (mkHashWithComparerTy g tmty)) unaryArg
let withcEqualsVal = mkValSpec g tcref tmty vis (Some(mkIStructuralEquatableEqualsSlotSig g)) "Equals" (tps +-> (mkEqualsWithComparerTy g tmty)) tupArg
objGetHashCodeVal, withcGetHashCodeVal, withcEqualsVal
@@ -1071,23 +1073,28 @@ let MakeBindingsForEqualsAugmentation (g: TcGlobals) (tycon: Tycon) =
elif tycon.IsRecordTycon || tycon.IsStructOrEnumTycon then mkEquals mkRecdEquality
else []
-let rec TypeDefinitelyHasEquality g ty =
- if isAppTy g ty && HasFSharpAttribute g g.attrib_NoEqualityAttribute (tcrefOfAppTy g ty).Attribs then
+let rec TypeDefinitelyHasEquality g ty =
+ let appTy = tryAppTy g ty
+ match appTy with
+ | ValueSome(tcref,_) when HasFSharpAttribute g g.attrib_NoEqualityAttribute tcref.Attribs ->
false
- elif isTyparTy g ty &&
- (destTyparTy g ty).Constraints |> List.exists (function TyparConstraint.SupportsEquality _ -> true | _ -> false) then
- true
- else
- match ty with
- | SpecialEquatableHeadType g tinst ->
- tinst |> List.forall (TypeDefinitelyHasEquality g)
- | SpecialNotEquatableHeadType g _ ->
- false
- | _ ->
- // The type is equatable because it has Object.Equals(...)
- isAppTy g ty &&
- let tcref, tinst = destAppTy g ty
- // Give a good error for structural types excluded from the equality relation because of their fields
- not (TyconIsCandidateForAugmentationWithEquals g tcref.Deref && Option.isNone tcref.GeneratedHashAndEqualsWithComparerValues) &&
- // Check the (possibly inferred) structural dependencies
- (tinst, tcref.TyparsNoRange) ||> List.lengthsEqAndForall2 (fun ty tp -> not tp.EqualityConditionalOn || TypeDefinitelyHasEquality g ty)
+ | _ ->
+ if isTyparTy g ty &&
+ (destTyparTy g ty).Constraints |> List.exists (function TyparConstraint.SupportsEquality _ -> true | _ -> false) then
+ true
+ else
+ match ty with
+ | SpecialEquatableHeadType g tinst ->
+ tinst |> List.forall (TypeDefinitelyHasEquality g)
+ | SpecialNotEquatableHeadType g _ ->
+ false
+ | _ ->
+ // The type is equatable because it has Object.Equals(...)
+ match appTy with
+ | ValueSome(tcref,tinst) ->
+ // Give a good error for structural types excluded from the equality relation because of their fields
+ not (TyconIsCandidateForAugmentationWithEquals g tcref.Deref && Option.isNone tcref.GeneratedHashAndEqualsWithComparerValues) &&
+ // Check the (possibly inferred) structural dependencies
+ (tinst, tcref.TyparsNoRange)
+ ||> List.lengthsEqAndForall2 (fun ty tp -> not tp.EqualityConditionalOn || TypeDefinitelyHasEquality g ty)
+ | _ -> false
diff --git a/src/fsharp/AugmentWithHashCompare.fsi b/src/fsharp/AugmentWithHashCompare.fsi
index 13d3f18f0e9..4e3acc47ab7 100644
--- a/src/fsharp/AugmentWithHashCompare.fsi
+++ b/src/fsharp/AugmentWithHashCompare.fsi
@@ -4,25 +4,34 @@
module internal FSharp.Compiler.AugmentWithHashCompare
open FSharp.Compiler
-open FSharp.Compiler.Tast
+open FSharp.Compiler.TypedTree
open FSharp.Compiler.TcGlobals
-val CheckAugmentationAttribs : bool -> TcGlobals -> Import.ImportMap -> Tycon -> unit
-val TyconIsCandidateForAugmentationWithCompare : TcGlobals -> Tycon -> bool
-val TyconIsCandidateForAugmentationWithEquals : TcGlobals -> Tycon -> bool
-val TyconIsCandidateForAugmentationWithHash : TcGlobals -> Tycon -> bool
+val CheckAugmentationAttribs: bool -> TcGlobals -> Import.ImportMap -> Tycon -> unit
-val MakeValsForCompareAugmentation : TcGlobals -> TyconRef -> Val * Val
-val MakeValsForCompareWithComparerAugmentation : TcGlobals -> TyconRef -> Val
-val MakeValsForEqualsAugmentation : TcGlobals -> TyconRef -> Val * Val
-val MakeValsForEqualityWithComparerAugmentation : TcGlobals -> TyconRef -> Val * Val * Val
+val TyconIsCandidateForAugmentationWithCompare: TcGlobals -> Tycon -> bool
-val MakeBindingsForCompareAugmentation : TcGlobals -> Tycon -> Binding list
-val MakeBindingsForCompareWithComparerAugmentation : TcGlobals -> Tycon -> Binding list
-val MakeBindingsForEqualsAugmentation : TcGlobals -> Tycon -> Binding list
-val MakeBindingsForEqualityWithComparerAugmentation : TcGlobals -> Tycon -> Binding list
+val TyconIsCandidateForAugmentationWithEquals: TcGlobals -> Tycon -> bool
+
+val TyconIsCandidateForAugmentationWithHash: TcGlobals -> Tycon -> bool
+
+val MakeValsForCompareAugmentation: TcGlobals -> TyconRef -> Val * Val
+
+val MakeValsForCompareWithComparerAugmentation: TcGlobals -> TyconRef -> Val
+
+val MakeValsForEqualsAugmentation: TcGlobals -> TyconRef -> Val * Val
+
+val MakeValsForEqualityWithComparerAugmentation: TcGlobals -> TyconRef -> Val * Val * Val
+
+val MakeBindingsForCompareAugmentation: TcGlobals -> Tycon -> Binding list
+
+val MakeBindingsForCompareWithComparerAugmentation: TcGlobals -> Tycon -> Binding list
+
+val MakeBindingsForEqualsAugmentation: TcGlobals -> Tycon -> Binding list
+
+val MakeBindingsForEqualityWithComparerAugmentation: TcGlobals -> Tycon -> Binding list
/// This predicate can be used once type inference is complete, before then it is an approximation
/// that doesn't assert any new constraints
-val TypeDefinitelyHasEquality : TcGlobals -> TType -> bool
+val TypeDefinitelyHasEquality: TcGlobals -> TType -> bool
diff --git a/src/fsharp/BinaryResourceFormats.fs b/src/fsharp/BinaryResourceFormats.fs
new file mode 100644
index 00000000000..82c134eeb11
--- /dev/null
+++ b/src/fsharp/BinaryResourceFormats.fs
@@ -0,0 +1,232 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+module internal FSharp.Compiler.BinaryResourceFormats
+
+open FSharp.Compiler.AbstractIL.IL
+open FSharp.Compiler.AbstractIL.Internal
+
+// Helpers for generating binary blobs
+module BinaryGenerationUtilities =
+ // Little-endian encoding of int32
+ let b0 n = byte (n &&& 0xFF)
+ let b1 n = byte ((n >>> 8) &&& 0xFF)
+ let b2 n = byte ((n >>> 16) &&& 0xFF)
+ let b3 n = byte ((n >>> 24) &&& 0xFF)
+
+ let i16 (i: int32) = [| b0 i; b1 i |]
+ let i32 (i: int32) = [| b0 i; b1 i; b2 i; b3 i |]
+
+ // Emit the bytes and pad to a 32-bit alignment
+ let Padded initialAlignment (v: byte[]) =
+ [| yield! v
+ for _ in 1..(4 - (initialAlignment + v.Length) % 4) % 4 do
+ yield 0x0uy |]
+
+// Generate nodes in a .res file format. These are then linked by Abstract IL using linkNativeResources
+module ResFileFormat =
+ open BinaryGenerationUtilities
+
+ let ResFileNode(dwTypeID, dwNameID, wMemFlags, wLangID, data: byte[]) =
+ [| yield! i32 data.Length // DWORD ResHdr.dwDataSize
+ yield! i32 0x00000020 // dwHeaderSize
+ yield! i32 ((dwTypeID <<< 16) ||| 0x0000FFFF) // dwTypeID, sizeof(DWORD)
+ yield! i32 ((dwNameID <<< 16) ||| 0x0000FFFF) // dwNameID, sizeof(DWORD)
+ yield! i32 0x00000000 // DWORD dwDataVersion
+ yield! i16 wMemFlags // WORD wMemFlags
+ yield! i16 wLangID // WORD wLangID
+ yield! i32 0x00000000 // DWORD dwVersion
+ yield! i32 0x00000000 // DWORD dwCharacteristics
+ yield! Padded 0 data |]
+
+ let ResFileHeader() = ResFileNode(0x0, 0x0, 0x0, 0x0, [| |])
+
+// Generate the VS_VERSION_INFO structure held in a Win32 Version Resource in a PE file
+//
+// Web reference: http://www.piclist.com/tecHREF/os/win/api/win32/struc/src/str24_5.htm
+module VersionResourceFormat =
+ open BinaryGenerationUtilities
+
+ let VersionInfoNode(data: byte[]) =
+ [| yield! i16 (data.Length + 2) // wLength : int16 // Specifies the length, in bytes, of the VS_VERSION_INFO structure.
+ yield! data |]
+
+ let VersionInfoElement(wType, szKey, valueOpt: byte[] option, children: byte[][], isString) =
+ // for String structs, wValueLength represents the word count, not the byte count
+ let wValueLength = (match valueOpt with None -> 0 | Some value -> (if isString then value.Length / 2 else value.Length))
+ VersionInfoNode
+ [| yield! i16 wValueLength // wValueLength: int16. Specifies the length, in words, of the Value member.
+ yield! i16 wType // wType : int16 Specifies the type of data in the version resource.
+ yield! Padded 2 szKey
+ match valueOpt with
+ | None -> yield! []
+ | Some value -> yield! Padded 0 value
+ for child in children do
+ yield! child |]
+
+ let Version(version: ILVersionInfo) =
+ [| // DWORD dwFileVersionMS
+ // Specifies the most significant 32 bits of the file's binary
+ // version number. This member is used with dwFileVersionLS to form a 64-bit value used
+ // for numeric comparisons.
+ yield! i32 (int32 version.Major <<< 16 ||| int32 version.Minor)
+
+ // DWORD dwFileVersionLS
+ // Specifies the least significant 32 bits of the file's binary
+ // version number. This member is used with dwFileVersionMS to form a 64-bit value used
+ // for numeric comparisons.
+ yield! i32 (int32 version.Build <<< 16 ||| int32 version.Revision)
+ |]
+
+ let String(string, value) =
+ let wType = 0x1 // Specifies the type of data in the version resource.
+ let szKey = Bytes.stringAsUnicodeNullTerminated string
+ VersionInfoElement(wType, szKey, Some (Bytes.stringAsUnicodeNullTerminated value), [| |], true)
+
+ let StringTable(language, strings) =
+ let wType = 0x1 // Specifies the type of data in the version resource.
+ let szKey = Bytes.stringAsUnicodeNullTerminated language
+ // Specifies an 8-digit hexadecimal number stored as a Unicode string.
+
+ let children =
+ [| for string in strings do
+ yield String string |]
+ VersionInfoElement(wType, szKey, None, children, false)
+
+ let StringFileInfo(stringTables: #seq >) =
+ let wType = 0x1 // Specifies the type of data in the version resource.
+ let szKey = Bytes.stringAsUnicodeNullTerminated "StringFileInfo" // Contains the Unicode string StringFileInfo
+ // Contains an array of one or more StringTable structures.
+ let children =
+ [| for stringTable in stringTables do
+ yield StringTable stringTable |]
+ VersionInfoElement(wType, szKey, None, children, false)
+
+ let VarFileInfo(vars: #seq) =
+ let wType = 0x1 // Specifies the type of data in the version resource.
+ let szKey = Bytes.stringAsUnicodeNullTerminated "VarFileInfo" // Contains the Unicode string StringFileInfo
+ // Contains an array of one or more StringTable structures.
+ let children =
+ [| for (lang, codePage) in vars do
+ let szKey = Bytes.stringAsUnicodeNullTerminated "Translation"
+ yield VersionInfoElement(0x0, szKey, Some([| yield! i16 lang
+ yield! i16 codePage |]), [| |], false) |]
+ VersionInfoElement(wType, szKey, None, children, false)
+
+ let VS_FIXEDFILEINFO(fileVersion: ILVersionInfo,
+ productVersion: ILVersionInfo,
+ dwFileFlagsMask,
+ dwFileFlags, dwFileOS,
+ dwFileType, dwFileSubtype,
+ lwFileDate: int64) =
+ let dwStrucVersion = 0x00010000
+ [| // DWORD dwSignature // Contains the value 0xFEEFO4BD.
+ yield! i32 0xFEEF04BD
+
+ // DWORD dwStrucVersion // Specifies the binary version number of this structure.
+ yield! i32 dwStrucVersion
+
+ // DWORD dwFileVersionMS, dwFileVersionLS // Specifies the most/least significant 32 bits of the file's binary version number.
+ yield! Version fileVersion
+
+ // DWORD dwProductVersionMS, dwProductVersionLS // Specifies the most/least significant 32 bits of the file's binary version number.
+ yield! Version productVersion
+
+ // DWORD dwFileFlagsMask // Contains a bitmask that specifies the valid bits in dwFileFlags.
+ yield! i32 dwFileFlagsMask
+
+ // DWORD dwFileFlags // Contains a bitmask that specifies the Boolean attributes of the file.
+ yield! i32 dwFileFlags
+ // VS_FF_DEBUG 0x1L The file contains debugging information or is compiled with debugging features enabled.
+ // VS_FF_INFOINFERRED The file's version structure was created dynamically; therefore, some of the members
+ // in this structure may be empty or incorrect. This flag should never be set in a file's
+ // VS_VERSION_INFO data.
+ // VS_FF_PATCHED The file has been modified and is not identical to the original shipping file of
+ // the same version number.
+ // VS_FF_PRERELEASE The file is a development version, not a commercially released product.
+ // VS_FF_PRIVATEBUILD The file was not built using standard release procedures. If this flag is
+ // set, the StringFileInfo structure should contain a PrivateBuild entry.
+ // VS_FF_SPECIALBUILD The file was built by the original company using standard release procedures
+ // but is a variation of the normal file of the same version number. If this
+ // flag is set, the StringFileInfo structure should contain a SpecialBuild entry.
+
+ //Specifies the operating system for which this file was designed. This member can be one of the following values: Flag
+ yield! i32 dwFileOS
+ //VOS_DOS 0x0001L The file was designed for MS-DOS.
+ //VOS_NT 0x0004L The file was designed for Windows NT.
+ //VOS__WINDOWS16 The file was designed for 16-bit Windows.
+ //VOS__WINDOWS32 The file was designed for the Win32 API.
+ //VOS_OS216 0x00020000L The file was designed for 16-bit OS/2.
+ //VOS_OS232 0x00030000L The file was designed for 32-bit OS/2.
+ //VOS__PM16 The file was designed for 16-bit Presentation Manager.
+ //VOS__PM32 The file was designed for 32-bit Presentation Manager.
+ //VOS_UNKNOWN The operating system for which the file was designed is unknown to Windows.
+
+ // Specifies the general type of file. This member can be one of the following values:
+ yield! i32 dwFileType
+
+ //VFT_UNKNOWN The file type is unknown to Windows.
+ //VFT_APP The file contains an application.
+ //VFT_DLL The file contains a dynamic-link library (DLL).
+ //VFT_DRV The file contains a device driver. If dwFileType is VFT_DRV, dwFileSubtype contains a more specific description of the driver.
+ //VFT_FONT The file contains a font. If dwFileType is VFT_FONT, dwFileSubtype contains a more specific description of the font file.
+ //VFT_VXD The file contains a virtual device.
+ //VFT_STATIC_LIB The file contains a static-link library.
+
+ // Specifies the function of the file. The possible values depend on the value of
+ // dwFileType. For all values of dwFileType not described in the following list,
+ // dwFileSubtype is zero. If dwFileType is VFT_DRV, dwFileSubtype can be one of the following values:
+ yield! i32 dwFileSubtype
+ //VFT2_UNKNOWN The driver type is unknown by Windows.
+ //VFT2_DRV_COMM The file contains a communications driver.
+ //VFT2_DRV_PRINTER The file contains a printer driver.
+ //VFT2_DRV_KEYBOARD The file contains a keyboard driver.
+ //VFT2_DRV_LANGUAGE The file contains a language driver.
+ //VFT2_DRV_DISPLAY The file contains a display driver.
+ //VFT2_DRV_MOUSE The file contains a mouse driver.
+ //VFT2_DRV_NETWORK The file contains a network driver.
+ //VFT2_DRV_SYSTEM The file contains a system driver.
+ //VFT2_DRV_INSTALLABLE The file contains an installable driver.
+ //VFT2_DRV_SOUND The file contains a sound driver.
+ //
+ //If dwFileType is VFT_FONT, dwFileSubtype can be one of the following values:
+ //
+ //VFT2_UNKNOWN The font type is unknown by Windows.
+ //VFT2_FONT_RASTER The file contains a raster font.
+ //VFT2_FONT_VECTOR The file contains a vector font.
+ //VFT2_FONT_TRUETYPE The file contains a TrueType font.
+ //
+ //If dwFileType is VFT_VXD, dwFileSubtype contains the virtual device identifier included in the virtual device control block.
+
+ // Specifies the most significant 32 bits of the file's 64-bit binary creation date and time stamp.
+ yield! i32 (int32 (lwFileDate >>> 32))
+
+ //Specifies the least significant 32 bits of the file's 64-bit binary creation date and time stamp.
+ yield! i32 (int32 lwFileDate)
+ |]
+
+ let VS_VERSION_INFO(fixedFileInfo, stringFileInfo, varFileInfo) =
+ let wType = 0x0
+ let szKey = Bytes.stringAsUnicodeNullTerminated "VS_VERSION_INFO" // Contains the Unicode string VS_VERSION_INFO
+ let value = VS_FIXEDFILEINFO (fixedFileInfo)
+ let children =
+ [| yield StringFileInfo stringFileInfo
+ yield VarFileInfo varFileInfo
+ |]
+ VersionInfoElement(wType, szKey, Some value, children, false)
+
+ let VS_VERSION_INFO_RESOURCE data =
+ let dwTypeID = 0x0010
+ let dwNameID = 0x0001
+ let wMemFlags = 0x0030 // REVIEW: HARDWIRED TO ENGLISH
+ let wLangID = 0x0
+ ResFileFormat.ResFileNode(dwTypeID, dwNameID, wMemFlags, wLangID, VS_VERSION_INFO data)
+
+module ManifestResourceFormat =
+
+ let VS_MANIFEST_RESOURCE(data, isLibrary) =
+ let dwTypeID = 0x0018
+ let dwNameID = if isLibrary then 0x2 else 0x1
+ let wMemFlags = 0x0
+ let wLangID = 0x0
+ ResFileFormat.ResFileNode(dwTypeID, dwNameID, wMemFlags, wLangID, data)
+
diff --git a/src/fsharp/BinaryResourceFormats.fsi b/src/fsharp/BinaryResourceFormats.fsi
new file mode 100644
index 00000000000..2efe5ff8221
--- /dev/null
+++ b/src/fsharp/BinaryResourceFormats.fsi
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+module internal FSharp.Compiler.BinaryResourceFormats
+
+open FSharp.Compiler.AbstractIL.IL
+
+module VersionResourceFormat =
+
+ val VS_VERSION_INFO_RESOURCE:
+ (ILVersionInfo * ILVersionInfo * int32 * int32 * int32 * int32 * int32 * int64) *
+ seq> *
+ seq
+ -> byte[]
+
+module ManifestResourceFormat =
+
+ val VS_MANIFEST_RESOURCE : data: byte[] * isLibrary: bool -> byte[]
+
+module ResFileFormat =
+
+ val ResFileHeader: unit -> byte[]
diff --git a/src/fsharp/CheckComputationExpressions.fs b/src/fsharp/CheckComputationExpressions.fs
new file mode 100644
index 00000000000..a8bd308b7ed
--- /dev/null
+++ b/src/fsharp/CheckComputationExpressions.fs
@@ -0,0 +1,1959 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+/// The typechecker. Left-to-right constrained type checking
+/// with generalization at appropriate points.
+module internal FSharp.Compiler.CheckComputationExpressions
+
+open FSharp.Compiler
+open FSharp.Compiler.AbstractIL.Internal.Library
+open FSharp.Compiler.AccessibilityLogic
+open FSharp.Compiler.AttributeChecking
+open FSharp.Compiler.CheckExpressions
+open FSharp.Compiler.ConstraintSolver
+open FSharp.Compiler.ErrorLogger
+open FSharp.Compiler.Features
+open FSharp.Compiler.Infos
+open FSharp.Compiler.InfoReader
+open FSharp.Compiler.NameResolution
+open FSharp.Compiler.PatternMatchCompilation
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.SourceCodeServices.PrettyNaming
+open FSharp.Compiler.SyntaxTree
+open FSharp.Compiler.SyntaxTreeOps
+open FSharp.Compiler.Text
+open FSharp.Compiler.Text.Range
+open FSharp.Compiler.TypedTree
+open FSharp.Compiler.TypedTreeOps
+
+type cenv = TcFileState
+
+/// Used to flag if this is the first or a sebsequent translation pass through a computation expression
+type CompExprTranslationPass = Initial | Subsequent
+
+/// Used to flag if computation expression custom operations are allowed in a given context
+type CustomOperationsMode = Allowed | Denied
+
+let TryFindIntrinsicOrExtensionMethInfo collectionSettings (cenv: cenv) (env: TcEnv) m ad nm ty =
+ AllMethInfosOfTypeInScope collectionSettings cenv.infoReader env.NameEnv (Some nm) ad IgnoreOverrides m ty
+
+/// Ignores an attribute
+let IgnoreAttribute _ = None
+
+let (|ExprAsPat|_|) (f: SynExpr) =
+ match f with
+ | SingleIdent v1 | SynExprParen(SingleIdent v1, _, _, _) -> Some (mkSynPatVar None v1)
+ | SynExprParen(SynExpr.Tuple (false, elems, _, _), _, _, _) ->
+ let elems = elems |> List.map (|SingleIdent|_|)
+ if elems |> List.forall (fun x -> x.IsSome) then
+ Some (SynPat.Tuple(false, (elems |> List.map (fun x -> mkSynPatVar None x.Value)), f.Range))
+ else
+ None
+ | _ -> None
+
+// For join clauses that join on nullable, we syntactically insert the creation of nullable values on the appropriate side of the condition,
+// then pull the syntax apart again
+let (|JoinRelation|_|) cenv env (e: SynExpr) =
+ let m = e.Range
+ let ad = env.eAccessRights
+
+ let isOpName opName vref s =
+ (s = opName) &&
+ match ResolveExprLongIdent cenv.tcSink cenv.nameResolver m ad env.eNameResEnv TypeNameResolutionInfo.Default [ident(opName, m)] with
+ | Result (_, Item.Value vref2, []) -> valRefEq cenv.g vref vref2
+ | _ -> false
+
+ match e with
+ | BinOpExpr(opId, a, b) when isOpName opNameEquals cenv.g.equals_operator_vref opId.idText -> Some (a, b)
+
+ | BinOpExpr(opId, a, b) when isOpName opNameEqualsNullable cenv.g.equals_nullable_operator_vref opId.idText ->
+
+ let a = SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet a.Range [MangledGlobalName;"System"] "Nullable", a, a.Range)
+ Some (a, b)
+
+ | BinOpExpr(opId, a, b) when isOpName opNameNullableEquals cenv.g.nullable_equals_operator_vref opId.idText ->
+
+ let b = SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet b.Range [MangledGlobalName;"System"] "Nullable", b, b.Range)
+ Some (a, b)
+
+ | BinOpExpr(opId, a, b) when isOpName opNameNullableEqualsNullable cenv.g.nullable_equals_nullable_operator_vref opId.idText ->
+
+ Some (a, b)
+
+ | _ -> None
+
+let elimFastIntegerForLoop (spBind, id, start, dir, finish, innerExpr, m) =
+ let pseudoEnumExpr =
+ if dir then mkSynInfix m start ".." finish
+ else mkSynTrifix m ".. .." start (SynExpr.Const (SynConst.Int32 -1, start.Range)) finish
+ SynExpr.ForEach (spBind, SeqExprOnly false, true, mkSynPatVar None id, pseudoEnumExpr, innerExpr, m)
+
+/// Check if a computation or sequence expression is syntactically free of 'yield' (though not yield!)
+let YieldFree (cenv: cenv) expr =
+ if cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitYield then
+
+ // Implement yield free logic for F# Language including the LanguageFeature.ImplicitYield
+ let rec YieldFree expr =
+ match expr with
+ | SynExpr.Sequential (_, _, e1, e2, _) ->
+ YieldFree e1 && YieldFree e2
+
+ | SynExpr.IfThenElse (_, e2, e3opt, _, _, _, _) ->
+ YieldFree e2 && Option.forall YieldFree e3opt
+
+ | SynExpr.TryWith (e1, _, clauses, _, _, _, _) ->
+ YieldFree e1 && clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
+
+ | (SynExpr.Match (_, _, clauses, _) | SynExpr.MatchBang (_, _, clauses, _)) ->
+ clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
+
+ | SynExpr.For (_, _, _, _, _, body, _)
+ | SynExpr.TryFinally (body, _, _, _, _)
+ | SynExpr.LetOrUse (_, _, _, body, _)
+ | SynExpr.While (_, _, body, _)
+ | SynExpr.ForEach (_, _, _, _, _, body, _) ->
+ YieldFree body
+
+ | SynExpr.LetOrUseBang(_, _, _, _, _, _, body, _) ->
+ YieldFree body
+
+ | SynExpr.YieldOrReturn((true, _), _, _) -> false
+
+ | _ -> true
+
+ YieldFree expr
+ else
+ // Implement yield free logic for F# Language without the LanguageFeature.ImplicitYield
+ let rec YieldFree expr =
+ match expr with
+ | SynExpr.Sequential (_, _, e1, e2, _) ->
+ YieldFree e1 && YieldFree e2
+
+ | SynExpr.IfThenElse (_, e2, e3opt, _, _, _, _) ->
+ YieldFree e2 && Option.forall YieldFree e3opt
+
+ | SynExpr.TryWith (e1, _, clauses, _, _, _, _) ->
+ YieldFree e1 && clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
+
+ | (SynExpr.Match (_, _, clauses, _) | SynExpr.MatchBang (_, _, clauses, _)) ->
+ clauses |> List.forall (fun (Clause(_, _, e, _, _)) -> YieldFree e)
+
+ | SynExpr.For (_, _, _, _, _, body, _)
+ | SynExpr.TryFinally (body, _, _, _, _)
+ | SynExpr.LetOrUse (_, _, _, body, _)
+ | SynExpr.While (_, _, body, _)
+ | SynExpr.ForEach (_, _, _, _, _, body, _) ->
+ YieldFree body
+
+ | SynExpr.LetOrUseBang _
+ | SynExpr.YieldOrReturnFrom _
+ | SynExpr.YieldOrReturn _
+ | SynExpr.ImplicitZero _
+ | SynExpr.Do _ -> false
+
+ | _ -> true
+
+ YieldFree expr
+
+
+/// Determine if a syntactic expression inside 'seq { ... }' or '[...]' counts as a "simple sequence
+/// of semicolon separated values". For example [1;2;3].
+/// 'acceptDeprecated' is true for the '[ ... ]' case, where we allow the syntax '[ if g then t else e ]' but ask it to be parenthesized
+///
+let (|SimpleSemicolonSequence|_|) cenv acceptDeprecated cexpr =
+
+ let IsSimpleSemicolonSequenceElement expr =
+ match expr with
+ | SynExpr.IfThenElse _ when acceptDeprecated && YieldFree cenv expr -> true
+ | SynExpr.IfThenElse _
+ | SynExpr.TryWith _
+ | SynExpr.Match _
+ | SynExpr.For _
+ | SynExpr.ForEach _
+ | SynExpr.TryFinally _
+ | SynExpr.YieldOrReturnFrom _
+ | SynExpr.YieldOrReturn _
+ | SynExpr.LetOrUse _
+ | SynExpr.Do _
+ | SynExpr.MatchBang _
+ | SynExpr.LetOrUseBang _
+ | SynExpr.While _ -> false
+ | _ -> true
+
+ let rec TryGetSimpleSemicolonSequenceOfComprehension expr acc =
+ match expr with
+ | SynExpr.Sequential (_, true, e1, e2, _) ->
+ if IsSimpleSemicolonSequenceElement e1 then
+ TryGetSimpleSemicolonSequenceOfComprehension e2 (e1 :: acc)
+ else
+ None
+ | e ->
+ if IsSimpleSemicolonSequenceElement e then
+ Some(List.rev (e :: acc))
+ else
+ None
+
+ TryGetSimpleSemicolonSequenceOfComprehension cexpr []
+
+let RecordNameAndTypeResolutions_IdeallyWithoutHavingOtherEffects cenv env tpenv expr =
+ // This function is motivated by cases like
+ // query { for ... join(for x in f(). }
+ // where there is incomplete code in a query, and we are current just dropping a piece of the AST on the floor (above, the bit inside the 'join').
+ //
+ // The problem with dropping the AST on the floor is that we get no captured resolutions, which means no Intellisense/QuickInfo/ParamHelp.
+ //
+ // The idea behind the fix is to semi-typecheck this AST-fragment, just to get resolutions captured.
+ //
+ // The tricky bit is to not also have any other effects from typechecking, namely producing error diagnostics (which may be spurious) or having
+ // side-effects on the typecheck environment.
+ //
+ // REVIEW: We are yet to deal with the tricky bit. As it stands, we turn off error logging, but still have typechecking environment effects. As a result,
+ // at the very least, you cannot call this function unless you're already reported a typechecking error (the 'worst' possible outcome would be
+ // to incorrectly solve typecheck constraints as a result of effects in this function, and then have the code compile successfully and behave
+ // in some weird way; so ensure the code can't possibly compile before calling this function as an expedient way to get better IntelliSense).
+ suppressErrorReporting (fun () ->
+ try ignore(TcExprOfUnknownType cenv env tpenv expr)
+ with e -> ())
+
+/// Used for all computation expressions except sequence expressions
+let TcComputationExpression cenv env overallTy tpenv (mWhole, interpExpr: Expr, builderTy, comp: SynExpr) =
+
+ //dprintfn "TcComputationExpression, comp = \n%A\n-------------------\n" comp
+ let ad = env.eAccessRights
+
+ let mkSynDelay2 (e: SynExpr) = mkSynDelay (e.Range.MakeSynthetic()) e
+
+ let builderValName = CompilerGeneratedName "builder"
+ let mBuilderVal = interpExpr.Range
+
+ // Give bespoke error messages for the FSharp.Core "query" builder
+ let isQuery =
+ match interpExpr with
+ | Expr.Val (vf, _, m) ->
+ let item = Item.CustomBuilder (vf.DisplayName, vf)
+ CallNameResolutionSink cenv.tcSink (m, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.eAccessRights)
+ valRefEq cenv.g vf cenv.g.query_value_vref
+ | _ -> false
+
+ /// Make a builder.Method(...) call
+ let mkSynCall nm (m: range) args =
+ let m = m.MakeSynthetic() // Mark as synthetic so the language service won't pick it up.
+ let args =
+ match args with
+ | [] -> SynExpr.Const (SynConst.Unit, m)
+ | [arg] -> SynExpr.Paren (SynExpr.Paren (arg, range0, None, m), range0, None, m)
+ | args -> SynExpr.Paren (SynExpr.Tuple (false, args, [], m), range0, None, m)
+
+ let builderVal = mkSynIdGet m builderValName
+ mkSynApp1 (SynExpr.DotGet (builderVal, range0, LongIdentWithDots([mkSynId m nm], []), m)) args m
+
+ let hasMethInfo nm = TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mBuilderVal ad nm builderTy |> isNil |> not
+
+ let sourceMethInfo = TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mBuilderVal ad "Source" builderTy
+
+ // Optionally wrap sources of "let!", "yield!", "use!" in "query.Source"
+ let mkSourceExpr callExpr =
+ match sourceMethInfo with
+ | [] -> callExpr
+ | _ -> mkSynCall "Source" callExpr.Range [callExpr]
+
+ let mkSourceExprConditional isFromSource callExpr =
+ if isFromSource then mkSourceExpr callExpr else callExpr
+
+ /// Decide if the builder is an auto-quote builder
+ let isAutoQuote = hasMethInfo "Quote"
+
+ let customOperationMethods =
+ AllMethInfosOfTypeInScope ResultCollectionSettings.AllResults cenv.infoReader env.NameEnv None ad IgnoreOverrides mBuilderVal builderTy
+ |> List.choose (fun methInfo ->
+ if not (IsMethInfoAccessible cenv.amap mBuilderVal ad methInfo) then None else
+ let nameSearch =
+ TryBindMethInfoAttribute cenv.g mBuilderVal cenv.g.attrib_CustomOperationAttribute methInfo
+ IgnoreAttribute // We do not respect this attribute for IL methods
+ (function (Attrib(_, _, [ AttribStringArg msg ], _, _, _, _)) -> Some msg | _ -> None)
+ IgnoreAttribute // We do not respect this attribute for provided methods
+
+ match nameSearch with
+ | None -> None
+ | Some nm ->
+ let joinConditionWord =
+ TryBindMethInfoAttribute cenv.g mBuilderVal cenv.g.attrib_CustomOperationAttribute methInfo
+ IgnoreAttribute // We do not respect this attribute for IL methods
+ (function (Attrib(_, _, _, ExtractAttribNamedArg "JoinConditionWord" (AttribStringArg s), _, _, _)) -> Some s | _ -> None)
+ IgnoreAttribute // We do not respect this attribute for provided methods
+
+ let flagSearch (propName: string) =
+ TryBindMethInfoAttribute cenv.g mBuilderVal cenv.g.attrib_CustomOperationAttribute methInfo
+ IgnoreAttribute // We do not respect this attribute for IL methods
+ (function (Attrib(_, _, _, ExtractAttribNamedArg propName (AttribBoolArg b), _, _, _)) -> Some b | _ -> None)
+ IgnoreAttribute // We do not respect this attribute for provided methods
+
+ let maintainsVarSpaceUsingBind = defaultArg (flagSearch "MaintainsVariableSpaceUsingBind") false
+ let maintainsVarSpace = defaultArg (flagSearch "MaintainsVariableSpace") false
+ let allowInto = defaultArg (flagSearch "AllowIntoPattern") false
+ let isLikeZip = defaultArg (flagSearch "IsLikeZip") false
+ let isLikeJoin = defaultArg (flagSearch "IsLikeJoin") false
+ let isLikeGroupJoin = defaultArg (flagSearch "IsLikeGroupJoin") false
+
+ Some (nm, maintainsVarSpaceUsingBind, maintainsVarSpace, allowInto, isLikeZip, isLikeJoin, isLikeGroupJoin, joinConditionWord, methInfo))
+
+ let customOperationMethodsIndexedByKeyword =
+ if cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations then
+ customOperationMethods
+ |> Seq.groupBy (fun (nm, _, _, _, _, _, _, _, _) -> nm)
+ |> Seq.map (fun (nm, group) ->
+ (nm,
+ group
+ |> Seq.toList))
+ else
+ customOperationMethods
+ |> Seq.groupBy (fun (nm, _, _, _, _, _, _, _, _) -> nm)
+ |> Seq.map (fun (nm, g) -> (nm, Seq.toList g))
+ |> dict
+
+ // Check for duplicates by method name (keywords and method names must be 1:1)
+ let customOperationMethodsIndexedByMethodName =
+ if cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations then
+ customOperationMethods
+ |> Seq.groupBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName)
+ |> Seq.map (fun (nm, group) ->
+ (nm,
+ group
+ |> Seq.toList))
+ else
+ customOperationMethods
+ |> Seq.groupBy (fun (_, _, _, _, _, _, _, _, methInfo) -> methInfo.LogicalName)
+ |> Seq.map (fun (nm, g) -> (nm, Seq.toList g))
+ |> dict
+
+ /// Decide if the identifier represents a use of a custom query operator
+ let tryGetDataForCustomOperation (nm: Ident) =
+ match customOperationMethodsIndexedByKeyword.TryGetValue nm.idText with
+ | true, opDatas when (opDatas.Length = 1 || (opDatas.Length > 0 && cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations)) ->
+ for opData in opDatas do
+ let (opName, maintainsVarSpaceUsingBind, maintainsVarSpace, _allowInto, isLikeZip, isLikeJoin, isLikeGroupJoin, _joinConditionWord, methInfo) = opData
+ if (maintainsVarSpaceUsingBind && maintainsVarSpace) || (isLikeZip && isLikeJoin) || (isLikeZip && isLikeGroupJoin) || (isLikeJoin && isLikeGroupJoin) then
+ errorR(Error(FSComp.SR.tcCustomOperationInvalid opName, nm.idRange))
+ if not (cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations) then
+ match customOperationMethodsIndexedByMethodName.TryGetValue methInfo.LogicalName with
+ | true, [_] -> ()
+ | _ -> errorR(Error(FSComp.SR.tcCustomOperationMayNotBeOverloaded nm.idText, nm.idRange))
+ Some opDatas
+ | true, (opData :: _) -> errorR(Error(FSComp.SR.tcCustomOperationMayNotBeOverloaded nm.idText, nm.idRange)); Some [opData]
+ | _ -> None
+
+ /// Decide if the identifier represents a use of a custom query operator
+ let hasCustomOperations () = if isNil customOperationMethods then CustomOperationsMode.Denied else CustomOperationsMode.Allowed
+
+ let isCustomOperation nm = tryGetDataForCustomOperation nm |> Option.isSome
+
+ let customOperationCheckValidity m f opDatas =
+ let vs = opDatas |> List.map f
+ let v0 = vs.[0]
+ let (opName, _maintainsVarSpaceUsingBind, _maintainsVarSpace, _allowInto, _isLikeZip, _isLikeJoin, _isLikeGroupJoin, _joinConditionWord, _methInfo) = opDatas.[0]
+ if not (List.allEqual vs) then
+ errorR(Error(FSComp.SR.tcCustomOperationInvalid opName, m))
+ v0
+
+ // Check for the MaintainsVariableSpace on custom operation
+ let customOperationMaintainsVarSpace (nm: Ident) =
+ match tryGetDataForCustomOperation nm with
+ | None -> false
+ | Some opDatas ->
+ opDatas |> customOperationCheckValidity nm.idRange (fun (_nm, _maintainsVarSpaceUsingBind, maintainsVarSpace, _allowInto, _isLikeZip, _isLikeJoin, _isLikeGroupJoin, _joinConditionWord, _methInfo) -> maintainsVarSpace)
+
+ let customOperationMaintainsVarSpaceUsingBind (nm: Ident) =
+ match tryGetDataForCustomOperation nm with
+ | None -> false
+ | Some opDatas ->
+ opDatas |> customOperationCheckValidity nm.idRange (fun (_nm, maintainsVarSpaceUsingBind, _maintainsVarSpace, _allowInto, _isLikeZip, _isLikeJoin, _isLikeGroupJoin, _joinConditionWord, _methInfo) -> maintainsVarSpaceUsingBind)
+
+ let customOperationIsLikeZip (nm: Ident) =
+ match tryGetDataForCustomOperation nm with
+ | None -> false
+ | Some opDatas ->
+ opDatas |> customOperationCheckValidity nm.idRange (fun (_nm, _maintainsVarSpaceUsingBind, _maintainsVarSpace, _allowInto, isLikeZip, _isLikeJoin, _isLikeGroupJoin, _joinConditionWord, _methInfo) -> isLikeZip)
+
+ let customOperationIsLikeJoin (nm: Ident) =
+ match tryGetDataForCustomOperation nm with
+ | None -> false
+ | Some opDatas ->
+ opDatas |> customOperationCheckValidity nm.idRange (fun (_nm, _maintainsVarSpaceUsingBind, _maintainsVarSpace, _allowInto, _isLikeZip, isLikeJoin, _isLikeGroupJoin, _joinConditionWord, _methInfo) -> isLikeJoin)
+
+ let customOperationIsLikeGroupJoin (nm: Ident) =
+ match tryGetDataForCustomOperation nm with
+ | None -> false
+ | Some opDatas ->
+ opDatas |> customOperationCheckValidity nm.idRange (fun (_nm, _maintainsVarSpaceUsingBind, _maintainsVarSpace, _allowInto, _isLikeZip, _isLikeJoin, isLikeGroupJoin, _joinConditionWord, _methInfo) -> isLikeGroupJoin)
+
+ let customOperationJoinConditionWord (nm: Ident) =
+ match tryGetDataForCustomOperation nm with
+ | Some opDatas ->
+ opDatas |> customOperationCheckValidity nm.idRange (fun (_nm, _maintainsVarSpaceUsingBind, _maintainsVarSpace, _allowInto, _isLikeZip, _isLikeJoin, _isLikeGroupJoin, joinConditionWord, _methInfo) -> joinConditionWord)
+ |> function None -> "on" | Some v -> v
+ | _ -> "on"
+
+ let customOperationAllowsInto (nm: Ident) =
+ match tryGetDataForCustomOperation nm with
+ | None -> false
+ | Some opDatas ->
+ opDatas |> customOperationCheckValidity nm.idRange (fun (_nm, _maintainsVarSpaceUsingBind, _maintainsVarSpace, allowInto, _isLikeZip, _isLikeJoin, _isLikeGroupJoin, _joinConditionWord, _methInfo) -> allowInto)
+
+ let customOpUsageText nm =
+ match tryGetDataForCustomOperation nm with
+ | Some ((_nm, _maintainsVarSpaceUsingBind, _maintainsVarSpace, _allowInto, isLikeZip, isLikeJoin, isLikeGroupJoin, _joinConditionWord, _methInfo) :: _) ->
+ if isLikeGroupJoin then
+ Some (FSComp.SR.customOperationTextLikeGroupJoin(nm.idText, customOperationJoinConditionWord nm, customOperationJoinConditionWord nm))
+ elif isLikeJoin then
+ Some (FSComp.SR.customOperationTextLikeJoin(nm.idText, customOperationJoinConditionWord nm, customOperationJoinConditionWord nm))
+ elif isLikeZip then
+ Some (FSComp.SR.customOperationTextLikeZip(nm.idText))
+ else
+ None
+ | _ -> None
+
+ /// Inside the 'query { ... }' use a modified name environment that contains fake 'CustomOperation' entries
+ /// for all custom operations. This adds them to the completion lists and prevents them being used as values inside
+ /// the query.
+ let env =
+ if List.isEmpty customOperationMethods then env else
+ { env with
+ eNameResEnv =
+ (env.eNameResEnv, customOperationMethods)
+ ||> Seq.fold (fun nenv (nm, _, _, _, _, _, _, _, methInfo) ->
+ AddFakeNameToNameEnv nm nenv (Item.CustomOperation (nm, (fun () -> customOpUsageText (ident (nm, mBuilderVal))), Some methInfo))) }
+
+ // Environment is needed for completions
+ CallEnvSink cenv.tcSink (comp.Range, env.NameEnv, ad)
+
+ // Check for the [] attribute on an argument position
+ let tryGetArgInfosForCustomOperator (nm: Ident) =
+ match tryGetDataForCustomOperation nm with
+ | Some argInfos ->
+ argInfos
+ |> List.map (fun (_nm, __maintainsVarSpaceUsingBind, _maintainsVarSpace, _allowInto, _isLikeZip, _isLikeJoin, _isLikeGroupJoin, _joinConditionWord, methInfo) ->
+ match methInfo with
+ | FSMeth(_, _, vref, _) ->
+ match ArgInfosOfMember cenv.g vref with
+ | [curriedArgInfo] -> Some curriedArgInfo // one for the actual argument group
+ | _ -> None
+ | _ -> None)
+ |> Some
+ | _ -> None
+
+ let tryExpectedArgCountForCustomOperator (nm: Ident) =
+ match tryGetArgInfosForCustomOperator nm with
+ | None -> None
+ | Some argInfosForOverloads ->
+ let nums = argInfosForOverloads |> List.map (function None -> -1 | Some argInfos -> List.length argInfos)
+ if nums |> List.forall (fun v -> v >= 0 && v = nums.[0]) then
+ Some (max (nums.[0] - 1) 0) // drop the computation context argument
+ else
+ None
+
+ // Check for the [] attribute on an argument position
+ let isCustomOperationProjectionParameter i (nm: Ident) =
+ match tryGetArgInfosForCustomOperator nm with
+ | None -> false
+ | Some argInfosForOverloads ->
+ let vs =
+ argInfosForOverloads |> List.map (function
+ | None -> false
+ | Some argInfos ->
+ i < argInfos.Length &&
+ let (_, argInfo) = List.item i argInfos
+ HasFSharpAttribute cenv.g cenv.g.attrib_ProjectionParameterAttribute argInfo.Attribs)
+ if List.allEqual vs then vs.[0]
+ else
+ let opDatas = (tryGetDataForCustomOperation nm).Value
+ let (opName, _, _, _, _, _, _, _j, _) = opDatas.[0]
+ errorR(Error(FSComp.SR.tcCustomOperationInvalid opName, nm.idRange))
+ false
+
+ let (|ForEachThen|_|) e =
+ match e with
+ | SynExpr.ForEach (_spBind, SeqExprOnly false, isFromSource, pat1, expr1, SynExpr.Sequential (_, true, clause, rest, _), _) -> Some (isFromSource, pat1, expr1, clause, rest)
+ | _ -> None
+
+ let (|CustomOpId|_|) predicate e =
+ match e with
+ | SingleIdent nm when isCustomOperation nm && predicate nm -> Some nm
+ | _ -> None
+
+ // e1 in e2 ('in' is parsed as 'JOIN_IN')
+ let (|InExpr|_|) (e: SynExpr) =
+ match e with
+ | SynExpr.JoinIn (e1, _, e2, mApp) -> Some (e1, e2, mApp)
+ | _ -> None
+
+ // e1 on e2 (note: 'on' is the 'JoinConditionWord')
+ let (|OnExpr|_|) nm (e: SynExpr) =
+ match tryGetDataForCustomOperation nm with
+ | None -> None
+ | Some _ ->
+ match e with
+ | SynExpr.App (_, _, SynExpr.App (_, _, e1, SingleIdent opName, _), e2, _) when opName.idText = customOperationJoinConditionWord nm ->
+ let item = Item.CustomOperation (opName.idText, (fun () -> None), None)
+ CallNameResolutionSink cenv.tcSink (opName.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.AccessRights)
+ Some (e1, e2)
+ | _ -> None
+
+ // e1 into e2
+ let (|IntoSuffix|_|) (e: SynExpr) =
+ match e with
+ | SynExpr.App (_, _, SynExpr.App (_, _, x, SingleIdent nm2, _), ExprAsPat intoPat, _) when nm2.idText = CustomOperations.Into ->
+ Some (x, nm2.idRange, intoPat)
+ | _ ->
+ None
+
+ let arbPat (m: range) = mkSynPatVar None (mkSynId (m.MakeSynthetic()) "_missingVar")
+
+ let MatchIntoSuffixOrRecover alreadyGivenError (nm: Ident) (e: SynExpr) =
+ match e with
+ | IntoSuffix (x, intoWordRange, intoPat) ->
+ // record the "into" as a custom operation for colorization
+ let item = Item.CustomOperation ("into", (fun () -> None), None)
+ CallNameResolutionSink cenv.tcSink (intoWordRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.eAccessRights)
+ (x, intoPat, alreadyGivenError)
+ | _ ->
+ if not alreadyGivenError then
+ errorR(Error(FSComp.SR.tcOperatorIncorrectSyntax(nm.idText, Option.get (customOpUsageText nm)), nm.idRange))
+ (e, arbPat e.Range, true)
+
+ let MatchOnExprOrRecover alreadyGivenError nm (onExpr: SynExpr) =
+ match onExpr with
+ | OnExpr nm (innerSource, SynExprParen(keySelectors, _, _, _)) ->
+ (innerSource, keySelectors)
+ | _ ->
+ if not alreadyGivenError then
+ suppressErrorReporting (fun () -> TcExprOfUnknownType cenv env tpenv onExpr) |> ignore
+ errorR(Error(FSComp.SR.tcOperatorIncorrectSyntax(nm.idText, Option.get (customOpUsageText nm)), nm.idRange))
+ (arbExpr("_innerSource", onExpr.Range), mkSynBifix onExpr.Range "=" (arbExpr("_keySelectors", onExpr.Range)) (arbExpr("_keySelector2", onExpr.Range)))
+
+ let JoinOrGroupJoinOp detector e =
+ match e with
+ | SynExpr.App (_, _, CustomOpId detector nm, ExprAsPat innerSourcePat, mJoinCore) ->
+ Some(nm, innerSourcePat, mJoinCore, false)
+ // join with bad pattern (gives error on "join" and continues)
+ | SynExpr.App (_, _, CustomOpId detector nm, _innerSourcePatExpr, mJoinCore) ->
+ errorR(Error(FSComp.SR.tcBinaryOperatorRequiresVariable(nm.idText, Option.get (customOpUsageText nm)), nm.idRange))
+ Some(nm, arbPat mJoinCore, mJoinCore, true)
+ // join (without anything after - gives error on "join" and continues)
+ | CustomOpId detector nm ->
+ errorR(Error(FSComp.SR.tcBinaryOperatorRequiresVariable(nm.idText, Option.get (customOpUsageText nm)), nm.idRange))
+ Some(nm, arbPat e.Range, e.Range, true)
+ | _ ->
+ None
+ // JoinOrGroupJoinOp customOperationIsLikeJoin
+
+ let (|JoinOp|_|) (e: SynExpr) = JoinOrGroupJoinOp customOperationIsLikeJoin e
+ let (|GroupJoinOp|_|) (e: SynExpr) = JoinOrGroupJoinOp customOperationIsLikeGroupJoin e
+
+ let arbKeySelectors m = mkSynBifix m "=" (arbExpr("_keySelectors", m)) (arbExpr("_keySelector2", m))
+
+ let (|JoinExpr|_|) (e: SynExpr) =
+ match e with
+ | InExpr (JoinOp(nm, innerSourcePat, _, alreadyGivenError), onExpr, mJoinCore) ->
+ let (innerSource, keySelectors) = MatchOnExprOrRecover alreadyGivenError nm onExpr
+ Some(nm, innerSourcePat, innerSource, keySelectors, mJoinCore)
+ | JoinOp (nm, innerSourcePat, mJoinCore, alreadyGivenError) ->
+ if alreadyGivenError then
+ errorR(Error(FSComp.SR.tcOperatorRequiresIn(nm.idText, Option.get (customOpUsageText nm)), nm.idRange))
+ Some (nm, innerSourcePat, arbExpr("_innerSource", e.Range), arbKeySelectors e.Range, mJoinCore)
+ | _ -> None
+
+ let (|GroupJoinExpr|_|) (e: SynExpr) =
+ match e with
+ | InExpr (GroupJoinOp (nm, innerSourcePat, _, alreadyGivenError), intoExpr, mGroupJoinCore) ->
+ let onExpr, intoPat, alreadyGivenError = MatchIntoSuffixOrRecover alreadyGivenError nm intoExpr
+ let innerSource, keySelectors = MatchOnExprOrRecover alreadyGivenError nm onExpr
+ Some (nm, innerSourcePat, innerSource, keySelectors, intoPat, mGroupJoinCore)
+ | GroupJoinOp (nm, innerSourcePat, mGroupJoinCore, alreadyGivenError) ->
+ if alreadyGivenError then
+ errorR(Error(FSComp.SR.tcOperatorRequiresIn(nm.idText, Option.get (customOpUsageText nm)), nm.idRange))
+ Some (nm, innerSourcePat, arbExpr("_innerSource", e.Range), arbKeySelectors e.Range, arbPat e.Range, mGroupJoinCore)
+ | _ ->
+ None
+
+
+ let (|JoinOrGroupJoinOrZipClause|_|) (e: SynExpr) =
+ match e with
+
+ // join innerSourcePat in innerSource on (keySelector1 = keySelector2)
+ | JoinExpr (nm, innerSourcePat, innerSource, keySelectors, mJoinCore) ->
+ Some(nm, innerSourcePat, innerSource, Some keySelectors, None, mJoinCore)
+
+ // groupJoin innerSourcePat in innerSource on (keySelector1 = keySelector2) into intoPat
+ | GroupJoinExpr (nm, innerSourcePat, innerSource, keySelectors, intoPat, mGroupJoinCore) ->
+ Some(nm, innerSourcePat, innerSource, Some keySelectors, Some intoPat, mGroupJoinCore)
+
+ // zip intoPat in secondSource
+ | InExpr (SynExpr.App (_, _, CustomOpId customOperationIsLikeZip nm, ExprAsPat secondSourcePat, _), secondSource, mZipCore) ->
+ Some(nm, secondSourcePat, secondSource, None, None, mZipCore)
+
+ // zip (without secondSource or in - gives error)
+ | CustomOpId customOperationIsLikeZip nm ->
+ errorR(Error(FSComp.SR.tcOperatorIncorrectSyntax(nm.idText, Option.get (customOpUsageText nm)), nm.idRange))
+ Some(nm, arbPat e.Range, arbExpr("_secondSource", e.Range), None, None, e.Range)
+
+ // zip secondSource (without in - gives error)
+ | SynExpr.App (_, _, CustomOpId customOperationIsLikeZip nm, ExprAsPat secondSourcePat, mZipCore) ->
+ errorR(Error(FSComp.SR.tcOperatorIncorrectSyntax(nm.idText, Option.get (customOpUsageText nm)), mZipCore))
+ Some(nm, secondSourcePat, arbExpr("_innerSource", e.Range), None, None, mZipCore)
+
+ | _ ->
+ None
+
+ let (|ForEachThenJoinOrGroupJoinOrZipClause|_|) e =
+ match e with
+ | ForEachThen (isFromSource, firstSourcePat, firstSource, JoinOrGroupJoinOrZipClause(nm, secondSourcePat, secondSource, keySelectorsOpt, pat3opt, mOpCore), innerComp)
+ when
+ (let _firstSourceSimplePats, later1 =
+ use _holder = TemporarilySuspendReportingTypecheckResultsToSink cenv.tcSink
+ SimplePatsOfPat cenv.synArgNameGenerator firstSourcePat
+ Option.isNone later1)
+
+ -> Some (isFromSource, firstSourcePat, firstSource, nm, secondSourcePat, secondSource, keySelectorsOpt, pat3opt, mOpCore, innerComp)
+
+ | JoinOrGroupJoinOrZipClause(nm, pat2, expr2, expr3, pat3opt, mOpCore) ->
+ errorR(Error(FSComp.SR.tcBinaryOperatorRequiresBody(nm.idText, Option.get (customOpUsageText nm)), nm.idRange))
+ Some (true, arbPat e.Range, arbExpr("_outerSource", e.Range), nm, pat2, expr2, expr3, pat3opt, mOpCore, arbExpr("_innerComp", e.Range))
+
+ | _ ->
+ None
+
+ let (|StripApps|) e =
+ let rec strip e =
+ match e with
+ | SynExpr.FromParseError (SynExpr.App (_, _, f, arg, _), _)
+ | SynExpr.App (_, _, f, arg, _) ->
+ let g, acc = strip f
+ g, (arg :: acc)
+ | _ -> e, []
+ let g, acc = strip e
+ g, List.rev acc
+
+ let (|OptionalIntoSuffix|) e =
+ match e with
+ | IntoSuffix (body, intoWordRange, optInfo) -> (body, Some (intoWordRange, optInfo))
+ | body -> (body, None)
+
+ let (|CustomOperationClause|_|) e =
+ match e with
+ | OptionalIntoSuffix(StripApps(SingleIdent nm, _) as core, optInto) when isCustomOperation nm ->
+ // Now we know we have a custom operation, commit the name resolution
+ let optIntoInfo =
+ match optInto with
+ | Some (intoWordRange, optInfo) ->
+ let item = Item.CustomOperation ("into", (fun () -> None), None)
+ CallNameResolutionSink cenv.tcSink (intoWordRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.eAccessRights)
+ Some optInfo
+ | None -> None
+
+ Some (nm, Option.get (tryGetDataForCustomOperation nm), core, core.Range, optIntoInfo)
+ | _ -> None
+
+ let mkSynLambda p e m = SynExpr.Lambda (false, false, p, e, None, m)
+
+ let mkExprForVarSpace m (patvs: Val list) =
+ match patvs with
+ | [] -> SynExpr.Const (SynConst.Unit, m)
+ | [v] -> SynExpr.Ident v.Id
+ | vs -> SynExpr.Tuple (false, (vs |> List.map (fun v -> SynExpr.Ident v.Id)), [], m)
+
+ let mkSimplePatForVarSpace m (patvs: Val list) =
+ let spats =
+ match patvs with
+ | [] -> []
+ | [v] -> [mkSynSimplePatVar false v.Id]
+ | vs -> vs |> List.map (fun v -> mkSynSimplePatVar false v.Id)
+ SynSimplePats.SimplePats (spats, m)
+
+ let mkPatForVarSpace m (patvs: Val list) =
+ match patvs with
+ | [] -> SynPat.Const (SynConst.Unit, m)
+ | [v] -> mkSynPatVar None v.Id
+ | vs -> SynPat.Tuple(false, (vs |> List.map (fun x -> mkSynPatVar None x.Id)), m)
+
+ let (|OptionalSequential|) e =
+ match e with
+ | SynExpr.Sequential (_sp, true, dataComp1, dataComp2, _) -> (dataComp1, Some dataComp2)
+ | _ -> (e, None)
+
+ // "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
+ let rangeForCombine innerComp1 =
+ match innerComp1 with
+ | SynExpr.IfThenElse (_, _, _, _, _, mIfToThen, _m) -> mIfToThen
+ | SynExpr.Match (DebugPointAtBinding mMatch, _, _, _) -> mMatch
+ | SynExpr.TryWith (_, _, _, _, _, DebugPointAtTry.Yes mTry, _) -> mTry
+ | SynExpr.TryFinally (_, _, _, DebugPointAtTry.Yes mTry, _) -> mTry
+ | SynExpr.For (DebugPointAtFor.Yes mBind, _, _, _, _, _, _) -> mBind
+ | SynExpr.ForEach (DebugPointAtFor.Yes mBind, _, _, _, _, _, _) -> mBind
+ | SynExpr.While (DebugPointAtWhile.Yes mWhile, _, _, _) -> mWhile
+ | _ -> innerComp1.Range
+
+ // Check for 'where x > y', 'select x, y' and other mis-applications of infix operators, give a good error message, and return a flag
+ let checkForBinaryApp comp =
+ match comp with
+ | StripApps(SingleIdent nm, [StripApps(SingleIdent nm2, args); arg2]) when
+ PrettyNaming.IsInfixOperator nm.idText &&
+ (match tryExpectedArgCountForCustomOperator nm2 with Some n -> n > 0 | _ -> false) &&
+ not (List.isEmpty args) ->
+ let estimatedRangeOfIntendedLeftAndRightArguments = unionRanges (List.last args).Range arg2.Range
+ errorR(Error(FSComp.SR.tcUnrecognizedQueryBinaryOperator(), estimatedRangeOfIntendedLeftAndRightArguments))
+ true
+ | SynExpr.Tuple (false, (StripApps(SingleIdent nm2, args) :: _), _, m) when
+ (match tryExpectedArgCountForCustomOperator nm2 with Some n -> n > 0 | _ -> false) &&
+ not (List.isEmpty args) ->
+ let estimatedRangeOfIntendedLeftAndRightArguments = unionRanges (List.last args).Range m.EndRange
+ errorR(Error(FSComp.SR.tcUnrecognizedQueryBinaryOperator(), estimatedRangeOfIntendedLeftAndRightArguments))
+ true
+ | _ ->
+ false
+
+ let addVarsToVarSpace (varSpace: LazyWithContext) f =
+ LazyWithContext.Create
+ ((fun m ->
+ let (patvs: Val list, env) = varSpace.Force m
+ let vs, envinner = f m env
+ let patvs = List.append patvs (vs |> List.filter (fun v -> not (patvs |> List.exists (fun v2 -> v.LogicalName = v2.LogicalName))))
+ patvs, envinner),
+ id)
+
+ let emptyVarSpace = LazyWithContext.NotLazy ([], env)
+
+ // If there are no 'yield' in the computation expression, and the builder supports 'Yield',
+ // then allow the type-directed rule interpreting non-unit-typed expressions in statement
+ // positions as 'yield'. 'yield!' may be present in the computation expression.
+ let enableImplicitYield =
+ cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitYield
+ && (hasMethInfo "Yield" && hasMethInfo "Combine" && hasMethInfo "Delay" && YieldFree cenv comp)
+
+ // q - a flag indicating if custom operators are allowed. They are not allowed inside try/with, try/finally, if/then/else etc.
+ // varSpace - a lazy data structure indicating the variables bound so far in the overall computation
+ // comp - the computation expression being analyzed
+ // translatedCtxt - represents the translation of the context in which the computation expression 'comp' occurs, up to a
+ // hole to be filled by (part of) the results of translating 'comp'.
+ let rec tryTrans firstTry q varSpace comp translatedCtxt =
+
+ match comp with
+
+ // for firstSourcePat in firstSource do
+ // join secondSourcePat in expr2 on (expr3 = expr4)
+ // ...
+ // -->
+ // join expr1 expr2 (fun firstSourcePat -> expr3) (fun secondSourcePat -> expr4) (fun firstSourcePat secondSourcePat -> ...)
+
+ // for firstSourcePat in firstSource do
+ // groupJoin secondSourcePat in expr2 on (expr3 = expr4) into groupPat
+ // ...
+ // -->
+ // groupJoin expr1 expr2 (fun firstSourcePat -> expr3) (fun secondSourcePat -> expr4) (fun firstSourcePat groupPat -> ...)
+
+ // for firstSourcePat in firstSource do
+ // zip secondSource into secondSourcePat
+ // ...
+ // -->
+ // zip expr1 expr2 (fun pat1 pat3 -> ...)
+ | ForEachThenJoinOrGroupJoinOrZipClause (isFromSource, firstSourcePat, firstSource, nm, secondSourcePat, secondSource, keySelectorsOpt, secondResultPatOpt, mOpCore, innerComp) ->
+
+
+ if q = CustomOperationsMode.Denied then error(Error(FSComp.SR.tcCustomOperationMayNotBeUsedHere(), nm.idRange))
+ let firstSource = mkSourceExprConditional isFromSource firstSource
+ let secondSource = mkSourceExpr secondSource
+
+ // Add the variables to the variable space, on demand
+ let varSpaceWithFirstVars =
+ addVarsToVarSpace varSpace (fun _mCustomOp env ->
+ use _holder = TemporarilySuspendReportingTypecheckResultsToSink cenv.tcSink
+ let _, _, vspecs, envinner, _ = TcMatchPattern cenv (NewInferenceType()) env tpenv (firstSourcePat, None)
+ vspecs, envinner)
+
+ let varSpaceWithSecondVars =
+ addVarsToVarSpace varSpaceWithFirstVars (fun _mCustomOp env ->
+ use _holder = TemporarilySuspendReportingTypecheckResultsToSink cenv.tcSink
+ let _, _, vspecs, envinner, _ = TcMatchPattern cenv (NewInferenceType()) env tpenv (secondSourcePat, None)
+ vspecs, envinner)
+
+ let varSpaceWithGroupJoinVars =
+ match secondResultPatOpt with
+ | Some pat3 ->
+ addVarsToVarSpace varSpaceWithFirstVars (fun _mCustomOp env ->
+ use _holder = TemporarilySuspendReportingTypecheckResultsToSink cenv.tcSink
+ let _, _, vspecs, envinner, _ = TcMatchPattern cenv (NewInferenceType()) env tpenv (pat3, None)
+ vspecs, envinner)
+ | None -> varSpace
+
+ let firstSourceSimplePats, later1 = SimplePatsOfPat cenv.synArgNameGenerator firstSourcePat
+ let secondSourceSimplePats, later2 = SimplePatsOfPat cenv.synArgNameGenerator secondSourcePat
+
+ if Option.isSome later1 then errorR (Error (FSComp.SR.tcJoinMustUseSimplePattern(nm.idText), firstSourcePat.Range))
+ if Option.isSome later2 then errorR (Error (FSComp.SR.tcJoinMustUseSimplePattern(nm.idText), secondSourcePat.Range))
+
+ // check 'join' or 'groupJoin' or 'zip' is permitted for this builder
+ match tryGetDataForCustomOperation nm with
+ | None -> error(Error(FSComp.SR.tcMissingCustomOperation(nm.idText), nm.idRange))
+ | Some opDatas ->
+ let (opName, _, _, _, _, _, _, _, methInfo) = opDatas.[0]
+
+ // Record the resolution of the custom operation for posterity
+ let item = Item.CustomOperation (opName, (fun () -> customOpUsageText nm), Some methInfo)
+
+ // FUTURE: consider whether we can do better than emptyTyparInst here, in order to display instantiations
+ // of type variables in the quick info provided in the IDE.
+ CallNameResolutionSink cenv.tcSink (nm.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.eAccessRights)
+
+ let mkJoinExpr keySelector1 keySelector2 innerPat e =
+ let mSynthetic = mOpCore.MakeSynthetic()
+ mkSynCall methInfo.DisplayName mOpCore
+ [ firstSource
+ secondSource
+ (mkSynLambda firstSourceSimplePats keySelector1 mSynthetic)
+ (mkSynLambda secondSourceSimplePats keySelector2 mSynthetic)
+ (mkSynLambda firstSourceSimplePats (mkSynLambda innerPat e mSynthetic) mSynthetic) ]
+
+ let mkZipExpr e =
+ let mSynthetic = mOpCore.MakeSynthetic()
+ mkSynCall methInfo.DisplayName mOpCore
+ [ firstSource
+ secondSource
+ (mkSynLambda firstSourceSimplePats (mkSynLambda secondSourceSimplePats e mSynthetic) mSynthetic) ]
+
+ // wraps given expression into sequence with result produced by arbExpr so result will look like:
+ // l; SynExpr.ArbitraryAfterError (...)
+ // this allows to handle cases like 'on (a > b)' // '>' is not permitted as correct join relation
+ // after wrapping a and b can still be typechecked (so we'll have correct completion inside 'on' part)
+ // but presence of SynExpr.ArbitraryAfterError allows to avoid errors about incompatible types in cases like
+ // query {
+ // for a in [1] do
+ // join b in [""] on (a > b)
+ // }
+ // if we typecheck raw 'a' and 'b' then we'll end up with 2 errors:
+ // 1. incorrect join relation
+ // 2. incompatible types: int and string
+ // with SynExpr.ArbitraryAfterError we have only first one
+ let wrapInArbErrSequence l caption =
+ SynExpr.Sequential (DebugPointAtSequential.Both, true, l, (arbExpr(caption, l.Range.EndRange)), l.Range)
+
+ let mkOverallExprGivenVarSpaceExpr, varSpaceInner =
+ let isNullableOp opId =
+ match DecompileOpName opId with "?=" | "=?" | "?=?" -> true | _ -> false
+ match secondResultPatOpt, keySelectorsOpt with
+ // groupJoin
+ | Some secondResultPat, Some relExpr when customOperationIsLikeGroupJoin nm ->
+ let secondResultSimplePats, later3 = SimplePatsOfPat cenv.synArgNameGenerator secondResultPat
+ if Option.isSome later3 then errorR (Error (FSComp.SR.tcJoinMustUseSimplePattern(nm.idText), secondResultPat.Range))
+ match relExpr with
+ | JoinRelation cenv env (keySelector1, keySelector2) ->
+ mkJoinExpr keySelector1 keySelector2 secondResultSimplePats, varSpaceWithGroupJoinVars
+ | BinOpExpr (opId, l, r) ->
+ if isNullableOp opId.idText then
+ // When we cannot resolve NullableOps, recommend the relevant namespace to be added
+ errorR(Error(FSComp.SR.cannotResolveNullableOperators(DecompileOpName opId.idText), relExpr.Range))
+ else
+ errorR(Error(FSComp.SR.tcInvalidRelationInJoin(nm.idText), relExpr.Range))
+ let l = wrapInArbErrSequence l "_keySelector1"
+ let r = wrapInArbErrSequence r "_keySelector2"
+ // this is not correct JoinRelation but it is still binary operation
+ // we've already reported error now we can use operands of binary operation as join components
+ mkJoinExpr l r secondResultSimplePats, varSpaceWithGroupJoinVars
+ | _ ->
+ errorR(Error(FSComp.SR.tcInvalidRelationInJoin(nm.idText), relExpr.Range))
+ // since the shape of relExpr doesn't match our expectations (JoinRelation)
+ // then we assume that this is l.h.s. of the join relation
+ // so typechecker will treat relExpr as body of outerKeySelector lambda parameter in GroupJoin method
+ mkJoinExpr relExpr (arbExpr("_keySelector2", relExpr.Range)) secondResultSimplePats, varSpaceWithGroupJoinVars
+
+ | None, Some relExpr when customOperationIsLikeJoin nm ->
+ match relExpr with
+ | JoinRelation cenv env (keySelector1, keySelector2) ->
+ mkJoinExpr keySelector1 keySelector2 secondSourceSimplePats, varSpaceWithSecondVars
+ | BinOpExpr (opId, l, r) ->
+ if isNullableOp opId.idText then
+ // When we cannot resolve NullableOps, recommend the relevant namespace to be added
+ errorR(Error(FSComp.SR.cannotResolveNullableOperators(DecompileOpName opId.idText), relExpr.Range))
+ else
+ errorR(Error(FSComp.SR.tcInvalidRelationInJoin(nm.idText), relExpr.Range))
+ // this is not correct JoinRelation but it is still binary operation
+ // we've already reported error now we can use operands of binary operation as join components
+ let l = wrapInArbErrSequence l "_keySelector1"
+ let r = wrapInArbErrSequence r "_keySelector2"
+ mkJoinExpr l r secondSourceSimplePats, varSpaceWithGroupJoinVars
+ | _ ->
+ errorR(Error(FSComp.SR.tcInvalidRelationInJoin(nm.idText), relExpr.Range))
+ // since the shape of relExpr doesn't match our expectations (JoinRelation)
+ // then we assume that this is l.h.s. of the join relation
+ // so typechecker will treat relExpr as body of outerKeySelector lambda parameter in Join method
+ mkJoinExpr relExpr (arbExpr("_keySelector2", relExpr.Range)) secondSourceSimplePats, varSpaceWithGroupJoinVars
+
+ | None, None when customOperationIsLikeZip nm ->
+ mkZipExpr, varSpaceWithSecondVars
+
+ | _ ->
+ assert false
+ failwith "unreachable"
+
+
+ // Case from C# spec: A query expression with a join clause with an into followed by something other than a select clause
+ // Case from C# spec: A query expression with a join clause without an into followed by something other than a select clause
+ let valsInner, _env = varSpaceInner.Force mOpCore
+ let varSpaceExpr = mkExprForVarSpace mOpCore valsInner
+ let varSpacePat = mkPatForVarSpace mOpCore valsInner
+ let joinExpr = mkOverallExprGivenVarSpaceExpr varSpaceExpr
+ Some (trans CompExprTranslationPass.Initial q varSpaceInner (SynExpr.ForEach (DebugPointAtFor.No, SeqExprOnly false, false, varSpacePat, joinExpr, innerComp, mOpCore)) translatedCtxt)
+
+
+ | SynExpr.ForEach (spForLoop, SeqExprOnly _seqExprOnly, isFromSource, pat, sourceExpr, innerComp, _) ->
+ let wrappedSourceExpr = mkSourceExprConditional isFromSource sourceExpr
+ let mFor = match spForLoop with DebugPointAtFor.Yes m -> m | _ -> pat.Range
+ let mPat = pat.Range
+ let spBind = match spForLoop with DebugPointAtFor.Yes m -> DebugPointAtBinding m | DebugPointAtFor.No -> NoDebugPointAtStickyBinding
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mFor ad "For" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("For"), mFor))
+
+ // 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()) env tpenv (pat, None)
+ vspecs, envinner)
+
+ Some (trans CompExprTranslationPass.Initial q varSpace innerComp
+ (fun holeFill ->
+ translatedCtxt (mkSynCall "For" mFor [wrappedSourceExpr; SynExpr.MatchLambda (false, sourceExpr.Range, [Clause(pat, None, holeFill, mPat, DebugPointForTarget.Yes)], spBind, mFor) ])) )
+
+ | SynExpr.For (spBind, id, start, dir, finish, innerComp, m) ->
+ let mFor = match spBind with DebugPointAtFor.Yes m -> m | _ -> m
+ if isQuery then errorR(Error(FSComp.SR.tcNoIntegerForLoopInQuery(), mFor))
+ Some (trans CompExprTranslationPass.Initial q varSpace (elimFastIntegerForLoop (spBind, id, start, dir, finish, innerComp, m)) translatedCtxt )
+
+ | SynExpr.While (spWhile, guardExpr, innerComp, _) ->
+ let mGuard = guardExpr.Range
+ let mWhile = match spWhile with DebugPointAtWhile.Yes m -> m | _ -> mGuard
+ if isQuery then error(Error(FSComp.SR.tcNoWhileInQuery(), mWhile))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mWhile ad "While" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("While"), mWhile))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mWhile ad "Delay" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), mWhile))
+ Some(trans CompExprTranslationPass.Initial q varSpace innerComp (fun holeFill -> translatedCtxt (mkSynCall "While" mWhile [mkSynDelay2 guardExpr; mkSynCall "Delay" mWhile [mkSynDelay innerComp.Range holeFill]])) )
+
+ | SynExpr.TryFinally (innerComp, unwindExpr, mTryToLast, spTry, _spFinally) ->
+
+ let mTry = match spTry with DebugPointAtTry.Yes m -> m | _ -> mTryToLast
+ if isQuery then error(Error(FSComp.SR.tcNoTryFinallyInQuery(), mTry))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mTry ad "TryFinally" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("TryFinally"), mTry))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mTry ad "Delay" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), mTry))
+ Some (translatedCtxt (mkSynCall "TryFinally" mTry [mkSynCall "Delay" mTry [mkSynDelay innerComp.Range (transNoQueryOps innerComp)]; mkSynDelay2 unwindExpr]))
+
+ | SynExpr.Paren (_, _, _, m) ->
+ error(Error(FSComp.SR.tcConstructIsAmbiguousInComputationExpression(), m))
+
+ // In some cases the node produced by `mkSynCall "Zero" m []` may be discarded in the case
+ // of implicit yields - for example "list { 1; 2 }" when each expression checks as an implicit yield.
+ // If it is not discarded, the syntax node will later be checked and the existence/non-existence of the Zero method
+ // will be checked/reported appropriately (though the error message won't mention computation expressions
+ // like our other error messages for missing methods).
+ | SynExpr.ImplicitZero m ->
+ if (not enableImplicitYield) &&
+ isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Zero" builderTy) then error(Error(FSComp.SR.tcRequireBuilderMethod("Zero"), m))
+ Some (translatedCtxt (mkSynCall "Zero" m []))
+
+ | OptionalSequential (JoinOrGroupJoinOrZipClause (_, _, _, _, _, mClause), _)
+ when firstTry = CompExprTranslationPass.Initial ->
+
+ // 'join' clauses preceded by 'let' and other constructs get processed by repackaging with a 'for' loop.
+ let patvs, _env = varSpace.Force comp.Range
+ let varSpaceExpr = mkExprForVarSpace mClause patvs
+ let varSpacePat = mkPatForVarSpace mClause patvs
+
+ let dataCompPrior =
+ translatedCtxt (transNoQueryOps (SynExpr.YieldOrReturn ((true, false), varSpaceExpr, mClause)))
+
+ // Rebind using for ...
+ let rebind =
+ SynExpr.ForEach (DebugPointAtFor.No, SeqExprOnly false, false, varSpacePat, dataCompPrior, comp, comp.Range)
+
+ // Retry with the 'for' loop packaging. Set firstTry=false just in case 'join' processing fails
+ tryTrans CompExprTranslationPass.Subsequent q varSpace rebind id
+
+
+ | OptionalSequential (CustomOperationClause (nm, _, opExpr, mClause, _), _) ->
+
+ if q = CustomOperationsMode.Denied then error(Error(FSComp.SR.tcCustomOperationMayNotBeUsedHere(), opExpr.Range))
+
+ let patvs, _env = varSpace.Force comp.Range
+ let varSpaceExpr = mkExprForVarSpace mClause patvs
+
+ let dataCompPriorToOp =
+ let isYield = not (customOperationMaintainsVarSpaceUsingBind nm)
+ translatedCtxt (transNoQueryOps (SynExpr.YieldOrReturn ((isYield, false), varSpaceExpr, mClause)))
+
+
+ // Now run the consumeCustomOpClauses
+ Some (consumeCustomOpClauses q varSpace dataCompPriorToOp comp false mClause)
+
+ | SynExpr.Sequential (sp, true, innerComp1, innerComp2, m) ->
+
+ // Check for 'where x > y' and other mis-applications of infix operators. If detected, give a good error message, and just ignore innerComp1
+ if isQuery && checkForBinaryApp innerComp1 then
+ Some (trans CompExprTranslationPass.Initial q varSpace innerComp2 translatedCtxt)
+
+ else
+
+ if isQuery && not(innerComp1.IsArbExprAndThusAlreadyReportedError) then
+ match innerComp1 with
+ | SynExpr.JoinIn _ -> () // an error will be reported later when we process innerComp1 as a sequential
+ | _ -> errorR(Error(FSComp.SR.tcUnrecognizedQueryOperator(), innerComp1.RangeOfFirstPortion))
+
+ match tryTrans CompExprTranslationPass.Initial CustomOperationsMode.Denied varSpace innerComp1 id with
+ | Some c ->
+ // "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
+ let m1 = rangeForCombine innerComp1
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Combine" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Combine"), m))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Delay" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), m))
+ Some (translatedCtxt (mkSynCall "Combine" m1 [c; mkSynCall "Delay" m1 [mkSynDelay innerComp2.Range (transNoQueryOps innerComp2)]]))
+ | None ->
+ // "do! expr; cexpr" is treated as { let! () = expr in cexpr }
+ match innerComp1 with
+ | SynExpr.DoBang (rhsExpr, m) ->
+ let sp =
+ match sp with
+ | DebugPointAtSequential.ExprOnly -> DebugPointAtBinding m
+ | DebugPointAtSequential.StmtOnly -> NoDebugPointAtDoBinding
+ | DebugPointAtSequential.Both -> DebugPointAtBinding m
+ Some(trans CompExprTranslationPass.Initial q varSpace (SynExpr.LetOrUseBang (sp, false, true, SynPat.Const(SynConst.Unit, rhsExpr.Range), rhsExpr, [], innerComp2, m)) translatedCtxt)
+
+ // "expr; cexpr" is treated as sequential execution
+ | _ ->
+ Some (trans CompExprTranslationPass.Initial q varSpace innerComp2 (fun holeFill ->
+ let fillExpr =
+ if enableImplicitYield then
+ // When implicit yields are enabled, then if the 'innerComp1' checks as type
+ // 'unit' we interpret the expression as a sequential, and when it doesn't
+ // have type 'unit' we interpret it as a 'Yield + Combine'.
+ let combineExpr =
+ let m1 = rangeForCombine innerComp1
+ let implicitYieldExpr = mkSynCall "Yield" comp.Range [innerComp1]
+ mkSynCall "Combine" m1 [implicitYieldExpr; mkSynCall "Delay" m1 [mkSynDelay holeFill.Range holeFill]]
+ SynExpr.SequentialOrImplicitYield(sp, innerComp1, holeFill, combineExpr, m)
+ else
+ SynExpr.Sequential(sp, true, innerComp1, holeFill, m)
+ translatedCtxt fillExpr))
+
+ | SynExpr.IfThenElse (guardExpr, thenComp, elseCompOpt, spIfToThen, isRecovery, mIfToThen, mIfToEndOfElseBranch) ->
+ match elseCompOpt with
+ | Some elseComp ->
+ if isQuery then error(Error(FSComp.SR.tcIfThenElseMayNotBeUsedWithinQueries(), mIfToThen))
+ Some (translatedCtxt (SynExpr.IfThenElse (guardExpr, transNoQueryOps thenComp, Some(transNoQueryOps elseComp), spIfToThen, isRecovery, mIfToThen, mIfToEndOfElseBranch)))
+ | None ->
+ let elseComp =
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mIfToThen ad "Zero" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Zero"), mIfToThen))
+ mkSynCall "Zero" mIfToThen []
+ Some (trans CompExprTranslationPass.Initial q varSpace thenComp (fun holeFill -> translatedCtxt (SynExpr.IfThenElse (guardExpr, holeFill, Some elseComp, spIfToThen, isRecovery, mIfToThen, mIfToEndOfElseBranch))))
+
+ // 'let binds in expr'
+ | SynExpr.LetOrUse (isRec, false, binds, innerComp, m) ->
+
+ // For 'query' check immediately
+ if isQuery then
+ match (List.map (BindingNormalization.NormalizeBinding ValOrMemberBinding cenv env) binds) with
+ | [NormalizedBinding(_, NormalBinding, (*inline*)false, (*mutable*)false, _, _, _, _, _, _, _, _)] when not isRec ->
+ ()
+ | normalizedBindings ->
+ let failAt m = error(Error(FSComp.SR.tcNonSimpleLetBindingInQuery(), m))
+ match normalizedBindings with
+ | NormalizedBinding(_, _, _, _, _, _, _, _, _, _, mBinding, _) :: _ -> failAt mBinding
+ | _ -> failAt m
+
+ // Add the variables to the query variable space, on demand
+ let varSpace =
+ addVarsToVarSpace varSpace (fun mQueryOp env ->
+ // Normalize the bindings before detecting the bound variables
+ match (List.map (BindingNormalization.NormalizeBinding ValOrMemberBinding cenv env) binds) with
+ | [NormalizedBinding(_vis, NormalBinding, false, false, _, _, _, _, pat, _, _, _)] ->
+ // successful case
+ use _holder = TemporarilySuspendReportingTypecheckResultsToSink cenv.tcSink
+ let _, _, vspecs, envinner, _ = TcMatchPattern cenv (NewInferenceType()) env tpenv (pat, None)
+ vspecs, envinner
+ | _ ->
+ // error case
+ error(Error(FSComp.SR.tcCustomOperationMayNotBeUsedInConjunctionWithNonSimpleLetBindings(), mQueryOp)))
+
+ Some (trans CompExprTranslationPass.Initial q varSpace innerComp (fun holeFill -> translatedCtxt (SynExpr.LetOrUse (isRec, false, binds, holeFill, m))))
+
+ // 'use x = expr in expr'
+ | SynExpr.LetOrUse (_, true, [Binding (_, NormalBinding, _, _, _, _, _, pat, _, rhsExpr, _, spBind)], innerComp, _) ->
+ let bindRange = match spBind with DebugPointAtBinding m -> m | _ -> rhsExpr.Range
+ if isQuery then error(Error(FSComp.SR.tcUseMayNotBeUsedInQueries(), bindRange))
+ let innerCompRange = innerComp.Range
+ let consumeExpr = SynExpr.MatchLambda(false, innerCompRange, [Clause(pat, None, transNoQueryOps innerComp, innerCompRange, DebugPointForTarget.Yes)], spBind, innerCompRange)
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad "Using" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Using"), bindRange))
+ Some (translatedCtxt (mkSynCall "Using" bindRange [rhsExpr; consumeExpr ]))
+
+ // '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 (spBind, false, isFromSource, pat, rhsExpr, [], innerComp, _) ->
+
+ let bindRange = match spBind with DebugPointAtBinding m -> m | _ -> rhsExpr.Range
+ if isQuery then error(Error(FSComp.SR.tcBindMayNotBeUsedInQueries(), bindRange))
+
+ // 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()) env tpenv (pat, None)
+ vspecs, envinner)
+
+ let rhsExpr = mkSourceExprConditional isFromSource rhsExpr
+ Some (transBind q varSpace bindRange "Bind" [rhsExpr] pat spBind 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))))
+ | SynExpr.LetOrUseBang (spBind, true, isFromSource, (SynPat.Named (SynPat.Wild _, id, false, _, _) as pat) , rhsExpr, [], innerComp, _)
+ | SynExpr.LetOrUseBang (spBind, true, isFromSource, (SynPat.LongIdent (longDotId=LongIdentWithDots([id], _)) as pat), rhsExpr, [], innerComp, _) ->
+
+ let bindRange = match spBind with DebugPointAtBinding m -> m | _ -> rhsExpr.Range
+ if isQuery then error(Error(FSComp.SR.tcBindMayNotBeUsedInQueries(), bindRange))
+
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad "Using" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Using"), bindRange))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad "Bind" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Bind"), bindRange))
+
+ let consumeExpr = SynExpr.MatchLambda(false, bindRange, [Clause(pat, None, transNoQueryOps innerComp, innerComp.Range, DebugPointForTarget.Yes)], spBind, bindRange)
+ let consumeExpr = mkSynCall "Using" bindRange [SynExpr.Ident(id); consumeExpr ]
+ let consumeExpr = SynExpr.MatchLambda(false, bindRange, [Clause(pat, None, consumeExpr, id.idRange, DebugPointForTarget.Yes)], spBind, bindRange)
+ let rhsExpr = mkSourceExprConditional isFromSource rhsExpr
+ // TODO: consider allowing translation to BindReturn
+ Some(translatedCtxt (mkSynCall "Bind" bindRange [rhsExpr; consumeExpr]))
+
+ // 'use! pat = e1 ... in e2' where 'pat' is not a simple name --> error
+ | SynExpr.LetOrUseBang (_spBind, true, _isFromSource, pat, _rhsExpr, andBangs, _innerComp, _) ->
+ if isNil andBangs then
+ error(Error(FSComp.SR.tcInvalidUseBangBinding(), pat.Range))
+ else
+ error(Error(FSComp.SR.tcInvalidUseBangBindingNoAndBangs(), comp.Range))
+
+ // '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(letSpBind, false, isFromSource, letPat, letRhsExpr, andBangBindings, innerComp, letBindRange) ->
+ if cenv.g.langVersion.SupportsFeature LanguageFeature.AndBang then
+ if isQuery then error(Error(FSComp.SR.tcBindMayNotBeUsedInQueries(), letBindRange))
+ let bindRange = match letSpBind with DebugPointAtBinding m -> m | _ -> letRhsExpr.Range
+ let sources = (letRhsExpr :: [for (_, _, _, _, andExpr, _) in andBangBindings -> andExpr ]) |> List.map (mkSourceExprConditional isFromSource)
+ let pats = letPat :: [for (_, _, _, 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 env bindRange ad bindReturnNName builderTy))
+ if hasBindReturnN && Option.isSome (convertSimpleReturnToExpr varSpace innerComp) 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()) env tpenv (consumePat, None)
+ vspecs, envinner)
+
+ Some (transBind q varSpace bindRange bindNName sources consumePat letSpBind innerComp translatedCtxt)
+
+ else
+
+ // Check if this is a Bind2 etc.
+ let hasBindN = not (isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad bindNName builderTy))
+ 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()) env tpenv (consumePat, None)
+ vspecs, envinner)
+
+ Some (transBind q varSpace bindRange bindNName sources consumePat letSpBind innerComp translatedCtxt)
+ else
+
+ // 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 env bindRange ad mergeSourcesName builderTy) then
+ (n-1)
+ else
+ loop (n+1)
+ loop 2
+
+ if maxMergeSources = 1 then error(Error(FSComp.SR.tcRequireMergeSourcesOrBindN(bindNName), bindRange))
+
+ let rec mergeSources (sourcesAndPats: (SynExpr * SynPat) list) =
+ let numSourcesAndPats = sourcesAndPats.Length
+ assert (numSourcesAndPats <> 0)
+ if numSourcesAndPats = 1 then
+ sourcesAndPats.[0]
+
+ elif numSourcesAndPats <= maxMergeSources then
+
+ // Call MergeSources2(e1, e2), MergeSources3(e1, e2, e3) etc
+ let mergeSourcesName = mkMergeSourcesName numSourcesAndPats
+
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad mergeSourcesName builderTy) then
+ error(Error(FSComp.SR.tcRequireMergeSourcesOrBindN(bindNName), bindRange))
+
+ let source = mkSynCall mergeSourcesName sourcesRange (List.map fst sourcesAndPats)
+ let pat = SynPat.Tuple(false, List.map snd sourcesAndPats, letPat.Range)
+ source, pat
+
+ else
+
+ // Call MergeSourcesMax(e1, e2, e3, e4, (...))
+ let nowSourcesAndPats, laterSourcesAndPats = List.splitAt (maxMergeSources - 1) sourcesAndPats
+ let mergeSourcesName = mkMergeSourcesName maxMergeSources
+
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad mergeSourcesName builderTy) then
+ error(Error(FSComp.SR.tcRequireMergeSourcesOrBindN(bindNName), bindRange))
+
+ let laterSource, laterPat = mergeSources laterSourcesAndPats
+ let source = mkSynCall mergeSourcesName sourcesRange (List.map fst nowSourcesAndPats @ [laterSource])
+ let pat = SynPat.Tuple(false, List.map snd nowSourcesAndPats @ [laterPat], letPat.Range)
+ source, pat
+
+ 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
+ let _, _, vspecs, envinner, _ = TcMatchPattern cenv (NewInferenceType()) env tpenv (consumePat, None)
+ vspecs, envinner)
+
+ // Build the 'Bind' call
+ Some (transBind q varSpace bindRange "Bind" [mergedSources] consumePat letSpBind innerComp translatedCtxt)
+ else
+ error(Error(FSComp.SR.tcAndBangNotSupported(), comp.Range))
+
+ | SynExpr.Match (spMatch, expr, clauses, m) ->
+ let mMatch = match spMatch with DebugPointAtBinding mMatch -> mMatch | _ -> m
+ if isQuery then error(Error(FSComp.SR.tcMatchMayNotBeUsedWithQuery(), mMatch))
+ let clauses = clauses |> List.map (fun (Clause(pat, cond, innerComp, patm, sp)) -> Clause(pat, cond, transNoQueryOps innerComp, patm, sp))
+ Some(translatedCtxt (SynExpr.Match (spMatch, expr, clauses, m)))
+
+ // 'match! expr with pats ...' --> build.Bind(e1, (function pats ...))
+ | SynExpr.MatchBang (spMatch, expr, clauses, m) ->
+ let matchExpr = mkSourceExpr expr
+ let mMatch = match spMatch with DebugPointAtBinding mMatch -> mMatch | _ -> m
+ if isQuery then error(Error(FSComp.SR.tcMatchMayNotBeUsedWithQuery(), mMatch))
+
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mMatch ad "Bind" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Bind"), mMatch))
+
+ let clauses = clauses |> List.map (fun (Clause(pat, cond, innerComp, patm, sp)) -> Clause(pat, cond, transNoQueryOps innerComp, patm, sp))
+ let consumeExpr = SynExpr.MatchLambda (false, mMatch, clauses, spMatch, mMatch)
+
+ // TODO: consider allowing translation to BindReturn
+ Some(translatedCtxt (mkSynCall "Bind" mMatch [matchExpr; consumeExpr]))
+
+ | SynExpr.TryWith (innerComp, _mTryToWith, clauses, _mWithToLast, mTryToLast, spTry, _spWith) ->
+ let mTry = match spTry with DebugPointAtTry.Yes m -> m | _ -> mTryToLast
+
+ if isQuery then error(Error(FSComp.SR.tcTryWithMayNotBeUsedInQueries(), mTry))
+ let clauses = clauses |> List.map (fun (Clause(pat, cond, clauseComp, patm, sp)) -> Clause(pat, cond, transNoQueryOps clauseComp, patm, sp))
+ let consumeExpr = SynExpr.MatchLambda(true, mTryToLast, clauses, NoDebugPointAtStickyBinding, mTryToLast)
+
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mTry ad "TryWith" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("TryWith"), mTry))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mTry ad "Delay" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("Delay"), mTry))
+
+ Some(translatedCtxt (mkSynCall "TryWith" mTry [mkSynCall "Delay" mTry [mkSynDelay2 (transNoQueryOps innerComp)]; consumeExpr]))
+
+ | SynExpr.YieldOrReturnFrom ((isYield, _), yieldExpr, m) ->
+ let yieldExpr = mkSourceExpr yieldExpr
+ if isYield then
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "YieldFrom" builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod("YieldFrom"), m))
+ Some (translatedCtxt (mkSynCall "YieldFrom" m [yieldExpr]))
+
+ else
+ if isQuery then error(Error(FSComp.SR.tcReturnMayNotBeUsedInQueries(), m))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "ReturnFrom" builderTy) then
+ errorR(Error(FSComp.SR.tcRequireBuilderMethod("ReturnFrom"), m))
+ Some (translatedCtxt yieldExpr)
+ else
+ Some (translatedCtxt (mkSynCall "ReturnFrom" m [yieldExpr]))
+
+ | SynExpr.YieldOrReturn ((isYield, _), yieldExpr, m) ->
+ let methName = (if isYield then "Yield" else "Return")
+ if isQuery && not isYield then error(Error(FSComp.SR.tcReturnMayNotBeUsedInQueries(), m))
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad methName builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod(methName), m))
+ Some(translatedCtxt (mkSynCall methName m [yieldExpr]))
+
+ | _ -> None
+
+ and consumeCustomOpClauses q (varSpace: LazyWithContext<_, _>) dataCompPrior compClausesExpr lastUsesBind mClause =
+
+ // Substitute 'yield ' into the context
+
+ let patvs, _env = varSpace.Force comp.Range
+ let varSpaceSimplePat = mkSimplePatForVarSpace mClause patvs
+ let varSpacePat = mkPatForVarSpace mClause patvs
+
+ match compClausesExpr with
+
+ // Detect one custom operation... This clause will always match at least once...
+ | OptionalSequential
+ (CustomOperationClause
+ (nm, opDatas,
+ opExpr, mClause, optionalIntoPat),
+ optionalCont) ->
+
+ let (opName, _, _, _, _, _, _, _, methInfo) = opDatas.[0]
+ let isLikeZip = customOperationIsLikeZip nm
+ let isLikeJoin = customOperationIsLikeJoin nm
+ let isLikeGroupJoin = customOperationIsLikeZip nm
+
+ // Record the resolution of the custom operation for posterity
+ let item = Item.CustomOperation (opName, (fun () -> customOpUsageText nm), Some methInfo)
+
+ // FUTURE: consider whether we can do better than emptyTyparInst here, in order to display instantiations
+ // of type variables in the quick info provided in the IDE.
+ CallNameResolutionSink cenv.tcSink (nm.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.eAccessRights)
+
+ if isLikeZip || isLikeJoin || isLikeGroupJoin then
+ errorR(Error(FSComp.SR.tcBinaryOperatorRequiresBody(nm.idText, Option.get (customOpUsageText nm)), nm.idRange))
+ match optionalCont with
+ | None ->
+ // we are about to drop the 'opExpr' AST on the floor. we've already reported an error. attempt to get name resolutions before dropping it
+ RecordNameAndTypeResolutions_IdeallyWithoutHavingOtherEffects cenv env tpenv opExpr
+ dataCompPrior
+ | Some contExpr -> consumeCustomOpClauses q varSpace dataCompPrior contExpr lastUsesBind mClause
+ else
+
+ let maintainsVarSpace = customOperationMaintainsVarSpace nm
+ let maintainsVarSpaceUsingBind = customOperationMaintainsVarSpaceUsingBind nm
+
+ let expectedArgCount = tryExpectedArgCountForCustomOperator nm
+
+ let dataCompAfterOp =
+ match opExpr with
+ | StripApps(SingleIdent nm, args) ->
+ let argCountsMatch =
+ match expectedArgCount with
+ | Some n -> n = args.Length
+ | None -> cenv.g.langVersion.SupportsFeature LanguageFeature.OverloadsForCustomOperations
+ if argCountsMatch then
+ // Check for the [] attribute on each argument position
+ let args = args |> List.mapi (fun i arg ->
+ if isCustomOperationProjectionParameter (i+1) nm then
+ SynExpr.Lambda (false, false, varSpaceSimplePat, arg, None, arg.Range.MakeSynthetic())
+ else arg)
+ mkSynCall methInfo.DisplayName mClause (dataCompPrior :: args)
+ else
+ let expectedArgCount = defaultArg expectedArgCount 0
+ errorR(Error(FSComp.SR.tcCustomOperationHasIncorrectArgCount(nm.idText, expectedArgCount, args.Length), nm.idRange))
+ mkSynCall methInfo.DisplayName mClause ([ dataCompPrior ] @ List.init expectedArgCount (fun i -> arbExpr("_arg" + string i, mClause)))
+ | _ -> failwith "unreachable"
+
+ match optionalCont with
+ | None ->
+ match optionalIntoPat with
+ | Some intoPat -> errorR(Error(FSComp.SR.tcIntoNeedsRestOfQuery(), intoPat.Range))
+ | None -> ()
+ dataCompAfterOp
+
+ | Some contExpr ->
+
+ // select a.Name into name; ...
+ // distinct into d; ...
+ //
+ // Rebind the into pattern and process the rest of the clauses
+ match optionalIntoPat with
+ | Some intoPat ->
+ if not (customOperationAllowsInto nm) then
+ error(Error(FSComp.SR.tcOperatorDoesntAcceptInto(nm.idText), intoPat.Range))
+
+ // Rebind using either for ... or let!....
+ let rebind =
+ if maintainsVarSpaceUsingBind then
+ SynExpr.LetOrUseBang (NoDebugPointAtLetBinding, false, false, intoPat, dataCompAfterOp, [], contExpr, intoPat.Range)
+ else
+ SynExpr.ForEach (DebugPointAtFor.No, SeqExprOnly false, false, intoPat, dataCompAfterOp, contExpr, intoPat.Range)
+
+ trans CompExprTranslationPass.Initial q emptyVarSpace rebind id
+
+ // select a.Name; ...
+ // distinct; ...
+ //
+ // Process the rest of the clauses
+ | None ->
+ if maintainsVarSpace || maintainsVarSpaceUsingBind then
+ consumeCustomOpClauses q varSpace dataCompAfterOp contExpr maintainsVarSpaceUsingBind mClause
+ else
+ consumeCustomOpClauses q emptyVarSpace dataCompAfterOp contExpr false mClause
+
+ // No more custom operator clauses in compClausesExpr, but there may be clauses like join, yield etc.
+ // Bind/iterate the dataCompPrior and use compClausesExpr as the body.
+ | _ ->
+ // Rebind using either for ... or let!....
+ let rebind =
+ if lastUsesBind then
+ SynExpr.LetOrUseBang (NoDebugPointAtLetBinding, false, false, varSpacePat, dataCompPrior, [], compClausesExpr, compClausesExpr.Range)
+ else
+ SynExpr.ForEach (DebugPointAtFor.No, SeqExprOnly false, false, varSpacePat, dataCompPrior, compClausesExpr, compClausesExpr.Range)
+
+ trans CompExprTranslationPass.Initial q varSpace rebind id
+ and transNoQueryOps comp =
+ trans CompExprTranslationPass.Initial CustomOperationsMode.Denied emptyVarSpace comp id
+
+ and trans firstTry q varSpace comp translatedCtxt =
+ match tryTrans firstTry q varSpace comp translatedCtxt with
+ | Some e -> e
+ | None ->
+ // This only occurs in final position in a sequence
+ match comp with
+ // "do! expr;" in final position is treated as { let! () = expr in return () } when Return is provided or as { let! () = expr in zero } otherwise
+ | SynExpr.DoBang (rhsExpr, m) ->
+ let mUnit = rhsExpr.Range
+ let rhsExpr = mkSourceExpr rhsExpr
+ if isQuery then error(Error(FSComp.SR.tcBindMayNotBeUsedInQueries(), m))
+ let bodyExpr =
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Return" builderTy) then
+ SynExpr.ImplicitZero m
+ else
+ SynExpr.YieldOrReturn((false, true), SynExpr.Const(SynConst.Unit, m), m)
+ trans CompExprTranslationPass.Initial q varSpace (SynExpr.LetOrUseBang (NoDebugPointAtDoBinding, false, false, SynPat.Const(SynConst.Unit, mUnit), rhsExpr, [], bodyExpr, m)) translatedCtxt
+
+ // "expr;" in final position is treated as { expr; zero }
+ // Suppress the sequence point on the "zero"
+ | _ ->
+ // Check for 'where x > y' and other mis-applications of infix operators. If detected, give a good error message, and just ignore comp
+ if isQuery && checkForBinaryApp comp then
+ trans CompExprTranslationPass.Initial q varSpace (SynExpr.ImplicitZero comp.Range) translatedCtxt
+ else
+ if isQuery && not comp.IsArbExprAndThusAlreadyReportedError then
+ match comp with
+ | SynExpr.JoinIn _ -> () // an error will be reported later when we process innerComp1 as a sequential
+ | _ -> errorR(Error(FSComp.SR.tcUnrecognizedQueryOperator(), comp.RangeOfFirstPortion))
+ trans CompExprTranslationPass.Initial q varSpace (SynExpr.ImplicitZero comp.Range) (fun holeFill ->
+ let fillExpr =
+ if enableImplicitYield then
+ let implicitYieldExpr = mkSynCall "Yield" comp.Range [comp]
+ SynExpr.SequentialOrImplicitYield(DebugPointAtSequential.ExprOnly, comp, holeFill, implicitYieldExpr, comp.Range)
+ else
+ SynExpr.Sequential(DebugPointAtSequential.ExprOnly, true, comp, holeFill, comp.Range)
+ translatedCtxt fillExpr)
+
+ and transBind q varSpace bindRange bindName bindArgs (consumePat: SynPat) spBind (innerComp: SynExpr) translatedCtxt =
+
+ let innerRange = innerComp.Range
+
+ let innerCompReturn =
+ if cenv.g.langVersion.SupportsFeature LanguageFeature.AndBang then
+ convertSimpleReturnToExpr varSpace innerComp
+ else None
+
+ match innerCompReturn with
+ | Some (innerExpr, customOpInfo) when
+ (let bindName = bindName + "Return"
+ not (isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad bindName builderTy))) ->
+
+ let bindName = bindName + "Return"
+
+ // Build the `BindReturn` call
+ let dataCompPriorToOp =
+ let consumeExpr = SynExpr.MatchLambda(false, consumePat.Range, [Clause(consumePat, None, innerExpr, innerRange, DebugPointForTarget.Yes)], spBind, innerRange)
+ translatedCtxt (mkSynCall bindName bindRange (bindArgs @ [consumeExpr]))
+
+ match customOpInfo with
+ | None -> dataCompPriorToOp
+ | Some (innerComp, mClause) ->
+ // If the `BindReturn` was forced by a custom operation, continue to process the clauses of the CustomOp
+ consumeCustomOpClauses q varSpace dataCompPriorToOp innerComp false mClause
+
+ | _ ->
+
+ if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env bindRange ad bindName builderTy) then
+ error(Error(FSComp.SR.tcRequireBuilderMethod(bindName), bindRange))
+
+ // Build the `Bind` call
+ trans CompExprTranslationPass.Initial q varSpace innerComp (fun holeFill ->
+ let consumeExpr = SynExpr.MatchLambda(false, consumePat.Range, [Clause(consumePat, None, holeFill, innerRange, DebugPointForTarget.Yes)], spBind, innerRange)
+ translatedCtxt (mkSynCall bindName bindRange (bindArgs @ [consumeExpr])))
+
+ and convertSimpleReturnToExpr varSpace innerComp =
+ match innerComp with
+ | SynExpr.YieldOrReturn ((false, _), returnExpr, _) -> Some (returnExpr, None)
+ | SynExpr.Match (spMatch, expr, clauses, m) ->
+ let clauses =
+ clauses |> List.map (fun (Clause(pat, cond, innerComp2, patm, sp)) ->
+ match convertSimpleReturnToExpr varSpace innerComp2 with
+ | None -> None // failure
+ | Some (_, Some _) -> None // custom op on branch = failure
+ | Some (innerExpr2, None) -> Some (Clause(pat, cond, innerExpr2, patm, sp)))
+ if clauses |> List.forall Option.isSome then
+ Some (SynExpr.Match (spMatch, expr, (clauses |> List.map Option.get), m), None)
+ else
+ None
+
+ | SynExpr.IfThenElse (guardExpr, thenComp, elseCompOpt, spIfToThen, isRecovery, mIfToThen, mIfToEndOfElseBranch) ->
+ match convertSimpleReturnToExpr varSpace thenComp with
+ | None -> None
+ | Some (_, Some _) -> None
+ | Some (thenExpr, None) ->
+ let elseExprOptOpt =
+ match elseCompOpt with
+ | None -> Some None
+ | Some elseComp ->
+ match convertSimpleReturnToExpr varSpace elseComp with
+ | None -> None // failure
+ | Some (_, Some _) -> None // custom op on branch = failure
+ | Some (elseExpr, None) -> Some (Some elseExpr)
+ match elseExprOptOpt with
+ | None -> None
+ | Some elseExprOpt -> Some (SynExpr.IfThenElse (guardExpr, thenExpr, elseExprOpt, spIfToThen, isRecovery, mIfToThen, mIfToEndOfElseBranch), None)
+
+ | SynExpr.LetOrUse (isRec, false, binds, innerComp, m) ->
+ match convertSimpleReturnToExpr varSpace innerComp with
+ | None -> None
+ | Some (_, Some _) -> None
+ | Some (innerExpr, None) -> Some (SynExpr.LetOrUse (isRec, false, binds, innerExpr, m), None)
+
+ | OptionalSequential (CustomOperationClause (nm, _, _, mClause, _), _) when customOperationMaintainsVarSpaceUsingBind nm ->
+
+ let patvs, _env = varSpace.Force comp.Range
+ let varSpaceExpr = mkExprForVarSpace mClause patvs
+
+ Some (varSpaceExpr, Some (innerComp, mClause))
+
+ | SynExpr.Sequential (sp, true, innerComp1, innerComp2, m) ->
+
+ // Check the first part isn't a computation expression construct
+ if isSimpleExpr innerComp1 then
+ // Check the second part is a simple return
+ match convertSimpleReturnToExpr varSpace innerComp2 with
+ | None -> None
+ | Some (innerExpr2, optionalCont) -> Some (SynExpr.Sequential (sp, true, innerComp1, innerExpr2, m), optionalCont)
+ else
+ None
+
+ | _ -> None
+
+ /// Check is an expression has no computation expression constructs
+ and isSimpleExpr comp =
+
+ match comp with
+ | ForEachThenJoinOrGroupJoinOrZipClause _ -> false
+ | SynExpr.ForEach _ -> false
+ | SynExpr.For _ -> false
+ | SynExpr.While _ -> false
+ | SynExpr.TryFinally _ -> false
+ | SynExpr.ImplicitZero _ -> false
+ | OptionalSequential (JoinOrGroupJoinOrZipClause _, _) -> false
+ | OptionalSequential (CustomOperationClause _, _) -> false
+ | SynExpr.Sequential (_, _, innerComp1, innerComp2, _) -> isSimpleExpr innerComp1 && isSimpleExpr innerComp2
+ | SynExpr.IfThenElse (_, thenComp, elseCompOpt, _, _, _, _) ->
+ isSimpleExpr thenComp && (match elseCompOpt with None -> true | Some c -> isSimpleExpr c)
+ | SynExpr.LetOrUse (_, _, _, innerComp, _) -> isSimpleExpr innerComp
+ | SynExpr.LetOrUseBang _ -> false
+ | SynExpr.Match (_, _, clauses, _) ->
+ clauses |> List.forall (fun (Clause(_, _, innerComp, _, _)) -> isSimpleExpr innerComp)
+ | SynExpr.MatchBang _ -> false
+ | SynExpr.TryWith (innerComp, _, clauses, _, _, _, _) ->
+ isSimpleExpr innerComp &&
+ clauses |> List.forall (fun (Clause(_, _, clauseComp, _, _)) -> isSimpleExpr clauseComp)
+ | SynExpr.YieldOrReturnFrom _ -> false
+ | SynExpr.YieldOrReturn _ -> false
+ | SynExpr.DoBang _ -> false
+ | _ -> true
+
+ let basicSynExpr =
+ trans CompExprTranslationPass.Initial (hasCustomOperations ()) (LazyWithContext.NotLazy ([], env)) comp (fun holeFill -> holeFill)
+
+ let delayedExpr =
+ match TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mBuilderVal ad "Delay" builderTy with
+ | [] -> basicSynExpr
+ | _ -> mkSynCall "Delay" mBuilderVal [(mkSynDelay2 basicSynExpr)]
+
+ let quotedSynExpr =
+ if isAutoQuote then
+ SynExpr.Quote (mkSynIdGet (mBuilderVal.MakeSynthetic()) (CompileOpName "<@ @>"), (*isRaw=*)false, delayedExpr, (*isFromQueryExpression=*)true, mWhole)
+ else delayedExpr
+
+ let runExpr =
+ match TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env mBuilderVal ad "Run" builderTy with
+ | [] -> quotedSynExpr
+ | _ -> mkSynCall "Run" mBuilderVal [quotedSynExpr]
+
+ let lambdaExpr =
+ let mBuilderVal = mBuilderVal.MakeSynthetic()
+ SynExpr.Lambda (false, false, SynSimplePats.SimplePats ([mkSynSimplePatVar false (mkSynId mBuilderVal builderValName)], mBuilderVal), runExpr, None, mBuilderVal)
+
+ let env =
+ match comp with
+ | SynExpr.YieldOrReturn ((true, _), _, _) -> { env with eContextInfo = ContextInfo.YieldInComputationExpression }
+ | SynExpr.YieldOrReturn ((_, true), _, _) -> { env with eContextInfo = ContextInfo.ReturnInComputationExpression }
+ | _ -> env
+
+ let lambdaExpr, tpenv= TcExpr cenv (builderTy --> overallTy) env tpenv lambdaExpr
+ // beta-var-reduce to bind the builder using a 'let' binding
+ let coreExpr = mkApps cenv.g ((lambdaExpr, tyOfExpr cenv.g lambdaExpr), [], [interpExpr], mBuilderVal)
+
+ coreExpr, tpenv
+
+let mkSeqEmpty (cenv: cenv) env m genTy =
+ // We must discover the 'zero' of the monadic algebra being generated in order to compile failing matches.
+ let genResultTy = NewInferenceType ()
+ UnifyTypes cenv env m genTy (mkSeqTy cenv.g genResultTy)
+ mkCallSeqEmpty cenv.g m genResultTy
+
+let mkSeqCollect (cenv: cenv) env m enumElemTy genTy lam enumExpr =
+ let genResultTy = NewInferenceType ()
+ UnifyTypes cenv env m genTy (mkSeqTy cenv.g genResultTy)
+ let enumExpr = mkCoerceIfNeeded cenv.g (mkSeqTy cenv.g enumElemTy) (tyOfExpr cenv.g enumExpr) enumExpr
+ mkCallSeqCollect cenv.g m enumElemTy genResultTy lam enumExpr
+
+let mkSeqUsing (cenv: cenv) (env: TcEnv) m resourceTy genTy resourceExpr lam =
+ AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace cenv.g.system_IDisposable_ty resourceTy
+ let genResultTy = NewInferenceType ()
+ UnifyTypes cenv env m genTy (mkSeqTy cenv.g genResultTy)
+ mkCallSeqUsing cenv.g m resourceTy genResultTy resourceExpr lam
+
+let mkSeqDelay (cenv: cenv) env m genTy lam =
+ let genResultTy = NewInferenceType ()
+ UnifyTypes cenv env m genTy (mkSeqTy cenv.g genResultTy)
+ mkCallSeqDelay cenv.g m genResultTy (mkUnitDelayLambda cenv.g m lam)
+
+
+let mkSeqAppend (cenv: cenv) env m genTy e1 e2 =
+ let genResultTy = NewInferenceType ()
+ UnifyTypes cenv env m genTy (mkSeqTy cenv.g genResultTy)
+ let e1 = mkCoerceIfNeeded cenv.g (mkSeqTy cenv.g genResultTy) (tyOfExpr cenv.g e1) e1
+ let e2 = mkCoerceIfNeeded cenv.g (mkSeqTy cenv.g genResultTy) (tyOfExpr cenv.g e2) e2
+ mkCallSeqAppend cenv.g m genResultTy e1 e2
+
+let mkSeqFromFunctions (cenv: cenv) env m genTy e1 e2 =
+ let genResultTy = NewInferenceType ()
+ UnifyTypes cenv env m genTy (mkSeqTy cenv.g genResultTy)
+ let e2 = mkCoerceIfNeeded cenv.g (mkSeqTy cenv.g genResultTy) (tyOfExpr cenv.g e2) e2
+ mkCallSeqGenerated cenv.g m genResultTy e1 e2
+
+let mkSeqFinally (cenv: cenv) env m genTy e1 e2 =
+ let genResultTy = NewInferenceType ()
+ UnifyTypes cenv env m genTy (mkSeqTy cenv.g genResultTy)
+ let e1 = mkCoerceIfNeeded cenv.g (mkSeqTy cenv.g genResultTy) (tyOfExpr cenv.g e1) e1
+ mkCallSeqFinally cenv.g m genResultTy e1 e2
+
+let mkSeqExprMatchClauses (pat', vspecs) innerExpr =
+ [TClause(pat', None, TTarget(vspecs, innerExpr, DebugPointForTarget.Yes), pat'.Range) ]
+
+let compileSeqExprMatchClauses (cenv: cenv) env inputExprMark (pat: Pattern, vspecs) innerExpr inputExprOpt bindPatTy genInnerTy =
+ let patMark = pat.Range
+ let tclauses = mkSeqExprMatchClauses (pat, vspecs) innerExpr
+ CompilePatternForMatchClauses cenv env inputExprMark patMark false ThrowIncompleteMatchException inputExprOpt bindPatTy genInnerTy tclauses
+
+/// This case is used for computation expressions which are sequence expressions. Technically the code path is different because it
+/// typechecks rather than doing a shallow syntactic translation, and generates calls into the Seq.* library
+/// and helpers rather than to the builder methods (there is actually no builder for 'seq' in the library).
+/// These are later detected by state machine compilation.
+///
+/// Also "ienumerable extraction" is performed on arguments to "for".
+let TcSequenceExpression (cenv: cenv) env tpenv comp overallTy m =
+
+ let genEnumElemTy = NewInferenceType ()
+ UnifyTypes cenv env m overallTy (mkSeqTy cenv.g genEnumElemTy)
+
+ // Allow subsumption at 'yield' if the element type is nominal prior to the analysis of the body of the sequence expression
+ let flex = not (isTyparTy cenv.g genEnumElemTy)
+
+ // If there are no 'yield' in the computation expression then allow the type-directed rule
+ // interpreting non-unit-typed expressions in statement positions as 'yield'. 'yield!' may be
+ // present in the computation expression.
+ let enableImplicitYield =
+ cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitYield
+ && (YieldFree cenv comp)
+
+ let mkDelayedExpr (coreExpr: Expr) =
+ let m = coreExpr.Range
+ let overallTy = tyOfExpr cenv.g coreExpr
+ mkSeqDelay cenv env m overallTy coreExpr
+
+ let rec tryTcSequenceExprBody env genOuterTy tpenv comp =
+ match comp with
+ | SynExpr.ForEach (_spBind, SeqExprOnly _seqExprOnly, _isFromSource, pat, pseudoEnumExpr, innerComp, m) ->
+ // This expression is not checked with the knowledge it is an IEnumerable, since we permit other enumerable types with GetEnumerator/MoveNext methods, as does C#
+ let pseudoEnumExpr, arb_ty, tpenv = TcExprOfUnknownType cenv env tpenv pseudoEnumExpr
+ let (enumExpr: Expr), enumElemTy = ConvertArbitraryExprToEnumerable cenv arb_ty env pseudoEnumExpr
+ let pat', _, (vspecs: Val list), envinner, tpenv = TcMatchPattern cenv enumElemTy env tpenv (pat, None)
+ let innerExpr, tpenv = tcSequenceExprBody envinner genOuterTy tpenv innerComp
+
+ match pat', vspecs, innerExpr with
+ // peephole optimization: "for x in e1 -> e2" == "e1 |> List.map (fun x -> e2)" *)
+ | (TPat_as (TPat_wild _, PBind (v, _), _),
+ vs,
+ Expr.App (Expr.Val (vf, _, _), _, [genEnumElemTy], [yexpr], _))
+ when vs.Length = 1 && valRefEq cenv.g vf cenv.g.seq_singleton_vref ->
+
+ let enumExprMark = enumExpr.Range
+ let lam = mkLambda enumExprMark v (yexpr, genEnumElemTy)
+
+ // SEQUENCE POINTS: need to build a let here consuming spBind
+ let enumExpr = mkCoerceIfNeeded cenv.g (mkSeqTy cenv.g enumElemTy) (tyOfExpr cenv.g enumExpr) enumExpr
+ Some(mkCallSeqMap cenv.g m enumElemTy genEnumElemTy lam enumExpr, tpenv)
+
+ | _ ->
+ let enumExprMark = enumExpr.Range
+
+ // SEQUENCE POINTS: need to build a let here consuming spBind
+
+ let matchv, matchExpr = compileSeqExprMatchClauses cenv env enumExprMark (pat', vspecs) innerExpr None enumElemTy genOuterTy
+ let lam = mkLambda enumExprMark matchv (matchExpr, tyOfExpr cenv.g matchExpr)
+ Some(mkSeqCollect cenv env m enumElemTy genOuterTy lam enumExpr, tpenv)
+
+ | SynExpr.For (spBind, id, start, dir, finish, innerComp, m) ->
+ Some(tcSequenceExprBody env genOuterTy tpenv (elimFastIntegerForLoop (spBind, id, start, dir, finish, innerComp, m)))
+
+ | SynExpr.While (_spWhile, guardExpr, innerComp, _m) ->
+ let guardExpr, tpenv = TcExpr cenv cenv.g.bool_ty env tpenv guardExpr
+ let innerExpr, tpenv = tcSequenceExprBody env genOuterTy tpenv innerComp
+
+ let guardExprMark = guardExpr.Range
+ let guardExpr = mkUnitDelayLambda cenv.g guardExprMark guardExpr
+ let innerExpr = mkDelayedExpr innerExpr
+ Some(mkSeqFromFunctions cenv env guardExprMark genOuterTy guardExpr innerExpr, tpenv)
+
+ | SynExpr.TryFinally (innerComp, unwindExpr, _mTryToLast, _spTry, _spFinally) ->
+ let innerExpr, tpenv = tcSequenceExprBody env genOuterTy tpenv innerComp
+ let (unwindExpr: Expr), tpenv = TcExpr cenv cenv.g.unit_ty env tpenv unwindExpr
+
+ let unwindExprMark = unwindExpr.Range
+ let unwindExpr = mkUnitDelayLambda cenv.g unwindExprMark unwindExpr
+ let innerExpr = mkDelayedExpr innerExpr
+ let innerExprMark = innerExpr.Range
+
+ Some(mkSeqFinally cenv env innerExprMark genOuterTy innerExpr unwindExpr, tpenv)
+
+ | SynExpr.Paren (_, _, _, m) when not (cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitYield)->
+ error(Error(FSComp.SR.tcConstructIsAmbiguousInSequenceExpression(), m))
+
+ | SynExpr.ImplicitZero m ->
+ Some(mkSeqEmpty cenv env m genOuterTy, tpenv )
+
+ | SynExpr.DoBang (_rhsExpr, m) ->
+ error(Error(FSComp.SR.tcDoBangIllegalInSequenceExpression(), m))
+
+ | SynExpr.Sequential (sp, true, innerComp1, innerComp2, m) ->
+ // "expr; cexpr" is treated as sequential execution
+ // "cexpr; cexpr" is treated as append
+ let res, tpenv = tcSequenceExprBodyAsSequenceOrStatement env genOuterTy tpenv innerComp1
+ match res with
+ | Choice1Of2 innerExpr1 ->
+ let innerExpr2, tpenv = tcSequenceExprBody env genOuterTy tpenv innerComp2
+ let innerExpr2 = mkDelayedExpr innerExpr2
+ Some(mkSeqAppend cenv env innerComp1.Range genOuterTy innerExpr1 innerExpr2, tpenv)
+ | Choice2Of2 stmt1 ->
+ let innerExpr2, tpenv = tcSequenceExprBody env genOuterTy tpenv innerComp2
+ Some(Expr.Sequential(stmt1, innerExpr2, NormalSeq, sp, m), tpenv)
+
+ | SynExpr.IfThenElse (guardExpr, thenComp, elseCompOpt, spIfToThen, _isRecovery, mIfToThen, mIfToEndOfElseBranch) ->
+ let guardExpr', tpenv = TcExpr cenv cenv.g.bool_ty env tpenv guardExpr
+ let thenExpr, tpenv = tcSequenceExprBody env genOuterTy tpenv thenComp
+ let elseComp = (match elseCompOpt with Some c -> c | None -> SynExpr.ImplicitZero mIfToThen)
+ let elseExpr, tpenv = tcSequenceExprBody env genOuterTy tpenv elseComp
+ Some(mkCond spIfToThen DebugPointForTarget.Yes mIfToEndOfElseBranch genOuterTy guardExpr' thenExpr elseExpr, tpenv)
+
+ // 'let x = expr in expr'
+ | SynExpr.LetOrUse (_, false (* not a 'use' binding *), _, _, _) ->
+ TcLinearExprs
+ (fun ty envinner tpenv e -> tcSequenceExprBody envinner ty tpenv e)
+ cenv env overallTy
+ tpenv
+ true
+ comp
+ (fun x -> x) |> Some
+
+ // 'use x = expr in expr'
+ | SynExpr.LetOrUse (_isRec, true, [Binding (_vis, NormalBinding, _, _, _, _, _, pat, _, rhsExpr, _, _spBind)], innerComp, wholeExprMark) ->
+
+ let bindPatTy = NewInferenceType ()
+ let inputExprTy = NewInferenceType ()
+ let pat', _, vspecs, envinner, tpenv = TcMatchPattern cenv bindPatTy env tpenv (pat, None)
+ UnifyTypes cenv env m inputExprTy bindPatTy
+ let (inputExpr: Expr), tpenv = TcExpr cenv inputExprTy env tpenv rhsExpr
+ let innerExpr, tpenv = tcSequenceExprBody envinner genOuterTy tpenv innerComp
+ let inputExprMark = inputExpr.Range
+ let matchv, matchExpr = compileSeqExprMatchClauses cenv env inputExprMark (pat', vspecs) innerExpr (Some inputExpr) bindPatTy genOuterTy
+ let consumeExpr = mkLambda wholeExprMark matchv (matchExpr, genOuterTy)
+ //SEQPOINT NEEDED - we must consume spBind on this path
+ Some(mkSeqUsing cenv env wholeExprMark bindPatTy genOuterTy inputExpr consumeExpr, tpenv)
+
+ | SynExpr.LetOrUseBang (range=m) ->
+ error(Error(FSComp.SR.tcUseForInSequenceExpression(), m))
+
+ | SynExpr.Match (spMatch, expr, clauses, _) ->
+ let inputExpr, matchty, tpenv = TcExprOfUnknownType cenv env tpenv expr
+ let tclauses, tpenv =
+ List.mapFold
+ (fun tpenv (Clause(pat, cond, innerComp, _, sp)) ->
+ let pat', cond', vspecs, envinner, tpenv = TcMatchPattern cenv matchty env tpenv (pat, cond)
+ let innerExpr, tpenv = tcSequenceExprBody envinner genOuterTy tpenv innerComp
+ TClause(pat', cond', TTarget(vspecs, innerExpr, sp), pat'.Range), tpenv)
+ tpenv
+ clauses
+ let inputExprTy = tyOfExpr cenv.g inputExpr
+ let inputExprMark = inputExpr.Range
+ let matchv, matchExpr = CompilePatternForMatchClauses cenv env inputExprMark inputExprMark true ThrowIncompleteMatchException (Some inputExpr) inputExprTy genOuterTy tclauses
+ Some(mkLet spMatch inputExprMark matchv inputExpr matchExpr, tpenv)
+
+ | SynExpr.TryWith (tryRange=mTryToWith) ->
+ error(Error(FSComp.SR.tcTryIllegalInSequenceExpression(), mTryToWith))
+
+ | SynExpr.YieldOrReturnFrom ((isYield, _), yieldExpr, m) ->
+ let resultExpr, genExprTy, tpenv = TcExprOfUnknownType cenv env tpenv yieldExpr
+
+ if not isYield then errorR(Error(FSComp.SR.tcUseYieldBangForMultipleResults(), m))
+
+ AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace genOuterTy genExprTy
+ Some(mkCoerceExpr(resultExpr, genOuterTy, m, genExprTy), tpenv)
+
+ | SynExpr.YieldOrReturn ((isYield, _), yieldExpr, m) ->
+ let genResultTy = NewInferenceType ()
+ if not isYield then errorR(Error(FSComp.SR.tcSeqResultsUseYield(), m))
+ UnifyTypes cenv env m genOuterTy (mkSeqTy cenv.g genResultTy)
+
+ let resultExpr, tpenv = TcExprFlex cenv flex true genResultTy env tpenv yieldExpr
+ Some(mkCallSeqSingleton cenv.g m genResultTy resultExpr, tpenv )
+
+ | _ -> None
+
+ and tcSequenceExprBody env genOuterTy tpenv comp =
+ let res, tpenv = tcSequenceExprBodyAsSequenceOrStatement env genOuterTy tpenv comp
+ match res with
+ | Choice1Of2 expr ->
+ expr, tpenv
+ | Choice2Of2 stmt ->
+ let m = comp.Range
+ let resExpr = Expr.Sequential(stmt, mkSeqEmpty cenv env m genOuterTy, NormalSeq, DebugPointAtSequential.ExprOnly, m)
+ resExpr, tpenv
+
+ and tcSequenceExprBodyAsSequenceOrStatement env genOuterTy tpenv comp =
+ match tryTcSequenceExprBody env genOuterTy tpenv comp with
+ | Some (expr, tpenv) -> Choice1Of2 expr, tpenv
+ | None ->
+ let env = { env with eContextInfo = ContextInfo.SequenceExpression genOuterTy }
+ if enableImplicitYield then
+ let hasTypeUnit, expr, tpenv = TryTcStmt cenv env tpenv comp
+ if hasTypeUnit then
+ Choice2Of2 expr, tpenv
+ else
+ let genResultTy = NewInferenceType ()
+ UnifyTypes cenv env m genOuterTy (mkSeqTy cenv.g genResultTy)
+ let exprTy = tyOfExpr cenv.g expr
+ AddCxTypeMustSubsumeType env.eContextInfo env.DisplayEnv cenv.css m NoTrace genResultTy exprTy
+ let resExpr = mkCallSeqSingleton cenv.g m genResultTy (mkCoerceExpr(expr, genResultTy, m, exprTy))
+ Choice1Of2 resExpr, tpenv
+ else
+ let stmt, tpenv = TcStmtThatCantBeCtorBody cenv env tpenv comp
+ Choice2Of2 stmt, tpenv
+
+ let coreExpr, tpenv = tcSequenceExprBody env overallTy tpenv comp
+ let delayedExpr = mkDelayedExpr coreExpr
+ delayedExpr, tpenv
+
+let TcSequenceExpressionEntry (cenv: cenv) env overallTy tpenv (isArrayOrList, isNotNakedRefCell, comp) m =
+ let implicitYieldEnabled = cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitYield
+ let validateObjectSequenceOrRecordExpression = not implicitYieldEnabled
+ if not isArrayOrList then
+ match comp with
+ | SynExpr.New _ ->
+ errorR(Error(FSComp.SR.tcInvalidObjectExpressionSyntaxForm(), m))
+ | SimpleSemicolonSequence cenv false _ when validateObjectSequenceOrRecordExpression ->
+ errorR(Error(FSComp.SR.tcInvalidObjectSequenceOrRecordExpression(), m))
+ | _ ->
+ ()
+ if not !isNotNakedRefCell && not cenv.g.compilingFslib then
+ error(Error(FSComp.SR.tcInvalidSequenceExpressionSyntaxForm(), m))
+
+ TcSequenceExpression cenv env tpenv comp overallTy m
+
+let TcArrayOrListSequenceExpression (cenv: cenv) env overallTy tpenv (isArray, comp) m =
+ // LanguageFeatures.ImplicitYield do not require this validation
+ let implicitYieldEnabled = cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitYield
+ let validateExpressionWithIfRequiresParenthesis = not implicitYieldEnabled
+ let acceptDeprecatedIfThenExpression = not implicitYieldEnabled
+
+ match comp with
+ | SynExpr.CompExpr (_, _, (SimpleSemicolonSequence cenv acceptDeprecatedIfThenExpression elems as body), _) ->
+ match body with
+ | SimpleSemicolonSequence cenv false _ -> ()
+ | _ when validateExpressionWithIfRequiresParenthesis -> errorR(Deprecated(FSComp.SR.tcExpressionWithIfRequiresParenthesis(), m))
+ | _ -> ()
+
+ let replacementExpr =
+ if isArray then
+ // This are to improve parsing/processing speed for parser tables by converting to an array blob ASAP
+ let nelems = elems.Length
+ if nelems > 0 && List.forall (function SynExpr.Const (SynConst.UInt16 _, _) -> true | _ -> false) elems
+ then SynExpr.Const (SynConst.UInt16s (Array.ofList (List.map (function SynExpr.Const (SynConst.UInt16 x, _) -> x | _ -> failwith "unreachable") elems)), m)
+ elif nelems > 0 && List.forall (function SynExpr.Const (SynConst.Byte _, _) -> true | _ -> false) elems
+ then SynExpr.Const (SynConst.Bytes (Array.ofList (List.map (function SynExpr.Const (SynConst.Byte x, _) -> x | _ -> failwith "unreachable") elems), m), m)
+ else SynExpr.ArrayOrList (isArray, elems, m)
+ else
+ if elems.Length > 500 then
+ error(Error(FSComp.SR.tcListLiteralMaxSize(), m))
+ SynExpr.ArrayOrList (isArray, elems, m)
+
+ TcExprUndelayed cenv overallTy env tpenv replacementExpr
+ | _ ->
+
+ let genCollElemTy = NewInferenceType ()
+
+ let genCollTy = (if isArray then mkArrayType else mkListTy) cenv.g genCollElemTy
+
+ UnifyTypes cenv env m overallTy genCollTy
+
+ let exprty = mkSeqTy cenv.g genCollElemTy
+
+ // Check the comprehension
+ let expr, tpenv = TcExpr cenv exprty env tpenv comp
+
+ let expr = mkCoerceIfNeeded cenv.g exprty (tyOfExpr cenv.g expr) expr
+
+ let expr =
+ if cenv.g.compilingFslib then
+ expr
+ else
+ // We add a call to 'seq ... ' to make sure sequence expression compilation gets applied to the contents of the
+ // comprehension. But don't do this in FSharp.Core.dll since 'seq' may not yet be defined.
+ mkCallSeq cenv.g m genCollElemTy expr
+
+ let expr = mkCoerceExpr(expr, exprty, expr.Range, overallTy)
+
+ let expr =
+ if isArray then
+ mkCallSeqToArray cenv.g m genCollElemTy expr
+ else
+ mkCallSeqToList cenv.g m genCollElemTy expr
+
+ expr, tpenv
diff --git a/src/fsharp/CheckComputationExpressions.fsi b/src/fsharp/CheckComputationExpressions.fsi
new file mode 100644
index 00000000000..c4265c8697a
--- /dev/null
+++ b/src/fsharp/CheckComputationExpressions.fsi
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+module internal FSharp.Compiler.CheckComputationExpressions
+
+open FSharp.Compiler.CheckExpressions
+open FSharp.Compiler.SyntaxTree
+open FSharp.Compiler.Text
+open FSharp.Compiler.Text.Range
+open FSharp.Compiler.TypedTree
+
+val TcSequenceExpressionEntry: cenv:TcFileState -> env:TcEnv -> overallTy:TType -> tpenv:UnscopedTyparEnv -> isArrayOrList:bool * isNotNakedRefCell:bool ref * comp:SynExpr -> m:range -> Expr * UnscopedTyparEnv
+
+val TcArrayOrListSequenceExpression: cenv:TcFileState -> env:TcEnv -> overallTy:TType -> tpenv:UnscopedTyparEnv -> isArray:bool * comp:SynExpr -> m:range -> Expr * UnscopedTyparEnv
+
+val TcComputationExpression: cenv:TcFileState -> env:TcEnv -> overallTy:TType -> tpenv:UnscopedTyparEnv -> mWhole:range * interpExpr:Expr * builderTy:TType * comp:SynExpr -> Expr * UnscopedTyparEnv
+
diff --git a/src/fsharp/CheckDeclarations.fs b/src/fsharp/CheckDeclarations.fs
new file mode 100644
index 00000000000..6d2d38ef198
--- /dev/null
+++ b/src/fsharp/CheckDeclarations.fs
@@ -0,0 +1,5929 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+module internal FSharp.Compiler.CheckDeclarations
+
+open System
+open System.Collections.Generic
+
+open Internal.Utilities
+
+open FSharp.Compiler
+open FSharp.Compiler.AbstractIL
+open FSharp.Compiler.AbstractIL.IL
+open FSharp.Compiler.AbstractIL.Internal
+open FSharp.Compiler.AbstractIL.Internal.Library
+open FSharp.Compiler.AbstractIL.Internal.Library.ResultOrException
+open FSharp.Compiler.AbstractIL.Diagnostics
+open FSharp.Compiler.AccessibilityLogic
+open FSharp.Compiler.AttributeChecking
+open FSharp.Compiler.CheckExpressions
+open FSharp.Compiler.CheckComputationExpressions
+open FSharp.Compiler.CompilerGlobalState
+open FSharp.Compiler.ConstraintSolver
+open FSharp.Compiler.ErrorLogger
+open FSharp.Compiler.Features
+open FSharp.Compiler.Infos
+open FSharp.Compiler.InfoReader
+open FSharp.Compiler.Lib
+open FSharp.Compiler.MethodOverrides
+open FSharp.Compiler.NameResolution
+open FSharp.Compiler.SourceCodeServices.PrettyNaming
+open FSharp.Compiler.Text.Range
+open FSharp.Compiler.SyntaxTree
+open FSharp.Compiler.SyntaxTreeOps
+open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.Text
+open FSharp.Compiler.TypedTree
+open FSharp.Compiler.TypedTreeBasics
+open FSharp.Compiler.TypedTreeOps
+open FSharp.Compiler.TypeRelations
+open FSharp.Compiler.XmlDoc
+
+#if !NO_EXTENSIONTYPING
+open FSharp.Compiler.ExtensionTyping
+#endif
+
+type cenv = TcFileState
+
+//-------------------------------------------------------------------------
+// Mutually recursive shapes
+//-------------------------------------------------------------------------
+
+type MutRecDataForOpen = MutRecDataForOpen of SynOpenDeclTarget * range * appliedScope: range
+type MutRecDataForModuleAbbrev = MutRecDataForModuleAbbrev of Ident * LongIdent * range
+
+/// Represents the shape of a mutually recursive group of declarations including nested modules
+[]
+type MutRecShape<'TypeData, 'LetsData, 'ModuleData> =
+ | Tycon of 'TypeData
+ | Lets of 'LetsData
+ | Module of 'ModuleData * MutRecShapes<'TypeData, 'LetsData, 'ModuleData>
+ | ModuleAbbrev of MutRecDataForModuleAbbrev
+ | Open of MutRecDataForOpen
+
+and MutRecShapes<'TypeData, 'LetsData, 'ModuleData> = MutRecShape<'TypeData, 'LetsData, 'ModuleData> list
+
+//-------------------------------------------------------------------------
+// Mutually recursive shapes
+//-------------------------------------------------------------------------
+
+module MutRecShapes =
+ let rec map f1 f2 f3 x =
+ x |> List.map (function
+ | MutRecShape.Open a -> MutRecShape.Open a
+ | MutRecShape.ModuleAbbrev b -> MutRecShape.ModuleAbbrev b
+ | MutRecShape.Tycon a -> MutRecShape.Tycon (f1 a)
+ | MutRecShape.Lets b -> MutRecShape.Lets (f2 b)
+ | MutRecShape.Module (c, d) -> MutRecShape.Module (f3 c, map f1 f2 f3 d))
+
+ let mapTycons f1 xs = map f1 id id xs
+ let mapTyconsAndLets f1 f2 xs = map f1 f2 id xs
+ let mapLets f2 xs = map id f2 id xs
+ let mapModules f1 xs = map id id f1 xs
+
+ let rec mapWithEnv fTycon fLets (env: 'Env) x =
+ x |> List.map (function
+ | MutRecShape.Open a -> MutRecShape.Open a
+ | MutRecShape.ModuleAbbrev a -> MutRecShape.ModuleAbbrev a
+ | MutRecShape.Tycon a -> MutRecShape.Tycon (fTycon env a)
+ | MutRecShape.Lets b -> MutRecShape.Lets (fLets env b)
+ | MutRecShape.Module ((c, env2), d) -> MutRecShape.Module ((c, env2), mapWithEnv fTycon fLets env2 d))
+
+ let mapTyconsWithEnv f1 env xs = mapWithEnv f1 (fun _env x -> x) env xs
+
+ let rec mapWithParent parent f1 f2 f3 xs =
+ xs |> List.map (function
+ | MutRecShape.Open a -> MutRecShape.Open a
+ | MutRecShape.ModuleAbbrev a -> MutRecShape.ModuleAbbrev a
+ | MutRecShape.Tycon a -> MutRecShape.Tycon (f2 parent a)
+ | MutRecShape.Lets b -> MutRecShape.Lets (f3 parent b)
+ | MutRecShape.Module (c, d) ->
+ let c2, parent2 = f1 parent c d
+ MutRecShape.Module (c2, mapWithParent parent2 f1 f2 f3 d))
+
+ let rec computeEnvs f1 f2 (env: 'Env) xs =
+ let env = f2 env xs
+ env,
+ xs |> List.map (function
+ | MutRecShape.Open a -> MutRecShape.Open a
+ | MutRecShape.ModuleAbbrev a -> MutRecShape.ModuleAbbrev a
+ | MutRecShape.Tycon a -> MutRecShape.Tycon a
+ | MutRecShape.Lets b -> MutRecShape.Lets b
+ | MutRecShape.Module (c, ds) ->
+ let env2 = f1 env c
+ let env3, ds2 = computeEnvs f1 f2 env2 ds
+ MutRecShape.Module ((c, env3), ds2))
+
+ let rec extendEnvs f1 (env: 'Env) xs =
+ let env = f1 env xs
+ env,
+ xs |> List.map (function
+ | MutRecShape.Module ((c, env), ds) ->
+ let env2, ds2 = extendEnvs f1 env ds
+ MutRecShape.Module ((c, env2), ds2)
+ | x -> x)
+
+ let dropEnvs xs = xs |> mapModules fst
+
+ let rec expandTyconsWithEnv f1 env xs =
+ let preBinds, postBinds =
+ xs |> List.map (fun elem ->
+ match elem with
+ | MutRecShape.Tycon a -> f1 env a
+ | _ -> [], [])
+ |> List.unzip
+ [MutRecShape.Lets (List.concat preBinds)] @
+ (xs |> List.map (fun elem ->
+ match elem with
+ | MutRecShape.Module ((c, env2), d) -> MutRecShape.Module ((c, env2), expandTyconsWithEnv f1 env2 d)
+ | _ -> elem)) @
+ [MutRecShape.Lets (List.concat postBinds)]
+
+ let rec mapFoldWithEnv f1 z env xs =
+ (z, xs) ||> List.mapFold (fun z x ->
+ match x with
+ | MutRecShape.Module ((c, env2), ds) -> let ds2, z = mapFoldWithEnv f1 z env2 ds in MutRecShape.Module ((c, env2), ds2), z
+ | _ -> let x2, z = f1 z env x in x2, z)
+
+
+ let rec collectTycons x =
+ x |> List.collect (function
+ | MutRecShape.Tycon a -> [a]
+ | MutRecShape.Module (_, d) -> collectTycons d
+ | _ -> [])
+
+ let topTycons x =
+ x |> List.choose (function MutRecShape.Tycon a -> Some a | _ -> None)
+
+ let rec iter f1 f2 f3 f4 f5 x =
+ x |> List.iter (function
+ | MutRecShape.Tycon a -> f1 a
+ | MutRecShape.Lets b -> f2 b
+ | MutRecShape.Module (c, d) -> f3 c; iter f1 f2 f3 f4 f5 d
+ | MutRecShape.Open a -> f4 a
+ | MutRecShape.ModuleAbbrev a -> f5 a)
+
+ let iterTycons f1 x = iter f1 ignore ignore ignore ignore x
+ let iterTyconsAndLets f1 f2 x = iter f1 f2 ignore ignore ignore x
+ let iterModules f1 x = iter ignore ignore f1 ignore ignore x
+
+ let rec iterWithEnv f1 f2 f3 f4 env x =
+ x |> List.iter (function
+ | MutRecShape.Tycon a -> f1 env a
+ | MutRecShape.Lets b -> f2 env b
+ | MutRecShape.Module ((_, env), d) -> iterWithEnv f1 f2 f3 f4 env d
+ | MutRecShape.Open a -> f3 env a
+ | MutRecShape.ModuleAbbrev a -> f4 env a)
+
+ let iterTyconsWithEnv f1 env xs = iterWithEnv f1 (fun _env _x -> ()) (fun _env _x -> ()) (fun _env _x -> ()) env xs
+
+
+/// Indicates a declaration is contained in the given module
+let ModuleOrNamespaceContainerInfo modref = ContainerInfo(Parent modref, Some(MemberOrValContainerInfo(modref, None, None, NoSafeInitInfo, [])))
+
+/// Indicates a declaration is contained in the given type definition in the given module
+let TyconContainerInfo (parent, tcref, declaredTyconTypars, safeInitInfo) = ContainerInfo(parent, Some(MemberOrValContainerInfo(tcref, None, None, safeInitInfo, declaredTyconTypars)))
+
+type TyconBindingDefn = TyconBindingDefn of ContainerInfo * NewSlotsOK * DeclKind * SynMemberDefn * range
+
+type MutRecSigsInitialData = MutRecShape list
+type MutRecDefnsInitialData = MutRecShape list
+
+type MutRecDefnsPhase1DataForTycon = MutRecDefnsPhase1DataForTycon of SynComponentInfo * SynTypeDefnSimpleRepr * (SynType * range) list * preEstablishedHasDefaultCtor: bool * hasSelfReferentialCtor: bool * isAtOriginalTyconDefn: bool
+type MutRecDefnsPhase1Data = MutRecShape list
+
+type MutRecDefnsPhase2DataForTycon = MutRecDefnsPhase2DataForTycon of Tycon option * ParentRef * DeclKind * TyconRef * Val option * SafeInitData * Typars * SynMemberDefn list * range * NewSlotsOK * fixupFinalAttribs: (unit -> unit)
+type MutRecDefnsPhase2DataForModule = MutRecDefnsPhase2DataForModule of ModuleOrNamespaceType ref * ModuleOrNamespace
+type MutRecDefnsPhase2Data = MutRecShape list
+
+type MutRecDefnsPhase2InfoForTycon = MutRecDefnsPhase2InfoForTycon of Tycon option * TyconRef * Typars * DeclKind * TyconBindingDefn list * fixupFinalAttrs: (unit -> unit)
+type MutRecDefnsPhase2Info = MutRecShape list
+
+//-------------------------------------------------------------------------
+// Helpers for TcEnv
+//-------------------------------------------------------------------------
+
+/// Add an exception definition to TcEnv and report it to the sink
+let AddLocalExnDefnAndReport tcSink scopem env (exnc: Tycon) =
+ let env = { env with eNameResEnv = AddExceptionDeclsToNameEnv BulkAdd.No env.eNameResEnv (mkLocalEntityRef exnc) }
+ // Also make VisualStudio think there is an identifier in scope at the range of the identifier text of its binding location
+ CallEnvSink tcSink (exnc.Range, env.NameEnv, env.AccessRights)
+ CallEnvSink tcSink (scopem, env.NameEnv, env.AccessRights)
+ env
+
+/// Add a list of type definitions to TcEnv
+let AddLocalTyconRefs ownDefinition g amap m tcrefs env =
+ if isNil tcrefs then env else
+ { env with eNameResEnv = AddTyconRefsToNameEnv BulkAdd.No ownDefinition g amap env.eAccessRights m false env.eNameResEnv tcrefs }
+
+/// Add a list of type definitions to TcEnv
+let AddLocalTycons g amap m (tycons: Tycon list) env =
+ if isNil tycons then env else
+ env |> AddLocalTyconRefs false g amap m (List.map mkLocalTyconRef tycons)
+
+/// Add a list of type definitions to TcEnv and report them to the sink
+let AddLocalTyconsAndReport tcSink scopem g amap m tycons env =
+ let env = AddLocalTycons g amap m tycons env
+ CallEnvSink tcSink (scopem, env.NameEnv, env.eAccessRights)
+ env
+
+/// Add a "module X = ..." definition to the TcEnv
+let AddLocalSubModule g amap m env (modul: ModuleOrNamespace) =
+ let env = { env with
+ eNameResEnv = AddModuleOrNamespaceRefToNameEnv g amap m false env.eAccessRights env.eNameResEnv (mkLocalModRef modul)
+ eUngeneralizableItems = addFreeItemOfModuleTy modul.ModuleOrNamespaceType env.eUngeneralizableItems }
+ env
+
+/// Add a "module X = ..." definition to the TcEnv and report it to the sink
+let AddLocalSubModuleAndReport tcSink scopem g amap m env (modul: ModuleOrNamespace) =
+ let env = AddLocalSubModule g amap m env modul
+ CallEnvSink tcSink (scopem, env.NameEnv, env.eAccessRights)
+ env
+
+/// Given an inferred module type, place that inside a namespace path implied by a "namespace X.Y.Z" definition
+let BuildRootModuleType enclosingNamespacePath (cpath: CompilationPath) mtyp =
+ (enclosingNamespacePath, (cpath, (mtyp, [])))
+ ||> List.foldBack (fun id (cpath, (mtyp, mspecs)) ->
+ let a, b = wrapModuleOrNamespaceTypeInNamespace id cpath.ParentCompPath mtyp
+ cpath.ParentCompPath, (a, b :: mspecs))
+ |> fun (_, (mtyp, mspecs)) -> mtyp, List.rev mspecs
+
+/// Given a resulting module expression, place that inside a namespace path implied by a "namespace X.Y.Z" definition
+let BuildRootModuleExpr enclosingNamespacePath (cpath: CompilationPath) mexpr =
+ (enclosingNamespacePath, (cpath, mexpr))
+ ||> List.foldBack (fun id (cpath, mexpr) -> (cpath.ParentCompPath, wrapModuleOrNamespaceExprInNamespace id cpath.ParentCompPath mexpr))
+ |> snd
+
+/// Try to take the "FSINNN" prefix off a namespace path
+let TryStripPrefixPath (g: TcGlobals) (enclosingNamespacePath: Ident list) =
+ match enclosingNamespacePath with
+ | p :: rest when
+ g.isInteractive &&
+ not (isNil rest) &&
+ p.idText.StartsWithOrdinal FsiDynamicModulePrefix &&
+ p.idText.[FsiDynamicModulePrefix.Length..] |> String.forall System.Char.IsDigit
+ -> Some(p, rest)
+ | _ -> None
+
+/// Add a "module X = Y" local module abbreviation to the TcEnv
+let AddModuleAbbreviationAndReport tcSink scopem id modrefs env =
+ let env =
+ if isNil modrefs then env else
+ { env with eNameResEnv = AddModuleAbbrevToNameEnv id env.eNameResEnv modrefs }
+
+ CallEnvSink tcSink (scopem, env.NameEnv, env.eAccessRights)
+ let item = Item.ModuleOrNamespaces modrefs
+ CallNameResolutionSink tcSink (id.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.AccessRights)
+ env
+
+/// Adjust the TcEnv to account for opening the set of modules or namespaces implied by an `open` declaration
+let OpenModuleOrNamespaceRefs tcSink g amap scopem root env mvvs openDeclaration =
+ let env =
+ if isNil mvvs then env else
+ { env with eNameResEnv = AddModuleOrNamespaceRefsContentsToNameEnv g amap env.eAccessRights scopem root env.eNameResEnv mvvs }
+ CallEnvSink tcSink (scopem, env.NameEnv, env.eAccessRights)
+ CallOpenDeclarationSink tcSink openDeclaration
+ env
+
+/// Adjust the TcEnv to account for opening a type implied by an `open type` declaration
+let OpenTypeContent tcSink g amap scopem env (typ: TType) openDeclaration =
+ let env =
+ { env with eNameResEnv = AddTypeContentsToNameEnv g amap env.eAccessRights scopem env.eNameResEnv typ }
+ CallEnvSink tcSink (scopem, env.NameEnv, env.eAccessRights)
+ CallOpenDeclarationSink tcSink openDeclaration
+ env
+
+/// Adjust the TcEnv to account for a new root Ccu being available, e.g. a referenced assembly
+let AddRootModuleOrNamespaceRefs g amap m env modrefs =
+ if isNil modrefs then env else
+ { env with eNameResEnv = AddModuleOrNamespaceRefsToNameEnv g amap m true env.eAccessRights env.eNameResEnv modrefs }
+
+/// Adjust the TcEnv to make more things 'InternalsVisibleTo'
+let addInternalsAccessibility env (ccu: CcuThunk) =
+ let compPath = CompPath (ccu.ILScopeRef, [])
+ let eInternalsVisibleCompPaths = compPath :: env.eInternalsVisibleCompPaths
+ { env with
+ eAccessRights = ComputeAccessRights env.eAccessPath eInternalsVisibleCompPaths env.eFamilyType // update this computed field
+ eInternalsVisibleCompPaths = compPath :: env.eInternalsVisibleCompPaths }
+
+/// Adjust the TcEnv to account for a new referenced assembly
+let AddNonLocalCcu g amap scopem env assemblyName (ccu: CcuThunk, internalsVisibleToAttributes) =
+
+ let internalsVisible =
+ internalsVisibleToAttributes
+ |> List.exists (fun visibleTo ->
+ try
+ System.Reflection.AssemblyName(visibleTo).Name = assemblyName
+ with e ->
+ warning(InvalidInternalsVisibleToAssemblyName(visibleTo, ccu.FileName))
+ false)
+
+ let env = if internalsVisible then addInternalsAccessibility env ccu else env
+
+ // Compute the top-rooted module or namespace references
+ let modrefs = ccu.RootModulesAndNamespaces |> List.map (mkNonLocalCcuRootEntityRef ccu)
+
+ // Compute the top-rooted type definitions
+ let tcrefs = ccu.RootTypeAndExceptionDefinitions |> List.map (mkNonLocalCcuRootEntityRef ccu)
+ let env = AddRootModuleOrNamespaceRefs g amap scopem env modrefs
+ let env =
+ if isNil tcrefs then env else
+ { env with eNameResEnv = AddTyconRefsToNameEnv BulkAdd.Yes false g amap env.eAccessRights scopem true env.eNameResEnv tcrefs }
+ env
+
+/// Adjust the TcEnv to account for a fully processed "namespace" declaration in this file
+let AddLocalRootModuleOrNamespace tcSink g amap scopem env (mtyp: ModuleOrNamespaceType) =
+ // Compute the top-rooted module or namespace references
+ let modrefs = mtyp.ModuleAndNamespaceDefinitions |> List.map mkLocalModRef
+ // Compute the top-rooted type definitions
+ let tcrefs = mtyp.TypeAndExceptionDefinitions |> List.map mkLocalTyconRef
+ let env = AddRootModuleOrNamespaceRefs g amap scopem env modrefs
+ 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 mtyp env.eUngeneralizableItems }
+ CallEnvSink tcSink (scopem, env.NameEnv, env.eAccessRights)
+ env
+
+/// Inside "namespace X.Y.Z" there is an implicit open of "X.Y.Z"
+let ImplicitlyOpenOwnNamespace tcSink g amap scopem enclosingNamespacePath (env: TcEnv) =
+ if isNil enclosingNamespacePath then
+ env
+ else
+ // For F# interactive, skip "FSI_0002" prefixes when determining the path to open implicitly
+ let enclosingNamespacePathToOpen =
+ match TryStripPrefixPath g enclosingNamespacePath with
+ | Some(_, rest) -> rest
+ | None -> enclosingNamespacePath
+
+ match enclosingNamespacePathToOpen with
+ | id :: rest ->
+ let ad = env.AccessRights
+ match ResolveLongIdentAsModuleOrNamespace tcSink ResultCollectionSettings.AllResults amap scopem true OpenQualified env.eNameResEnv ad id rest true with
+ | Result modrefs ->
+ let modrefs = List.map p23 modrefs
+ let openTarget = SynOpenDeclTarget.ModuleOrNamespace(enclosingNamespacePathToOpen, scopem)
+ let openDecl = OpenDeclaration.Create (openTarget, modrefs, [], scopem, true)
+ OpenModuleOrNamespaceRefs tcSink g amap scopem false env modrefs openDecl
+ | Exception _ -> env
+ | _ -> env
+
+//-------------------------------------------------------------------------
+// Bind elements of data definitions for exceptions and types (fields, etc.)
+//-------------------------------------------------------------------------
+
+exception NotUpperCaseConstructor of range
+
+let CheckNamespaceModuleOrTypeName (g: TcGlobals) (id: Ident) =
+ // type names '[]' etc. are used in fslib
+ if not g.compilingFslib && id.idText.IndexOfAny IllegalCharactersInTypeAndNamespaceNames <> -1 then
+ errorR(Error(FSComp.SR.tcInvalidNamespaceModuleTypeUnionName(), id.idRange))
+
+let CheckDuplicates (idf: _ -> Ident) k elems =
+ elems |> List.iteri (fun i uc1 ->
+ elems |> List.iteri (fun j uc2 ->
+ let id1 = (idf uc1)
+ let id2 = (idf uc2)
+ if j > i && id1.idText = id2.idText then
+ errorR (Duplicate(k, id1.idText, id1.idRange))))
+ elems
+
+
+module TcRecdUnionAndEnumDeclarations =
+
+ let CombineReprAccess parent vis =
+ match parent with
+ | ParentNone -> vis
+ | Parent tcref -> combineAccess vis tcref.TypeReprAccessibility
+
+ let MakeRecdFieldSpec _cenv env parent (isStatic, konst, ty', attrsForProperty, attrsForField, id, nameGenerated, isMutable, vol, xmldoc, vis, m) =
+ let vis, _ = ComputeAccessAndCompPath env None m vis None parent
+ let vis = CombineReprAccess parent vis
+ Construct.NewRecdField isStatic konst id nameGenerated ty' isMutable vol attrsForProperty attrsForField xmldoc vis false
+
+ let TcFieldDecl cenv env parent isIncrClass tpenv (isStatic, synAttrs, id, nameGenerated, ty, isMutable, xmldoc, vis, m) =
+ let attrs, _ = TcAttributesWithPossibleTargets false cenv env AttributeTargets.FieldDecl synAttrs
+ let attrsForProperty, attrsForField = attrs |> List.partition (fun (attrTargets, _) -> (attrTargets &&& AttributeTargets.Property) <> enum 0)
+ let attrsForProperty = (List.map snd attrsForProperty)
+ let attrsForField = (List.map snd attrsForField)
+ let ty', _ = TcTypeAndRecover cenv NoNewTypars CheckCxs ItemOccurence.UseInType env tpenv ty
+ let zeroInit = HasFSharpAttribute cenv.g cenv.g.attrib_DefaultValueAttribute attrsForField
+ let isVolatile = HasFSharpAttribute cenv.g cenv.g.attrib_VolatileFieldAttribute attrsForField
+
+ let isThreadStatic = isThreadOrContextStatic cenv.g attrsForField
+ if isThreadStatic && (not zeroInit || not isStatic) then
+ error(Error(FSComp.SR.tcThreadStaticAndContextStaticMustBeStatic(), m))
+
+ if isVolatile then
+ error(Error(FSComp.SR.tcVolatileOnlyOnClassLetBindings(), m))
+
+ if isIncrClass && (not zeroInit || not isMutable) then errorR(Error(FSComp.SR.tcUninitializedValFieldsMustBeMutable(), m))
+ if isStatic && (not zeroInit || not isMutable || vis <> Some SynAccess.Private ) then errorR(Error(FSComp.SR.tcStaticValFieldsMustBeMutableAndPrivate(), m))
+ let konst = if zeroInit then Some Const.Zero else None
+ let rfspec = MakeRecdFieldSpec cenv env parent (isStatic, konst, ty', attrsForProperty, attrsForField, id, nameGenerated, isMutable, isVolatile, xmldoc, vis, m)
+ match parent with
+ | Parent tcref when useGenuineField tcref.Deref rfspec ->
+ // Recheck the attributes for errors if the definition only generates a field
+ TcAttributesWithPossibleTargets false cenv env AttributeTargets.FieldDeclRestricted synAttrs |> ignore
+ | _ -> ()
+ rfspec
+
+ let TcAnonFieldDecl cenv env parent tpenv nm (Field(Attributes attribs, isStatic, idOpt, ty, isMutable, xmldoc, vis, m)) =
+ let id = (match idOpt with None -> mkSynId m nm | Some id -> id)
+ let doc = xmldoc.ToXmlDoc(true, Some [])
+ TcFieldDecl cenv env parent false tpenv (isStatic, attribs, id, idOpt.IsNone, ty, isMutable, doc, vis, m)
+
+ let TcNamedFieldDecl cenv env parent isIncrClass tpenv (Field(Attributes attribs, isStatic, id, ty, isMutable, xmldoc, vis, m)) =
+ match id with
+ | None -> error (Error(FSComp.SR.tcFieldRequiresName(), m))
+ | Some id ->
+ let doc = xmldoc.ToXmlDoc(true, Some [])
+ TcFieldDecl cenv env parent isIncrClass tpenv (isStatic, attribs, id, false, ty, isMutable, doc, vis, m)
+
+ let TcNamedFieldDecls cenv env parent isIncrClass tpenv fields =
+ fields |> List.map (TcNamedFieldDecl cenv env parent isIncrClass tpenv)
+
+ //-------------------------------------------------------------------------
+ // Bind other elements of type definitions (constructors etc.)
+ //-------------------------------------------------------------------------
+
+ let CheckUnionCaseName (cenv: cenv) (id: Ident) =
+ let name = id.idText
+ if name = "Tags" then
+ errorR(Error(FSComp.SR.tcUnionCaseNameConflictsWithGeneratedType(name, "Tags"), id.idRange))
+
+ CheckNamespaceModuleOrTypeName cenv.g id
+ if not (String.isLeadingIdentifierCharacterUpperCase name) && name <> opNameCons && name <> opNameNil then
+ errorR(NotUpperCaseConstructor(id.idRange))
+
+ let ValidateFieldNames (synFields: SynField list, tastFields: RecdField list) =
+ let seen = Dictionary()
+ for (sf, f) in List.zip synFields tastFields do
+ match seen.TryGetValue f.Name with
+ | true, synField ->
+ match sf, synField with
+ | Field(_, _, Some id, _, _, _, _, _), Field(_, _, Some(_), _, _, _, _, _) ->
+ error(Error(FSComp.SR.tcFieldNameIsUsedModeThanOnce(id.idText), id.idRange))
+ | Field(_, _, Some id, _, _, _, _, _), Field(_, _, None, _, _, _, _, _)
+ | Field(_, _, None, _, _, _, _, _), Field(_, _, Some id, _, _, _, _, _) ->
+ error(Error(FSComp.SR.tcFieldNameConflictsWithGeneratedNameForAnonymousField(id.idText), id.idRange))
+ | _ -> assert false
+ | _ ->
+ seen.Add(f.Name, sf)
+
+ let TcUnionCaseDecl cenv env parent thisTy thisTyInst tpenv (UnionCase(Attributes synAttrs, id, args, xmldoc, vis, m)) =
+ let attrs = TcAttributes cenv env AttributeTargets.UnionCaseDecl synAttrs // the attributes of a union case decl get attached to the generated "static factory" method
+ let vis, _ = ComputeAccessAndCompPath env None m vis None parent
+ let vis = CombineReprAccess parent vis
+
+ CheckUnionCaseName cenv id
+
+ let rfields, recordTy =
+ match args with
+ | UnionCaseFields flds ->
+ let nFields = flds.Length
+ let rfields = flds |> List.mapi (fun i (Field (idOpt = idOpt) as fld) ->
+ match idOpt, parent with
+ | Some fieldId, Parent tcref ->
+ let item = Item.UnionCaseField (UnionCaseInfo (thisTyInst, UnionCaseRef (tcref, id.idText)), i)
+ CallNameResolutionSink cenv.tcSink (fieldId.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Binding, env.AccessRights)
+ | _ -> ()
+
+ TcAnonFieldDecl cenv env parent tpenv (mkUnionCaseFieldName nFields i) fld)
+ ValidateFieldNames(flds, rfields)
+
+ rfields, thisTy
+ | UnionCaseFullType (ty, arity) ->
+ let ty', _ = TcTypeAndRecover cenv NoNewTypars CheckCxs ItemOccurence.UseInType env tpenv ty
+ let curriedArgTys, recordTy = GetTopTauTypeInFSharpForm cenv.g (arity |> TranslateTopValSynInfo m (TcAttributes cenv env) |> TranslatePartialArity []).ArgInfos ty' m
+ if curriedArgTys.Length > 1 then
+ errorR(Error(FSComp.SR.tcIllegalFormForExplicitTypeDeclaration(), m))
+ let argTys = curriedArgTys |> List.concat
+ let nFields = argTys.Length
+ let rfields =
+ argTys |> List.mapi (fun i (argty, argInfo) ->
+ let id = (match argInfo.Name with Some id -> id | None -> mkSynId m (mkUnionCaseFieldName nFields i))
+ MakeRecdFieldSpec cenv env parent (false, None, argty, [], [], id, argInfo.Name.IsNone, false, false, XmlDoc.Empty, None, m))
+ if not (typeEquiv cenv.g recordTy thisTy) then
+ error(Error(FSComp.SR.tcReturnTypesForUnionMustBeSameAsType(), m))
+ rfields, recordTy
+ let names = rfields |> List.map (fun f -> f.Name)
+ let doc = xmldoc.ToXmlDoc(true, Some names)
+ Construct.NewUnionCase id rfields recordTy attrs doc vis
+
+ let TcUnionCaseDecls cenv env parent (thisTy: TType) thisTyInst tpenv unionCases =
+ let unionCases' = unionCases |> List.map (TcUnionCaseDecl cenv env parent thisTy thisTyInst tpenv)
+ unionCases' |> CheckDuplicates (fun uc -> uc.Id) "union case"
+
+ let TcEnumDecl cenv env parent thisTy fieldTy (EnumCase(Attributes synAttrs, id, v, xmldoc, m)) =
+ let attrs = TcAttributes cenv env AttributeTargets.Field synAttrs
+ match v with
+ | SynConst.Bytes _
+ | SynConst.UInt16s _
+ | SynConst.UserNum _ -> error(Error(FSComp.SR.tcInvalidEnumerationLiteral(), m))
+ | _ ->
+ let v = TcConst cenv fieldTy m env v
+ let vis, _ = ComputeAccessAndCompPath env None m None None parent
+ let vis = CombineReprAccess parent vis
+ if id.idText = "value__" then errorR(Error(FSComp.SR.tcNotValidEnumCaseName(), id.idRange))
+ let doc = xmldoc.ToXmlDoc(true, Some [])
+ Construct.NewRecdField true (Some v) id false thisTy false false [] attrs doc vis false
+
+ let TcEnumDecls cenv env parent thisTy enumCases =
+ let fieldTy = NewInferenceType ()
+ let enumCases' = enumCases |> List.map (TcEnumDecl cenv env parent thisTy fieldTy) |> CheckDuplicates (fun f -> f.Id) "enum element"
+ fieldTy, enumCases'
+
+//-------------------------------------------------------------------------
+// Bind elements of classes
+//-------------------------------------------------------------------------
+
+let PublishInterface (cenv: cenv) denv (tcref: TyconRef) m compgen ty' =
+ if not (isInterfaceTy cenv.g ty') then errorR(Error(FSComp.SR.tcTypeIsNotInterfaceType1(NicePrint.minimalStringOfType denv ty'), m))
+ let tcaug = tcref.TypeContents
+ if tcref.HasInterface cenv.g ty' then
+ errorR(Error(FSComp.SR.tcDuplicateSpecOfInterface(), m))
+ tcaug.tcaug_interfaces <- (ty', compgen, m) :: tcaug.tcaug_interfaces
+
+let TcAndPublishMemberSpec cenv env containerInfo declKind tpenv memb =
+ match memb with
+ | SynMemberSig.ValField(_, m) -> error(Error(FSComp.SR.tcFieldValIllegalHere(), m))
+ | SynMemberSig.Inherit(_, m) -> error(Error(FSComp.SR.tcInheritIllegalHere(), m))
+ | SynMemberSig.NestedType(_, m) -> error(Error(FSComp.SR.tcTypesCannotContainNestedTypes(), m))
+ | SynMemberSig.Member(valSpfn, memberFlags, _) ->
+ TcAndPublishValSpec (cenv, env, containerInfo, declKind, Some memberFlags, tpenv, valSpfn)
+ | SynMemberSig.Interface _ ->
+ // These are done in TcMutRecDefns_Phase1
+ [], tpenv
+
+
+let TcTyconMemberSpecs cenv env containerInfo declKind tpenv augSpfn =
+ let members, tpenv = List.mapFold (TcAndPublishMemberSpec cenv env containerInfo declKind) tpenv augSpfn
+ List.concat members, tpenv
+
+
+//-------------------------------------------------------------------------
+// Bind 'open' declarations
+//-------------------------------------------------------------------------
+
+let TcOpenLidAndPermitAutoResolve tcSink (env: TcEnv) amap (longId : Ident list) =
+ let ad = env.AccessRights
+ match longId with
+ | [] -> []
+ | id :: rest ->
+ let m = longId |> List.map (fun id -> id.idRange) |> List.reduce unionRanges
+ match ResolveLongIdentAsModuleOrNamespace tcSink ResultCollectionSettings.AllResults amap m true OpenQualified env.NameEnv ad id rest true with
+ | Result res -> res
+ | Exception err ->
+ errorR(err); []
+
+let TcOpenModuleOrNamespaceDecl tcSink g amap scopem env (longId, m) =
+ match TcOpenLidAndPermitAutoResolve tcSink env amap longId with
+ | [] -> env
+ | modrefs ->
+
+ // validate opened namespace names
+ for id in longId do
+ if id.idText <> MangledGlobalName then
+ CheckNamespaceModuleOrTypeName g id
+
+ let IsPartiallyQualifiedNamespace (modref: ModuleOrNamespaceRef) =
+ let (CompPath(_, p)) = modref.CompilationPath
+ // Bug FSharp 1.0 3274: FSI paths don't count when determining this warning
+ let p =
+ match p with
+ | [] -> []
+ | (h, _) :: t -> if h.StartsWithOrdinal FsiDynamicModulePrefix then t else p
+
+ // See https://fslang.uservoice.com/forums/245727-f-language/suggestions/6107641-make-microsoft-prefix-optional-when-using-core-f
+ let isFSharpCoreSpecialCase =
+ match ccuOfTyconRef modref with
+ | None -> false
+ | Some ccu ->
+ ccuEq ccu g.fslibCcu &&
+ // Check if we're using a reference one string shorter than what we expect.
+ //
+ // "p" is the fully qualified path _containing_ the thing we're opening, e.g. "Microsoft.FSharp" when opening "Microsoft.FSharp.Data"
+ // "longId" is the text being used, e.g. "FSharp.Data"
+ // Length of thing being opened = p.Length + 1
+ // Length of reference = longId.Length
+ // So the reference is a "shortened" reference if (p.Length + 1) - 1 = longId.Length
+ (p.Length + 1) - 1 = longId.Length &&
+ fst p.[0] = "Microsoft"
+
+ modref.IsNamespace &&
+ p.Length >= longId.Length &&
+ not isFSharpCoreSpecialCase
+ // Allow "open Foo" for "Microsoft.Foo" from FSharp.Core
+
+ modrefs |> List.iter (fun (_, modref, _) ->
+ if modref.IsModule && HasFSharpAttribute g g.attrib_RequireQualifiedAccessAttribute modref.Attribs then
+ errorR(Error(FSComp.SR.tcModuleRequiresQualifiedAccess(fullDisplayTextOfModRef modref), m)))
+
+ // Bug FSharp 1.0 3133: 'open Lexing'. Skip this warning if we successfully resolved to at least a module name
+ if not (modrefs |> List.exists (fun (_, modref, _) -> modref.IsModule && not (HasFSharpAttribute g g.attrib_RequireQualifiedAccessAttribute modref.Attribs))) then
+ modrefs |> List.iter (fun (_, modref, _) ->
+ if IsPartiallyQualifiedNamespace modref then
+ errorR(Error(FSComp.SR.tcOpenUsedWithPartiallyQualifiedPath(fullDisplayTextOfModRef modref), m)))
+
+ let modrefs = List.map p23 modrefs
+ modrefs |> List.iter (fun modref -> CheckEntityAttributes g modref m |> CommitOperationResult)
+
+ let openDecl = OpenDeclaration.Create (SynOpenDeclTarget.ModuleOrNamespace (longId, m), modrefs, [], scopem, false)
+ let env = OpenModuleOrNamespaceRefs tcSink g amap scopem false env modrefs openDecl
+ env
+
+let TcOpenTypeDecl (cenv: cenv) mOpenDecl scopem env (synType: SynType, m) =
+ let g = cenv.g
+
+ checkLanguageFeatureError g.langVersion LanguageFeature.OpenTypeDeclaration mOpenDecl
+
+ let typ, _tpenv = TcType cenv NoNewTypars CheckCxs ItemOccurence.Open env emptyUnscopedTyparEnv synType
+
+ if not (isAppTy g typ) then
+ error(Error(FSComp.SR.tcNamedTypeRequired("open type"), m))
+
+ if isByrefTy g typ then
+ error(Error(FSComp.SR.tcIllegalByrefsInOpenTypeDeclaration(), m))
+
+ let openDecl = OpenDeclaration.Create (SynOpenDeclTarget.Type (synType, m), [], [typ], scopem, false)
+ let env = OpenTypeContent cenv.tcSink g cenv.amap scopem env typ openDecl
+ env
+
+let TcOpenDecl cenv mOpenDecl scopem env target =
+ match target with
+ | SynOpenDeclTarget.ModuleOrNamespace (longId, m) -> TcOpenModuleOrNamespaceDecl cenv.tcSink cenv.g cenv.amap scopem env (longId, m)
+ | SynOpenDeclTarget.Type (synType, m) -> TcOpenTypeDecl cenv mOpenDecl scopem env (synType, m)
+
+exception ParameterlessStructCtor of range
+
+let MakeSafeInitField (g: TcGlobals) env m isStatic =
+ let id =
+ // Ensure that we have an g.CompilerGlobalState
+ assert(g.CompilerGlobalState |> Option.isSome)
+ ident(g.CompilerGlobalState.Value.NiceNameGenerator.FreshCompilerGeneratedName("init", m), m)
+ let taccess = TAccess [env.eAccessPath]
+ Construct.NewRecdField isStatic None id false g.int_ty true true [] [] XmlDoc.Empty taccess true
+
+/// Incremental class definitions
+module IncrClassChecking =
+
+ /// Represents a single group of bindings in a class with an implicit constructor
+ type IncrClassBindingGroup =
+ | IncrClassBindingGroup of Binding list * (*isStatic:*) bool* (*recursive:*) bool
+ | IncrClassDo of Expr * (*isStatic:*) bool
+
+ /// Typechecked info for implicit constructor and it's arguments
+ type IncrClassCtorLhs =
+ {
+ /// The TyconRef for the type being defined
+ TyconRef: TyconRef
+
+ /// The type parameters allocated for the implicit instance constructor.
+ /// These may be equated with other (WillBeRigid) type parameters through equi-recursive inference, and so
+ /// should always be renormalized/canonicalized when used.
+ InstanceCtorDeclaredTypars: Typars
+
+ /// The value representing the static implicit constructor.
+ /// Lazy to ensure the static ctor value is only published if needed.
+ StaticCtorValInfo: Lazy<(Val list * Val * ValScheme)>
+
+ /// The value representing the implicit constructor.
+ InstanceCtorVal: Val
+
+ /// The type of the implicit constructor, representing as a ValScheme.
+ InstanceCtorValScheme: ValScheme
+
+ /// The values representing the arguments to the implicit constructor.
+ InstanceCtorArgs: Val list
+
+ /// The reference cell holding the 'this' parameter within the implicit constructor so it can be referenced in the
+ /// arguments passed to the base constructor
+ InstanceCtorSafeThisValOpt: Val option
+
+ /// Data indicating if safe-initialization checks need to be inserted for this type.
+ InstanceCtorSafeInitInfo: SafeInitData
+
+ /// The value representing the 'base' variable within the implicit instance constructor.
+ InstanceCtorBaseValOpt: Val option
+
+ /// The value representing the 'this' variable within the implicit instance constructor.
+ InstanceCtorThisVal: Val
+
+ /// The name generator used to generate the names of fields etc. within the type.
+ NameGenerator: NiceNameGenerator
+ }
+
+ /// Get the type parameters of the implicit constructor, after taking equi-recursive inference into account.
+ member ctorInfo.GetNormalizedInstanceCtorDeclaredTypars (cenv: cenv) denv m =
+ let ctorDeclaredTypars = ctorInfo.InstanceCtorDeclaredTypars
+ let ctorDeclaredTypars = ChooseCanonicalDeclaredTyparsAfterInference cenv.g denv ctorDeclaredTypars m
+ ctorDeclaredTypars
+
+ /// Check and elaborate the "left hand side" of the implicit class construction
+ /// syntax.
+ let TcImplicitCtorLhs_Phase2A(cenv: cenv, env, tpenv, tcref: TyconRef, vis, attrs, spats, thisIdOpt, baseValOpt: Val option, safeInitInfo, m, copyOfTyconTypars, objTy, thisTy, doc: PreXmlDoc) =
+
+ let baseValOpt =
+ match GetSuperTypeOfType cenv.g cenv.amap m objTy with
+ | Some superTy -> MakeAndPublishBaseVal cenv env (match baseValOpt with None -> None | Some v -> Some v.Id) superTy
+ | None -> None
+
+ // Add class typars to env
+ let env = AddDeclaredTypars CheckForDuplicateTypars copyOfTyconTypars env
+
+ // Type check arguments by processing them as 'simple' patterns
+ // NOTE: if we allow richer patterns here this is where we'd process those patterns
+ let ctorArgNames, (_, names, _) = TcSimplePatsOfUnknownType cenv true CheckCxs env tpenv (SynSimplePats.SimplePats (spats, m))
+
+ // Create the values with the given names
+ let _, vspecs = MakeAndPublishSimpleVals cenv env names
+
+ if tcref.IsStructOrEnumTycon && isNil spats then
+ errorR (ParameterlessStructCtor(tcref.Range))
+
+ // Put them in order
+ let ctorArgs = List.map (fun v -> NameMap.find v vspecs) ctorArgNames
+ let safeThisValOpt = MakeAndPublishSafeThisVal cenv env thisIdOpt thisTy
+
+ // NOTE: the type scheme here is not complete!!! The ctorTy is more or less
+ // just a type variable. The type and typars get fixed-up after inference
+ let ctorValScheme, ctorVal =
+ let argty = mkRefTupledTy cenv.g (typesOfVals ctorArgs)
+ // Initial type has known information
+ let ctorTy = mkFunTy argty objTy
+ // REVIEW: no attributes can currently be specified for the implicit constructor
+ let attribs = TcAttributes cenv env (AttributeTargets.Constructor ||| AttributeTargets.Method) attrs
+ let memberFlags = CtorMemberFlags
+
+ let synArgInfos = List.map (SynInfo.InferSynArgInfoFromSimplePat []) spats
+ let valSynData = SynValInfo([synArgInfos], SynInfo.unnamedRetVal)
+ let id = ident ("new", m)
+
+ CheckForNonAbstractInterface ModuleOrMemberBinding tcref memberFlags id.idRange
+ let memberInfo = MakeMemberDataAndMangledNameForMemberVal(cenv.g, tcref, false, attribs, [], memberFlags, valSynData, id, false)
+ let partialValReprInfo = TranslateTopValSynInfo m (TcAttributes cenv env) valSynData
+ let prelimTyschemeG = TypeScheme(copyOfTyconTypars, ctorTy)
+ let isComplete = ComputeIsComplete copyOfTyconTypars [] ctorTy
+ let topValInfo = InferGenericArityFromTyScheme prelimTyschemeG partialValReprInfo
+ let ctorValScheme = ValScheme(id, prelimTyschemeG, Some topValInfo, Some memberInfo, false, ValInline.Never, NormalVal, vis, false, true, false, false)
+ let paramNames = topValInfo.ArgNames
+ let doc = doc.ToXmlDoc(true, paramNames)
+ let ctorVal = MakeAndPublishVal cenv env (Parent tcref, false, ModuleOrMemberBinding, ValInRecScope isComplete, ctorValScheme, attribs, doc, None, false)
+ ctorValScheme, ctorVal
+
+ // We only generate the cctor on demand, because we don't need it if there are no cctor actions.
+ // The code below has a side-effect (MakeAndPublishVal), so we only want to run it once if at all.
+ // The .cctor is never referenced by any other code.
+ let cctorValInfo =
+ lazy
+ (let cctorArgs = [ fst(mkCompGenLocal m "unitVar" cenv.g.unit_ty) ]
+
+ let cctorTy = mkFunTy cenv.g.unit_ty cenv.g.unit_ty
+ let valSynData = SynValInfo([[]], SynInfo.unnamedRetVal)
+ let id = ident ("cctor", m)
+ CheckForNonAbstractInterface ModuleOrMemberBinding tcref ClassCtorMemberFlags id.idRange
+ let memberInfo = MakeMemberDataAndMangledNameForMemberVal(cenv.g, tcref, false, [(*no attributes*)], [], ClassCtorMemberFlags, valSynData, id, false)
+ let partialValReprInfo = TranslateTopValSynInfo m (TcAttributes cenv env) valSynData
+ let prelimTyschemeG = TypeScheme(copyOfTyconTypars, cctorTy)
+ let topValInfo = InferGenericArityFromTyScheme prelimTyschemeG partialValReprInfo
+ let cctorValScheme = ValScheme(id, prelimTyschemeG, Some topValInfo, Some memberInfo, false, ValInline.Never, NormalVal, Some SynAccess.Private, false, true, false, false)
+
+ let cctorVal = MakeAndPublishVal cenv env (Parent tcref, false, ModuleOrMemberBinding, ValNotInRecScope, cctorValScheme, [(* no attributes*)], XmlDoc.Empty, None, false)
+ cctorArgs, cctorVal, cctorValScheme)
+
+ let thisVal =
+ // --- Create this for use inside constructor
+ let thisId = ident ("this", m)
+ let thisValScheme = ValScheme(thisId, NonGenericTypeScheme thisTy, None, None, false, ValInline.Never, CtorThisVal, None, true, false, false, false)
+ let thisVal = MakeAndPublishVal cenv env (ParentNone, false, ClassLetBinding false, ValNotInRecScope, thisValScheme, [], XmlDoc.Empty, None, false)
+ thisVal
+
+ {TyconRef = tcref
+ InstanceCtorDeclaredTypars = copyOfTyconTypars
+ StaticCtorValInfo = cctorValInfo
+ InstanceCtorArgs = ctorArgs
+ InstanceCtorVal = ctorVal
+ InstanceCtorValScheme = ctorValScheme
+ InstanceCtorBaseValOpt = baseValOpt
+ InstanceCtorSafeThisValOpt = safeThisValOpt
+ InstanceCtorSafeInitInfo = safeInitInfo
+ InstanceCtorThisVal = thisVal
+ // For generating names of local fields
+ NameGenerator = NiceNameGenerator()
+
+ }
+
+
+ // Partial class defns - local val mapping to fields
+
+ /// Create the field for a "let" binding in a type definition.
+ ///
+ /// The "v" is the local typed w.r.t. tyvars of the implicit ctor.
+ /// The formalTyparInst does the formal-typars/implicit-ctor-typars subst.
+ /// Field specifications added to a tcref must be in terms of the tcrefs formal typars.
+ let private MakeIncrClassField(g, cpath, formalTyparInst: TyparInst, v: Val, isStatic, rfref: RecdFieldRef) =
+ let name = rfref.FieldName
+ let id = ident (name, v.Range)
+ let ty = v.Type |> instType formalTyparInst
+ let taccess = TAccess [cpath]
+ let isVolatile = HasFSharpAttribute g g.attrib_VolatileFieldAttribute v.Attribs
+
+ Construct.NewRecdField isStatic None id false ty v.IsMutable isVolatile [] v.Attribs v.XmlDoc taccess true
+
+ /// Indicates how is a 'let' bound value in a class with implicit construction is represented in
+ /// the TAST ultimately produced by type checking.
+ type IncrClassValRepr =
+
+ // e.g representation for 'let v = 3' if it is not used in anything given a method representation
+ | InVar of (* isArg: *) bool
+
+ // e.g representation for 'let v = 3'
+ | InField of (*isStatic:*)bool * (*staticCountForSafeInit:*) int * RecdFieldRef
+
+ // e.g representation for 'let f x = 3'
+ | InMethod of (*isStatic:*)bool * Val * ValReprInfo
+
+ /// IncrClassReprInfo represents the decisions we make about the representation of 'let' and 'do' bindings in a
+ /// type defined with implicit class construction.
+ type IncrClassReprInfo =
+ {
+ /// Indicates the set of field names taken within one incremental class
+ TakenFieldNames: Set
+
+ RepInfoTcGlobals: TcGlobals
+
+ /// vals mapped to representations
+ ValReprs: Zmap
+
+ /// vals represented as fields or members from this point on
+ ValsWithRepresentation: Zset
+ }
+
+ static member Empty(g, names) =
+ { TakenFieldNames=Set.ofList names
+ RepInfoTcGlobals=g
+ ValReprs = Zmap.empty valOrder
+ ValsWithRepresentation = Zset.empty valOrder }
+
+ /// Find the representation of a value
+ member localRep.LookupRepr (v: Val) =
+ match Zmap.tryFind v localRep.ValReprs with
+ | None -> error(InternalError("LookupRepr: failed to find representation for value", v.Range))
+ | Some res -> res
+
+ static member IsMethodRepr (cenv: cenv) (bind: Binding) =
+ let v = bind.Var
+ // unit fields are not stored, just run rhs for effects
+ if isUnitTy cenv.g v.Type then
+ false
+ else
+ let arity = InferArityOfExprBinding cenv.g AllowTypeDirectedDetupling.Yes v bind.Expr
+ not arity.HasNoArgs && not v.IsMutable
+
+
+ /// Choose how a binding is represented
+ member localRep.ChooseRepresentation (cenv: cenv, env: TcEnv, isStatic, isCtorArg,
+ ctorInfo: IncrClassCtorLhs,
+ /// The vars forced to be fields due to static member bindings, instance initialization expressions or instance member bindings
+ staticForcedFieldVars: FreeLocals,
+ /// The vars forced to be fields due to instance member bindings
+ instanceForcedFieldVars: FreeLocals,
+ takenFieldNames: Set,
+ bind: Binding) =
+ let g = cenv.g
+ let v = bind.Var
+ let relevantForcedFieldVars = (if isStatic then staticForcedFieldVars else instanceForcedFieldVars)
+
+ let tcref = ctorInfo.TyconRef
+ let name, takenFieldNames =
+
+ let isNameTaken =
+ // Check if a implicit field already exists with this name
+ takenFieldNames.Contains(v.LogicalName) ||
+ // Check if a user-defined field already exists with this name. Struct fields have already been created - see bug FSharp 1.0 5304
+ (tcref.GetFieldByName(v.LogicalName).IsSome && (isStatic || not tcref.IsFSharpStructOrEnumTycon))
+
+ let nm =
+ if isNameTaken then
+ ctorInfo.NameGenerator.FreshCompilerGeneratedName (v.LogicalName, v.Range)
+ else
+ v.LogicalName
+ nm, takenFieldNames.Add nm
+
+ let reportIfUnused() =
+ if not v.HasBeenReferenced && not v.IsCompiledAsTopLevel && not (v.DisplayName.StartsWithOrdinal("_")) && not v.IsCompilerGenerated then
+ warning (Error(FSComp.SR.chkUnusedValue(v.DisplayName), v.Range))
+
+ let repr =
+ match InferArityOfExprBinding g AllowTypeDirectedDetupling.Yes v bind.Expr with
+ | arity when arity.HasNoArgs || v.IsMutable ->
+ // all mutable variables are forced into fields, since they may escape into closures within the implicit constructor
+ // e.g.
+ // type C() =
+ // let mutable m = 1
+ // let n = ... (fun () -> m) ....
+ //
+ // All struct variables are forced into fields. Structs may not contain "let" bindings, so no new variables can be
+ // introduced.
+
+ if v.IsMutable || relevantForcedFieldVars.Contains v || tcref.IsStructOrEnumTycon then
+ //dprintfn "Representing %s as a field %s" v.LogicalName name
+ let rfref = RecdFieldRef(tcref, name)
+ reportIfUnused()
+ InField (isStatic, localRep.ValReprs.Count, rfref)
+ else
+ //if not v.Attribs.IsEmpty then
+ // warning(Error(FSComp.SR.tcAttributesIgnoredOnLetBinding(), v.Range))
+ //dprintfn
+ // "Representing %s as a local variable %s, staticForcedFieldVars = %s, instanceForcedFieldVars = %s"
+ // v.LogicalName name
+ // (staticForcedFieldVars |> Seq.map (fun v -> v.LogicalName) |> String.concat ",")
+ // (instanceForcedFieldVars |> Seq.map (fun v -> v.LogicalName) |> String.concat ",")
+ InVar isCtorArg
+ | topValInfo ->
+ //dprintfn "Representing %s as a method %s" v.LogicalName name
+ let tps, _, argInfos, _, _ = GetTopValTypeInCompiledForm g topValInfo 0 v.Type v.Range
+
+ let valSynInfo = SynValInfo(argInfos |> List.mapSquared (fun (_, argInfo) -> SynArgInfo([], false, argInfo.Name)), SynInfo.unnamedRetVal)
+ let memberFlags = (if isStatic then StaticMemberFlags else NonVirtualMemberFlags) MemberKind.Member
+ let id = mkSynId v.Range name
+ let memberInfo = MakeMemberDataAndMangledNameForMemberVal(g, tcref, false, [], [], memberFlags, valSynInfo, mkSynId v.Range name, true)
+
+ let copyOfTyconTypars = ctorInfo.GetNormalizedInstanceCtorDeclaredTypars cenv env.DisplayEnv ctorInfo.TyconRef.Range
+ // Add the 'this' pointer on to the function
+ let memberTauTy, topValInfo =
+ let tauTy = v.TauType
+ if isStatic then
+ tauTy, topValInfo
+ else
+ let tauTy = ctorInfo.InstanceCtorThisVal.Type --> v.TauType
+ let (ValReprInfo(tpNames, args, ret)) = topValInfo
+ let topValInfo = ValReprInfo(tpNames, ValReprInfo.selfMetadata :: args, ret)
+ tauTy, topValInfo
+
+ // Add the enclosing type parameters on to the function
+ let topValInfo =
+ let (ValReprInfo(tpNames, args, ret)) = topValInfo
+ ValReprInfo(tpNames@ValReprInfo.InferTyparInfo copyOfTyconTypars, args, ret)
+
+ let prelimTyschemeG = TypeScheme(copyOfTyconTypars@tps, memberTauTy)
+ let memberValScheme = ValScheme(id, prelimTyschemeG, Some topValInfo, Some memberInfo, false, ValInline.Never, NormalVal, None, true (* isCompilerGenerated *), true (* isIncrClass *), false, false)
+ let methodVal = MakeAndPublishVal cenv env (Parent tcref, false, ModuleOrMemberBinding, ValNotInRecScope, memberValScheme, v.Attribs, XmlDoc.Empty, None, false)
+ reportIfUnused()
+ InMethod(isStatic, methodVal, topValInfo)
+
+ repr, takenFieldNames
+
+ /// Extend the known local representations by choosing a representation for a binding
+ member localRep.ChooseAndAddRepresentation(cenv: cenv, env: TcEnv, isStatic, isCtorArg, ctorInfo: IncrClassCtorLhs, staticForcedFieldVars: FreeLocals, instanceForcedFieldVars: FreeLocals, bind: Binding) =
+ let v = bind.Var
+ let repr, takenFieldNames = localRep.ChooseRepresentation (cenv, env, isStatic, isCtorArg, ctorInfo, staticForcedFieldVars, instanceForcedFieldVars, localRep.TakenFieldNames, bind )
+ // OK, representation chosen, now add it
+ {localRep with
+ TakenFieldNames=takenFieldNames
+ ValReprs = Zmap.add v repr localRep.ValReprs}
+
+ member localRep.ValNowWithRepresentation (v: Val) =
+ {localRep with ValsWithRepresentation = Zset.add v localRep.ValsWithRepresentation}
+
+ member localRep.IsValWithRepresentation (v: Val) =
+ localRep.ValsWithRepresentation.Contains v
+
+ member localRep.IsValRepresentedAsLocalVar (v: Val) =
+ match localRep.LookupRepr v with
+ | InVar false -> true
+ | _ -> false
+
+ member localRep.IsValRepresentedAsMethod (v: Val) =
+ localRep.IsValWithRepresentation v &&
+ match localRep.LookupRepr v with
+ | InMethod _ -> true
+ | _ -> false
+
+ /// Make the elaborated expression that represents a use of a
+ /// a "let v = ..." class binding
+ member localRep.MakeValueLookup thisValOpt tinst safeStaticInitInfo v tyargs m =
+ let g = localRep.RepInfoTcGlobals
+ match localRep.LookupRepr v, thisValOpt with
+ | InVar _, _ ->
+ exprForVal m v
+ | InField(false, _idx, rfref), Some thisVal ->
+ let thise = exprForVal m thisVal
+ mkRecdFieldGetViaExprAddr (thise, rfref, tinst, m)
+ | InField(false, _idx, _rfref), None ->
+ error(InternalError("Unexpected missing 'this' variable in MakeValueLookup", m))
+ | InField(true, idx, rfref), _ ->
+ let expr = mkStaticRecdFieldGet (rfref, tinst, m)
+ MakeCheckSafeInit g tinst safeStaticInitInfo (mkInt g m idx) expr
+
+ | InMethod(isStatic, methodVal, topValInfo), _ ->
+ //dprintfn "Rewriting application of %s to be call to method %s" v.LogicalName methodVal.LogicalName
+ let expr, exprty = AdjustValForExpectedArity g m (mkLocalValRef methodVal) NormalValUse topValInfo
+ // Prepend the the type arguments for the class
+ let tyargs = tinst @ tyargs
+ let thisArgs =
+ if isStatic then []
+ else Option.toList (Option.map (exprForVal m) thisValOpt)
+
+ MakeApplicationAndBetaReduce g (expr, exprty, [tyargs], thisArgs, m)
+
+ /// Make the elaborated expression that represents an assignment
+ /// to a "let mutable v = ..." class binding
+ member localRep.MakeValueAssign thisValOpt tinst safeStaticInitInfo v expr m =
+ let g = localRep.RepInfoTcGlobals
+ match localRep.LookupRepr v, thisValOpt with
+ | InField(false, _, rfref), Some thisVal ->
+ let thise = exprForVal m thisVal
+ mkRecdFieldSetViaExprAddr(thise, rfref, tinst, expr, m)
+ | InField(false, _, _rfref), None ->
+ error(InternalError("Unexpected missing 'this' variable in MakeValueAssign", m))
+ | InVar _, _ ->
+ mkValSet m (mkLocalValRef v) expr
+ | InField (true, idx, rfref), _ ->
+ let expr = mkStaticRecdFieldSet(rfref, tinst, expr, m)
+ MakeCheckSafeInit g tinst safeStaticInitInfo (mkInt g m idx) expr
+ | InMethod _, _ ->
+ error(InternalError("Local was given method storage, yet later it's been assigned to", m))
+
+ member localRep.MakeValueGetAddress readonly thisValOpt tinst safeStaticInitInfo v m =
+ let g = localRep.RepInfoTcGlobals
+ match localRep.LookupRepr v, thisValOpt with
+ | InField(false, _, rfref), Some thisVal ->
+ let thise = exprForVal m thisVal
+ mkRecdFieldGetAddrViaExprAddr(readonly, thise, rfref, tinst, m)
+ | InField(false, _, _rfref), None ->
+ error(InternalError("Unexpected missing 'this' variable in MakeValueGetAddress", m))
+ | InField(true, idx, rfref), _ ->
+ let expr = mkStaticRecdFieldGetAddr(readonly, rfref, tinst, m)
+ MakeCheckSafeInit g tinst safeStaticInitInfo (mkInt g m idx) expr
+ | InVar _, _ ->
+ mkValAddr m readonly (mkLocalValRef v)
+ | InMethod _, _ ->
+ error(InternalError("Local was given method storage, yet later it's address was required", m))
+
+ /// Mutate a type definition by adding fields
+ /// Used as part of processing "let" bindings in a type definition.
+ member localRep.PublishIncrClassFields (cenv, denv, cpath, ctorInfo: IncrClassCtorLhs, safeStaticInitInfo) =
+ let tcref = ctorInfo.TyconRef
+ let rfspecs =
+ [ for KeyValue(v, repr) in localRep.ValReprs do
+ match repr with
+ | InField(isStatic, _, rfref) ->
+ // Instance fields for structs are published earlier because the full set of fields is determined syntactically from the implicit
+ // constructor arguments. This is important for the "default value" and "does it have an implicit default constructor"
+ // semantic conditions for structs - see bug FSharp 1.0 5304.
+ if isStatic || not tcref.IsFSharpStructOrEnumTycon then
+ let ctorDeclaredTypars = ctorInfo.GetNormalizedInstanceCtorDeclaredTypars cenv denv ctorInfo.TyconRef.Range
+
+ // Note: tcrefObjTy contains the original "formal" typars, thisTy is the "fresh" one... f<>fresh.
+ let revTypeInst = List.zip ctorDeclaredTypars (tcref.TyparsNoRange |> List.map mkTyparTy)
+
+ yield MakeIncrClassField(localRep.RepInfoTcGlobals, cpath, revTypeInst, v, isStatic, rfref)
+ | _ ->
+ ()
+ match safeStaticInitInfo with
+ | SafeInitField (_, fld) -> yield fld
+ | NoSafeInitInfo -> () ]
+
+ let recdFields = Construct.MakeRecdFieldsTable (rfspecs @ tcref.AllFieldsAsList)
+
+ // Mutate the entity_tycon_repr to publish the fields
+ tcref.Deref.entity_tycon_repr <- TFSharpObjectRepr { tcref.FSharpObjectModelTypeInfo with fsobjmodel_rfields = recdFields}
+
+
+ /// Given localRep saying how locals have been represented, e.g. as fields.
+ /// Given an expr under a given thisVal context.
+ //
+ /// Fix up the references to the locals, e.g.
+ /// v -> this.fieldv
+ /// f x -> this.method x
+ member localRep.FixupIncrClassExprPhase2C cenv thisValOpt safeStaticInitInfo (thisTyInst: TypeInst) expr =
+ // fixup: intercept and expr rewrite
+ let FixupExprNode rw e =
+ //dprintfn "Fixup %s" (showL (exprL e))
+ let g = localRep.RepInfoTcGlobals
+ let e = NormalizeAndAdjustPossibleSubsumptionExprs g e
+ match e with
+ // Rewrite references to applied let-bound-functions-compiled-as-methods
+ // Rewrite references to applied recursive let-bound-functions-compiled-as-methods
+ // Rewrite references to applied recursive generic let-bound-functions-compiled-as-methods
+ | Expr.App (Expr.Val (ValDeref v, _, _), _, tyargs, args, m)
+ | Expr.App (Expr.Link {contents = Expr.Val (ValDeref v, _, _) }, _, tyargs, args, m)
+ | Expr.App (Expr.Link {contents = Expr.App (Expr.Val (ValDeref v, _, _), _, tyargs, [], _) }, _, [], args, m)
+ when localRep.IsValRepresentedAsMethod v && not (cenv.recUses.ContainsKey v) ->
+
+ let expr = localRep.MakeValueLookup thisValOpt thisTyInst safeStaticInitInfo v tyargs m
+ let args = args |> List.map rw
+ Some (MakeApplicationAndBetaReduce g (expr, (tyOfExpr g expr), [], args, m))
+
+ // Rewrite references to values stored as fields and first class uses of method values
+ | Expr.Val (ValDeref v, _, m)
+ when localRep.IsValWithRepresentation v ->
+
+ //dprintfn "Found use of %s" v.LogicalName
+ Some (localRep.MakeValueLookup thisValOpt thisTyInst safeStaticInitInfo v [] m)
+
+ // Rewrite assignments to mutable values stored as fields
+ | Expr.Op (TOp.LValueOp (LSet, ValDeref v), [], [arg], m)
+ when localRep.IsValWithRepresentation v ->
+ let arg = rw arg
+ Some (localRep.MakeValueAssign thisValOpt thisTyInst safeStaticInitInfo v arg m)
+
+ // Rewrite taking the address of mutable values stored as fields
+ | Expr.Op (TOp.LValueOp (LAddrOf readonly, ValDeref v), [], [], m)
+ when localRep.IsValWithRepresentation v ->
+ Some (localRep.MakeValueGetAddress readonly thisValOpt thisTyInst safeStaticInitInfo v m)
+
+ | _ -> None
+ RewriteExpr { PreIntercept = Some FixupExprNode
+ PostTransform = (fun _ -> None)
+ PreInterceptBinding = None
+ IsUnderQuotations=true } expr
+
+
+ type IncrClassConstructionBindingsPhase2C =
+ | Phase2CBindings of IncrClassBindingGroup list
+ | Phase2CCtorJustAfterSuperInit
+ | Phase2CCtorJustAfterLastLet
+
+ /// Given a set of 'let' bindings (static or not, recursive or not) that make up a class,
+ /// generate their initialization expression(s).
+ let MakeCtorForIncrClassConstructionPhase2C
+ (cenv: cenv,
+ env: TcEnv,
+ /// The lhs information about the implicit constructor
+ ctorInfo: IncrClassCtorLhs,
+ /// The call to the super class constructor
+ inheritsExpr,
+ /// Should we place a sequence point at the 'inheritedTys call?
+ inheritsIsVisible,
+ /// The declarations
+ decs: IncrClassConstructionBindingsPhase2C list,
+ memberBinds: Binding list,
+ /// Record any unconstrained type parameters generalized for the outer members as "free choices" in the let bindings
+ generalizedTyparsForRecursiveBlock,
+ safeStaticInitInfo: SafeInitData) =
+
+
+ let denv = env.DisplayEnv
+ let g = cenv.g
+ let thisVal = ctorInfo.InstanceCtorThisVal
+
+ let m = thisVal.Range
+ let ctorDeclaredTypars = ctorInfo.GetNormalizedInstanceCtorDeclaredTypars cenv denv m
+
+ ctorDeclaredTypars |> List.iter (SetTyparRigid env.DisplayEnv m)
+
+ // Reconstitute the type with the correct quantified type variables.
+ ctorInfo.InstanceCtorVal.SetType (mkForallTyIfNeeded ctorDeclaredTypars ctorInfo.InstanceCtorVal.TauType)
+
+ let freeChoiceTypars = ListSet.subtract typarEq generalizedTyparsForRecursiveBlock ctorDeclaredTypars
+
+ let thisTyInst = List.map mkTyparTy ctorDeclaredTypars
+
+ let accFreeInExpr acc expr =
+ unionFreeVars acc (freeInExpr CollectLocalsNoCaching expr)
+
+ let accFreeInBinding acc (bind: Binding) =
+ accFreeInExpr acc bind.Expr
+
+ let accFreeInBindings acc (binds: Binding list) =
+ (acc, binds) ||> List.fold accFreeInBinding
+
+ // Find all the variables used in any method. These become fields.
+ // staticForcedFieldVars: FreeLocals: the vars forced to be fields due to static member bindings, instance initialization expressions or instance member bindings
+ // instanceForcedFieldVars: FreeLocals: the vars forced to be fields due to instance member bindings
+
+ let staticForcedFieldVars, instanceForcedFieldVars =
+ let (staticForcedFieldVars, instanceForcedFieldVars) =
+ ((emptyFreeVars, emptyFreeVars), decs) ||> List.fold (fun (staticForcedFieldVars, instanceForcedFieldVars) dec ->
+ match dec with
+ | Phase2CCtorJustAfterLastLet
+ | Phase2CCtorJustAfterSuperInit ->
+ (staticForcedFieldVars, instanceForcedFieldVars)
+ | Phase2CBindings decs ->
+ ((staticForcedFieldVars, instanceForcedFieldVars), decs) ||> List.fold (fun (staticForcedFieldVars, instanceForcedFieldVars) dec ->
+ match dec with
+ | IncrClassBindingGroup(binds, isStatic, _) ->
+ let methodBinds = binds |> List.filter (IncrClassReprInfo.IsMethodRepr cenv)
+ let staticForcedFieldVars =
+ if isStatic then
+ // Any references to static variables in any static method force the variable to be represented as a field
+ (staticForcedFieldVars, methodBinds) ||> accFreeInBindings
+ else
+ // Any references to static variables in any instance bindings force the variable to be represented as a field
+ (staticForcedFieldVars, binds) ||> accFreeInBindings
+
+ let instanceForcedFieldVars =
+ // Any references to instance variables in any methods force the variable to be represented as a field
+ (instanceForcedFieldVars, methodBinds) ||> accFreeInBindings
+
+ (staticForcedFieldVars, instanceForcedFieldVars)
+ | IncrClassDo (e, isStatic) ->
+ let staticForcedFieldVars =
+ if isStatic then
+ staticForcedFieldVars
+ else
+ unionFreeVars staticForcedFieldVars (freeInExpr CollectLocalsNoCaching e)
+ (staticForcedFieldVars, instanceForcedFieldVars)))
+ let staticForcedFieldVars = (staticForcedFieldVars, memberBinds) ||> accFreeInBindings
+ let instanceForcedFieldVars = (instanceForcedFieldVars, memberBinds) ||> accFreeInBindings
+
+ // Any references to static variables in the 'inherits' expression force those static variables to be represented as fields
+ let staticForcedFieldVars = (staticForcedFieldVars, inheritsExpr) ||> accFreeInExpr
+
+ (staticForcedFieldVars.FreeLocals, instanceForcedFieldVars.FreeLocals)
+
+
+ // Compute the implicit construction side effects of single
+ // 'let' or 'let rec' binding in the implicit class construction sequence
+ let TransBind (reps: IncrClassReprInfo) (TBind(v, rhsExpr, spBind)) =
+ if v.MustInline then
+ error(Error(FSComp.SR.tcLocalClassBindingsCannotBeInline(), v.Range))
+ let rhsExpr = reps.FixupIncrClassExprPhase2C cenv (Some thisVal) safeStaticInitInfo thisTyInst rhsExpr
+
+ // The initialization of the 'ref cell' variable for 'this' is the only binding which comes prior to the super init
+ let isPriorToSuperInit =
+ match ctorInfo.InstanceCtorSafeThisValOpt with
+ | None -> false
+ | Some v2 -> valEq v v2
+
+ match reps.LookupRepr v with
+ | InMethod(isStatic, methodVal, _) ->
+ let _, chooseTps, tauExpr, tauTy, m =
+ match rhsExpr with
+ | Expr.TyChoose (chooseTps, b, _) -> [], chooseTps, b, (tyOfExpr g b), m
+ | Expr.TyLambda (_, tps, Expr.TyChoose (chooseTps, b, _), m, returnTy) -> tps, chooseTps, b, returnTy, m
+ | Expr.TyLambda (_, tps, b, m, returnTy) -> tps, [], b, returnTy, m
+ | e -> [], [], e, (tyOfExpr g e), e.Range
+
+ let chooseTps = chooseTps @ (ListSet.subtract typarEq freeChoiceTypars methodVal.Typars)
+
+ // Add the 'this' variable as an argument
+ let tauExpr, tauTy =
+ if isStatic then
+ tauExpr, tauTy
+ else
+ let e = mkLambda m thisVal (tauExpr, tauTy)
+ e, tyOfExpr g e
+
+ // Replace the type parameters that used to be on the rhs with
+ // the full set of type parameters including the type parameters of the enclosing class
+ let rhsExpr = mkTypeLambda m methodVal.Typars (mkTypeChoose m chooseTps tauExpr, tauTy)
+ (isPriorToSuperInit, (fun e -> e)), [TBind (methodVal, rhsExpr, spBind)]
+
+ // If it's represented as a non-escaping local variable then just bind it to its value
+ // If it's represented as a non-escaping local arg then no binding necessary (ctor args are already bound)
+
+ | InVar isArg ->
+ (isPriorToSuperInit, (fun e -> if isArg then e else mkLetBind m (TBind(v, rhsExpr, spBind)) e)), []
+
+ | InField (isStatic, idx, _) ->
+ // Use spBind if it available as the span for the assignment into the field
+ let m =
+ match spBind, rhsExpr with
+ // Don't generate big sequence points for functions in classes
+ | _, (Expr.Lambda _ | Expr.TyLambda _) -> v.Range
+ | DebugPointAtBinding m, _ -> m
+ | _ -> v.Range
+ let assignExpr = reps.MakeValueAssign (Some thisVal) thisTyInst NoSafeInitInfo v rhsExpr m
+ let adjustSafeInitFieldExprOpt =
+ if isStatic then
+ match safeStaticInitInfo with
+ | SafeInitField (rfref, _) ->
+ let setExpr = mkStaticRecdFieldSet (rfref, thisTyInst, mkInt g m idx, m)
+ let setExpr = reps.FixupIncrClassExprPhase2C cenv (Some thisVal) NoSafeInitInfo thisTyInst setExpr
+ Some setExpr
+ | NoSafeInitInfo ->
+ None
+ else
+ None
+
+ (isPriorToSuperInit, (fun e ->
+ let e = match adjustSafeInitFieldExprOpt with None -> e | Some ae -> mkCompGenSequential m ae e
+ mkSequential DebugPointAtSequential.Both m assignExpr e)), []
+
+ /// Work out the implicit construction side effects of a 'let', 'let rec' or 'do'
+ /// binding in the implicit class construction sequence
+ let TransTrueDec isCtorArg (reps: IncrClassReprInfo) dec =
+ match dec with
+ | (IncrClassBindingGroup(binds, isStatic, isRec)) ->
+ let actions, reps, methodBinds =
+ let reps = (reps, binds) ||> List.fold (fun rep bind -> rep.ChooseAndAddRepresentation(cenv, env, isStatic, isCtorArg, ctorInfo, staticForcedFieldVars, instanceForcedFieldVars, bind)) // extend
+ if isRec then
+ // Note: the recursive calls are made via members on the object
+ // or via access to fields. This means the recursive loop is "broken",
+ // and we can collapse to sequential bindings
+ let reps = (reps, binds) ||> List.fold (fun rep bind -> rep.ValNowWithRepresentation bind.Var) // in scope before
+ let actions, methodBinds = binds |> List.map (TransBind reps) |> List.unzip // since can occur in RHS of own defns
+ actions, reps, methodBinds
+ else
+ let actions, methodBinds = binds |> List.map (TransBind reps) |> List.unzip
+ let reps = (reps, binds) ||> List.fold (fun rep bind -> rep.ValNowWithRepresentation bind.Var) // in scope after
+ actions, reps, methodBinds
+ let methodBinds = List.concat methodBinds
+ if isStatic then
+ (actions, [], methodBinds), reps
+ else
+ ([], actions, methodBinds), reps
+
+ | IncrClassDo (doExpr, isStatic) ->
+ let doExpr = reps.FixupIncrClassExprPhase2C cenv (Some thisVal) safeStaticInitInfo thisTyInst doExpr
+ let binder = (fun e -> mkSequential DebugPointAtSequential.Both doExpr.Range doExpr e)
+ let isPriorToSuperInit = false
+ if isStatic then
+ ([(isPriorToSuperInit, binder)], [], []), reps
+ else
+ ([], [(isPriorToSuperInit, binder)], []), reps
+
+
+ /// Work out the implicit construction side effects of each declaration
+ /// in the implicit class construction sequence
+ let TransDec (reps: IncrClassReprInfo) dec =
+ match dec with
+ // The call to the base class constructor is done so we can set the ref cell
+ | Phase2CCtorJustAfterSuperInit ->
+ let binders =
+ [ match ctorInfo.InstanceCtorSafeThisValOpt with
+ | None -> ()
+ | Some v ->
+ let setExpr = mkRefCellSet g m ctorInfo.InstanceCtorThisVal.Type (exprForVal m v) (exprForVal m ctorInfo.InstanceCtorThisVal)
+ let setExpr = reps.FixupIncrClassExprPhase2C cenv (Some thisVal) safeStaticInitInfo thisTyInst setExpr
+ let binder = (fun e -> mkSequential DebugPointAtSequential.Both setExpr.Range setExpr e)
+ let isPriorToSuperInit = false
+ yield (isPriorToSuperInit, binder) ]
+
+ ([], binders, []), reps
+
+ // The last 'let' binding is done so we can set the initialization condition for the collection of object fields
+ // which now allows members to be called.
+ | Phase2CCtorJustAfterLastLet ->
+ let binders =
+ [ match ctorInfo.InstanceCtorSafeInitInfo with
+ | SafeInitField (rfref, _) ->
+ let setExpr = mkRecdFieldSetViaExprAddr (exprForVal m thisVal, rfref, thisTyInst, mkOne g m, m)
+ let setExpr = reps.FixupIncrClassExprPhase2C cenv (Some thisVal) safeStaticInitInfo thisTyInst setExpr
+ let binder = (fun e -> mkSequential DebugPointAtSequential.Both setExpr.Range setExpr e)
+ let isPriorToSuperInit = false
+ yield (isPriorToSuperInit, binder)
+ | NoSafeInitInfo ->
+ () ]
+
+ ([], binders, []), reps
+
+ | Phase2CBindings decs ->
+ let initActions, reps = List.mapFold (TransTrueDec false) reps decs
+ let cctorInitActions, ctorInitActions, methodBinds = List.unzip3 initActions
+ (List.concat cctorInitActions, List.concat ctorInitActions, List.concat methodBinds), reps
+
+
+
+ let takenFieldNames =
+ [ for b in memberBinds do
+ yield b.Var.CompiledName cenv.g.CompilerGlobalState
+ yield b.Var.DisplayName
+ yield b.Var.CoreDisplayName
+ yield b.Var.LogicalName ]
+ let reps = IncrClassReprInfo.Empty(g, takenFieldNames)
+
+ // Bind the IsArg(true) representations of the object constructor arguments and assign them to fields
+ // if they escape to the members. We do this by running the instance bindings 'let x = x' through TransTrueDec
+ // for each constructor argument 'x', but with the special flag 'isCtorArg', which helps TransBind know that
+ // the value is already available as an argument, and that nothing special needs to be done unless the
+ // value is being stored into a field.
+ let (cctorInitActions1, ctorInitActions1, methodBinds1), reps =
+ let binds = ctorInfo.InstanceCtorArgs |> List.map (fun v -> mkInvisibleBind v (exprForVal v.Range v))
+ TransTrueDec true reps (IncrClassBindingGroup(binds, false, false))
+
+ // We expect that only ctorInitActions1 will be non-empty here, and even then only if some elements are stored in the field
+ assert (isNil cctorInitActions1)
+ assert (isNil methodBinds1)
+
+ // Now deal with all the 'let' and 'member' declarations
+ let initActions, reps = List.mapFold TransDec reps decs
+ let cctorInitActions2, ctorInitActions2, methodBinds2 = List.unzip3 initActions
+ let cctorInitActions = cctorInitActions1 @ List.concat cctorInitActions2
+ let ctorInitActions = ctorInitActions1 @ List.concat ctorInitActions2
+ let methodBinds = methodBinds1 @ List.concat methodBinds2
+
+ let ctorBody =
+ // Build the elements of the implicit constructor body, starting from the bottom
+ //
+ //
+ //
+ // return ()
+ let ctorInitActionsPre, ctorInitActionsPost = ctorInitActions |> List.partition (fun (isPriorToSuperInit, _) -> isPriorToSuperInit)
+
+ // This is the return result
+ let ctorBody = mkUnit g m
+
+ // Add .
+ // That is, add any that come prior to the super init constructor call,
+ // This is only ever at most the init of the InstanceCtorSafeThisValOpt and InstanceCtorSafeInitInfo var/field
+ let ctorBody = List.foldBack (fun (_, binder) acc -> binder acc) ctorInitActionsPost ctorBody
+
+ // Add the
+ let ctorBody =
+ // The inheritsExpr may refer to the this variable or to incoming arguments, e.g. in closure fields.
+ // References to the this variable go via the ref cell that gets created to help ensure coherent initialization.
+ // This ref cell itself may be stored in a field of the object and accessed via arg0.
+ // Likewise the incoming arguments will eventually be stored in fields and accessed via arg0.
+ //
+ // As a result, the most natural way to implement this would be to simply capture arg0 if needed
+ // and access all variables via that. This would be done by rewriting the inheritsExpr as follows:
+ // let inheritsExpr = reps.FixupIncrClassExprPhase2C (Some thisVal) thisTyInst inheritsExpr
+ // However, the rules of IL mean we are not actually allowed to capture arg0
+ // and store it as a closure field before the base class constructor is called.
+ //
+ // As a result we do not rewrite the inheritsExpr and instead
+ // (a) wrap a let binding for the ref cell around the inheritsExpr if needed
+ // (b) rely on the fact that the input arguments are in scope and can be accessed from as argument variables
+ // (c) rely on the fact that there are no 'let' bindings prior to the inherits expr.
+ let inheritsExpr =
+ match ctorInfo.InstanceCtorSafeThisValOpt with
+ | Some v when not (reps.IsValRepresentedAsLocalVar v) ->
+ // Rewrite the expression to convert it to a load of a field if needed.
+ // We are allowed to load fields from our own object even though we haven't called
+ // the super class constructor yet.
+ let ldexpr = reps.FixupIncrClassExprPhase2C cenv (Some thisVal) safeStaticInitInfo thisTyInst (exprForVal m v)
+ mkInvisibleLet m v ldexpr inheritsExpr
+ | _ ->
+ inheritsExpr
+
+ let spAtSuperInit = (if inheritsIsVisible then DebugPointAtSequential.Both else DebugPointAtSequential.StmtOnly)
+ mkSequential spAtSuperInit m inheritsExpr ctorBody
+
+ // Add the normal
+ let ctorBody = List.foldBack (fun (_, binder) acc -> binder acc) ctorInitActionsPre ctorBody
+
+ // Add the final wrapping to make this into a method
+ let ctorBody = mkMemberLambdas m [] (Some thisVal) ctorInfo.InstanceCtorBaseValOpt [ctorInfo.InstanceCtorArgs] (ctorBody, g.unit_ty)
+
+ ctorBody
+
+ let cctorBodyOpt =
+ /// Omit the .cctor if it's empty
+ match cctorInitActions with
+ | [] -> None
+ | _ ->
+ let cctorInitAction = List.foldBack (fun (_, binder) acc -> binder acc) cctorInitActions (mkUnit g m)
+ let m = thisVal.Range
+ let cctorArgs, cctorVal, _ = ctorInfo.StaticCtorValInfo.Force()
+ // Reconstitute the type of the implicit class constructor with the correct quantified type variables.
+ cctorVal.SetType (mkForallTyIfNeeded ctorDeclaredTypars cctorVal.TauType)
+ let cctorBody = mkMemberLambdas m [] None None [cctorArgs] (cctorInitAction, g.unit_ty)
+ Some cctorBody
+
+ ctorBody, cctorBodyOpt, methodBinds, reps
+
+// Checking of mutually recursive types, members and 'let' bindings in classes
+//
+// Technique: multiple passes.
+// Phase1: create and establish type definitions and core representation information
+// Phase2A: create Vals for recursive items given names and args
+// Phase2B-D: type check AST to TAST collecting (sufficient) type constraints,
+// generalize definitions, fix up recursive instances, build ctor binding
+module MutRecBindingChecking =
+
+ open IncrClassChecking
+
+ /// Represents one element in a type definition, after the first phase
+ type TyconBindingPhase2A =
+ /// An entry corresponding to the definition of the implicit constructor for a class
+ | Phase2AIncrClassCtor of IncrClassCtorLhs
+ /// An 'inherit' declaration in an incremental class
+ ///
+ /// Phase2AInherit (ty, arg, baseValOpt, m)
+ | Phase2AInherit of SynType * SynExpr * Val option * range
+ /// A set of value or function definitions in an incremental class
+ ///
+ /// Phase2AIncrClassBindings (tcref, letBinds, isStatic, isRec, m)
+ | Phase2AIncrClassBindings of TyconRef * SynBinding list * bool * bool * range
+ /// A 'member' definition in a class
+ | Phase2AMember of PreCheckingRecursiveBinding
+#if OPEN_IN_TYPE_DECLARATIONS
+ /// A dummy declaration, should we ever support 'open' in type definitions
+ | Phase2AOpen of SynOpenDeclTarget * range
+#endif
+ /// Indicates the super init has just been called, 'this' may now be published
+ | Phase2AIncrClassCtorJustAfterSuperInit
+ /// Indicates the last 'field' has been initialized, only 'do' comes after
+ | Phase2AIncrClassCtorJustAfterLastLet
+
+ /// The collected syntactic input definitions for a single type or type-extension definition
+ type TyconBindingsPhase2A =
+ | TyconBindingsPhase2A of Tycon option * DeclKind * Val list * TyconRef * Typar list * TType * TyconBindingPhase2A list
+
+ /// The collected syntactic input definitions for a recursive group of type or type-extension definitions
+ type MutRecDefnsPhase2AData = MutRecShape list
+
+ /// Represents one element in a type definition, after the second phase
+ type TyconBindingPhase2B =
+ | Phase2BIncrClassCtor of IncrClassCtorLhs * Binding option
+ | Phase2BInherit of Expr * Val option
+ /// A set of value of function definitions in a class definition with an implicit constructor.
+ | Phase2BIncrClassBindings of IncrClassBindingGroup list
+ | Phase2BMember of int
+ /// An intermediate definition that represent the point in an implicit class definition where
+ /// the super type has been initialized.
+ | Phase2BIncrClassCtorJustAfterSuperInit
+ /// An intermediate definition that represent the point in an implicit class definition where
+ /// the last 'field' has been initialized, i.e. only 'do' and 'member' definitions come after
+ /// this point.
+ | Phase2BIncrClassCtorJustAfterLastLet
+
+ type TyconBindingsPhase2B = TyconBindingsPhase2B of Tycon option * TyconRef * TyconBindingPhase2B list
+
+ type MutRecDefnsPhase2BData = MutRecShape list
+
+ /// Represents one element in a type definition, after the third phase
+ type TyconBindingPhase2C =
+ | Phase2CIncrClassCtor of IncrClassCtorLhs * Binding option
+ | Phase2CInherit of Expr * Val option
+ | Phase2CIncrClassBindings of IncrClassBindingGroup list
+ | Phase2CMember of PreInitializationGraphEliminationBinding
+ // Indicates the last 'field' has been initialized, only 'do' comes after
+ | Phase2CIncrClassCtorJustAfterSuperInit
+ | Phase2CIncrClassCtorJustAfterLastLet
+
+ type TyconBindingsPhase2C = TyconBindingsPhase2C of Tycon option * TyconRef * TyconBindingPhase2C list
+
+ type MutRecDefnsPhase2CData = MutRecShape list
+
+ // Phase2A: create member prelimRecValues for "recursive" items, i.e. ctor val and member vals
+ // Phase2A: also processes their arg patterns - collecting type assertions
+ let TcMutRecBindings_Phase2A_CreateRecursiveValuesAndCheckArgumentPatterns (cenv: cenv) tpenv (envMutRec, mutRecDefns: MutRecDefnsPhase2Info) =
+ let g = cenv.g
+
+ // The basic iteration over the declarations in a single type definition
+ // State:
+ // tpenv: floating type parameter environment
+ // recBindIdx: index of the recursive binding
+ // prelimRecValuesRev: accumulation of prelim value entries
+ // uncheckedBindsRev: accumulation of unchecked bindings
+ let (defnsAs: MutRecDefnsPhase2AData), (tpenv, _, uncheckedBindsRev) =
+ let initialOuterState = (tpenv, 0, ([]: PreCheckingRecursiveBinding list))
+ (initialOuterState, envMutRec, mutRecDefns) |||> MutRecShapes.mapFoldWithEnv (fun outerState envForDecls defn ->
+ let (tpenv, recBindIdx, uncheckedBindsRev) = outerState
+ match defn with
+ | MutRecShape.Module _ -> failwith "unreachable"
+ | MutRecShape.Open x -> MutRecShape.Open x, outerState
+ | MutRecShape.ModuleAbbrev x -> MutRecShape.ModuleAbbrev x, outerState
+ | MutRecShape.Lets recBinds ->
+ let normRecDefns =
+ [ for (RecDefnBindingInfo(a, b, c, bind)) in recBinds do
+ yield NormalizedRecBindingDefn(a, b, c, BindingNormalization.NormalizeBinding ValOrMemberBinding cenv envForDecls bind) ]
+ let bindsAndValues, (tpenv, recBindIdx) = ((tpenv, recBindIdx), normRecDefns) ||> List.mapFold (AnalyzeAndMakeAndPublishRecursiveValue ErrorOnOverrides false cenv envForDecls)
+ let binds = bindsAndValues |> List.collect fst
+
+ let defnAs = MutRecShape.Lets binds
+ defnAs, (tpenv, recBindIdx, List.rev binds @ uncheckedBindsRev)
+
+ | MutRecShape.Tycon (MutRecDefnsPhase2InfoForTycon(tyconOpt, tcref, declaredTyconTypars, declKind, binds, _)) ->
+
+ // Class members can access protected members of the implemented type
+ // Class members can access private members in the ty
+ let isExtrinsic = (declKind = ExtrinsicExtensionBinding)
+ let initialEnvForTycon = MakeInnerEnvForTyconRef envForDecls tcref isExtrinsic
+
+ // Re-add the type constructor to make it take precedence for record label field resolutions
+ // This does not apply to extension members: in those cases the relationship between the record labels
+ // and the type is too extruded
+ let envForTycon =
+ if isExtrinsic then
+ initialEnvForTycon
+ else
+ AddLocalTyconRefs true g cenv.amap tcref.Range [tcref] initialEnvForTycon
+
+ // Make fresh version of the class type for type checking the members and lets *
+ let _, copyOfTyconTypars, _, objTy, thisTy = FreshenObjectArgType cenv tcref.Range TyparRigidity.WillBeRigid tcref isExtrinsic declaredTyconTypars
+
+
+ // The basic iteration over the declarations in a single type definition
+ let initialInnerState = (None, envForTycon, tpenv, recBindIdx, uncheckedBindsRev)
+ let defnAs, (_, _envForTycon, tpenv, recBindIdx, uncheckedBindsRev) =
+
+ (initialInnerState, binds) ||> List.collectFold (fun innerState defn ->
+
+ let (TyconBindingDefn(containerInfo, newslotsOK, declKind, classMemberDef, m)) = defn
+ let (incrClassCtorLhsOpt, envForTycon, tpenv, recBindIdx, uncheckedBindsRev) = innerState
+
+ if tcref.IsTypeAbbrev then
+ // ideally we'd have the 'm' of the type declaration stored here, to avoid needing to trim to line to approx
+ error(Error(FSComp.SR.tcTypeAbbreviationsMayNotHaveMembers(), (trimRangeToLine m)))
+
+ if tcref.IsEnumTycon && (declKind <> ExtrinsicExtensionBinding) then
+ // ideally we'd have the 'm' of the type declaration stored here, to avoid needing to trim to line to approx
+ error(Error(FSComp.SR.tcEnumerationsMayNotHaveMembers(), (trimRangeToLine m)))
+
+ match classMemberDef, containerInfo with
+ | SynMemberDefn.ImplicitCtor (vis, Attributes attrs, SynSimplePats.SimplePats(spats, _), thisIdOpt, doc, m), ContainerInfo(_, Some(MemberOrValContainerInfo(tcref, _, baseValOpt, safeInitInfo, _))) ->
+ if tcref.TypeOrMeasureKind = TyparKind.Measure then
+ error(Error(FSComp.SR.tcMeasureDeclarationsRequireStaticMembers(), m))
+
+ // Phase2A: make incrClassCtorLhs - ctorv, thisVal etc, type depends on argty(s)
+ let incrClassCtorLhs = TcImplicitCtorLhs_Phase2A(cenv, envForTycon, tpenv, tcref, vis, attrs, spats, thisIdOpt, baseValOpt, safeInitInfo, m, copyOfTyconTypars, objTy, thisTy, doc)
+ // Phase2A: Add copyOfTyconTypars from incrClassCtorLhs - or from tcref
+ let envForTycon = AddDeclaredTypars CheckForDuplicateTypars incrClassCtorLhs.InstanceCtorDeclaredTypars envForTycon
+ let innerState = (Some incrClassCtorLhs, envForTycon, tpenv, recBindIdx, uncheckedBindsRev)
+
+ [Phase2AIncrClassCtor incrClassCtorLhs], innerState
+
+ | SynMemberDefn.ImplicitInherit (ty, arg, _baseIdOpt, m), _ ->
+ if tcref.TypeOrMeasureKind = TyparKind.Measure then
+ error(Error(FSComp.SR.tcMeasureDeclarationsRequireStaticMembers(), m))
+
+ // Phase2A: inherit ty(arg) as base - pass through
+ // Phase2A: pick up baseValOpt!
+ let baseValOpt = incrClassCtorLhsOpt |> Option.bind (fun x -> x.InstanceCtorBaseValOpt)
+ let innerState = (incrClassCtorLhsOpt, envForTycon, tpenv, recBindIdx, uncheckedBindsRev)
+ [Phase2AInherit (ty, arg, baseValOpt, m); Phase2AIncrClassCtorJustAfterSuperInit], innerState
+
+ | SynMemberDefn.LetBindings (letBinds, isStatic, isRec, m), _ ->
+ match tcref.TypeOrMeasureKind, isStatic with
+ | TyparKind.Measure, false -> error(Error(FSComp.SR.tcMeasureDeclarationsRequireStaticMembers(), m))
+ | _ -> ()
+
+ if not isStatic && tcref.IsStructOrEnumTycon then
+ let allDo = letBinds |> List.forall (function (Binding(_, DoBinding, _, _, _, _, _, _, _, _, _, _)) -> true | _ -> false)
+ // Code for potential future design change to allow functions-compiled-as-members in structs
+ if allDo then
+ errorR(Deprecated(FSComp.SR.tcStructsMayNotContainDoBindings(), (trimRangeToLine m)))
+ else
+ // Code for potential future design change to allow functions-compiled-as-members in structs
+ errorR(Error(FSComp.SR.tcStructsMayNotContainLetBindings(), (trimRangeToLine m)))
+
+ if isStatic && Option.isNone incrClassCtorLhsOpt then
+ errorR(Error(FSComp.SR.tcStaticLetBindingsRequireClassesWithImplicitConstructors(), m))
+
+ // Phase2A: let-bindings - pass through
+ let innerState = (incrClassCtorLhsOpt, envForTycon, tpenv, recBindIdx, uncheckedBindsRev)
+ [Phase2AIncrClassBindings (tcref, letBinds, isStatic, isRec, m)], innerState
+
+ | SynMemberDefn.Member (bind, m), _ ->
+ // Phase2A: member binding - create prelim valspec (for recursive reference) and RecursiveBindingInfo
+ let (NormalizedBinding(_, _, _, _, _, _, _, valSynData, _, _, _, _)) as bind = BindingNormalization.NormalizeBinding ValOrMemberBinding cenv envForTycon bind
+ let (SynValData(memberFlagsOpt, _, _)) = valSynData
+ match tcref.TypeOrMeasureKind with
+ | TyparKind.Type -> ()
+ | TyparKind.Measure ->
+ match memberFlagsOpt with
+ | None -> ()
+ | Some memberFlags ->
+ if memberFlags.IsInstance then error(Error(FSComp.SR.tcMeasureDeclarationsRequireStaticMembers(), m))
+ match memberFlags.MemberKind with
+ | MemberKind.Constructor -> error(Error(FSComp.SR.tcMeasureDeclarationsRequireStaticMembersNotConstructors(), m))
+ | _ -> ()
+ let rbind = NormalizedRecBindingDefn(containerInfo, newslotsOK, declKind, bind)
+ let overridesOK = DeclKind.CanOverrideOrImplement declKind
+ let (binds, _values), (tpenv, recBindIdx) = AnalyzeAndMakeAndPublishRecursiveValue overridesOK false cenv envForTycon (tpenv, recBindIdx) rbind
+ let cbinds = [ for rbind in binds -> Phase2AMember rbind ]
+
+ let innerState = (incrClassCtorLhsOpt, envForTycon, tpenv, recBindIdx, List.rev binds @ uncheckedBindsRev)
+ cbinds, innerState
+
+#if OPEN_IN_TYPE_DECLARATIONS
+ | SynMemberDefn.Open (target, m), _ ->
+ let innerState = (incrClassCtorLhsOpt, env, tpenv, recBindIdx, prelimRecValuesRev, uncheckedBindsRev)
+ [ Phase2AOpen (target, m) ], innerState
+#endif
+
+ | definition ->
+ error(InternalError(sprintf "Unexpected definition %A" definition, m)))
+
+ // If no constructor call, insert Phase2AIncrClassCtorJustAfterSuperInit at start
+ let defnAs =
+ match defnAs with
+ | (Phase2AIncrClassCtor _ as b1) :: rest ->
+ let rest =
+ if rest |> List.exists (function Phase2AIncrClassCtorJustAfterSuperInit -> true | _ -> false) then
+ rest
+ else
+ Phase2AIncrClassCtorJustAfterSuperInit :: rest
+ // Insert Phase2AIncrClassCtorJustAfterLastLet at the point where local construction is known to have been finished
+ let rest =
+ let isAfter b =
+ match b with
+#if OPEN_IN_TYPE_DECLARATIONS
+ | Phase2AOpen _
+#endif
+ | Phase2AIncrClassCtor _ | Phase2AInherit _ | Phase2AIncrClassCtorJustAfterSuperInit -> false
+ | Phase2AIncrClassBindings (_, binds, _, _, _) -> binds |> List.exists (function (Binding (_, DoBinding, _, _, _, _, _, _, _, _, _, _)) -> true | _ -> false)
+ | Phase2AIncrClassCtorJustAfterLastLet
+ | Phase2AMember _ -> true
+ let restRev = List.rev rest
+ let afterRev = restRev |> List.takeWhile isAfter
+ let beforeRev = restRev |> List.skipWhile isAfter
+
+ [ yield! List.rev beforeRev
+ yield Phase2AIncrClassCtorJustAfterLastLet
+ yield! List.rev afterRev ]
+ b1 :: rest
+
+ // Cover the case where this is not a type with an implicit constructor.
+ | rest -> rest
+
+ let prelimRecValues = [ for x in defnAs do match x with Phase2AMember bind -> yield bind.RecBindingInfo.Val | _ -> () ]
+ let defnAs = MutRecShape.Tycon(TyconBindingsPhase2A(tyconOpt, declKind, prelimRecValues, tcref, copyOfTyconTypars, thisTy, defnAs))
+ defnAs, (tpenv, recBindIdx, uncheckedBindsRev))
+
+ let uncheckedRecBinds = List.rev uncheckedBindsRev
+
+ (defnsAs, uncheckedRecBinds, tpenv)
+
+ /// Phase2B: check each of the bindings, convert from ast to tast and collects type assertions.
+ /// Also generalize incrementally.
+ let TcMutRecBindings_Phase2B_TypeCheckAndIncrementalGeneralization (cenv: cenv) tpenv envInitial (envMutRec, defnsAs: MutRecDefnsPhase2AData, uncheckedRecBinds: PreCheckingRecursiveBinding list, scopem) : MutRecDefnsPhase2BData * _ * _ =
+ let g = cenv.g
+
+ let (defnsBs: MutRecDefnsPhase2BData), (tpenv, generalizedRecBinds, preGeneralizationRecBinds, _, _) =
+
+ let uncheckedRecBindsTable = uncheckedRecBinds |> List.map (fun rbind -> rbind.RecBindingInfo.Val.Stamp, rbind) |> Map.ofList
+
+ // Loop through the types being defined...
+ //
+ // The envNonRec is the environment used to limit generalization to prevent leakage of type
+ // variables into the types of 'let' bindings. It gets accumulated across type definitions, e.g.
+ // consider
+ //
+ // type A<'T>() =
+ // let someFuncValue: 'A = A<'T>.Meth2()
+ // static member Meth2() = A<'T>.Meth2()
+ // and B<'T>() =
+ // static member Meth1() = A<'T>.Meth2()
+ //
+ // Here 'A can't be generalized, even at 'Meth1'.
+ //
+ // The envForTycon is the environment used for name resolution within the let and member bindings
+ // of the type definition. This becomes 'envStatic' and 'envInstance' for the two
+
+ let initialOuterState = (tpenv, ([]: PostGeneralizationRecursiveBinding list), ([]: PreGeneralizationRecursiveBinding list), uncheckedRecBindsTable, envInitial)
+
+ (initialOuterState, envMutRec, defnsAs) |||> MutRecShapes.mapFoldWithEnv (fun outerState envForDecls defnsA ->
+
+ let (tpenv, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable, envNonRec) = outerState
+
+ match defnsA with
+ | MutRecShape.Module _ -> failwith "unreachable"
+ | MutRecShape.Open x -> MutRecShape.Open x, outerState
+ | MutRecShape.ModuleAbbrev x -> MutRecShape.ModuleAbbrev x, outerState
+ | MutRecShape.Lets binds ->
+
+ let defnBs, (tpenv, _, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable) =
+
+ let initialInnerState = (tpenv, envForDecls, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable)
+ (initialInnerState, binds) ||> List.mapFold (fun innerState rbind ->
+
+ let (tpenv, envStatic, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable) = innerState
+
+ let (envNonRec, generalizedRecBinds, preGeneralizationRecBinds, _, uncheckedRecBindsTable) =
+ TcLetrecBinding (cenv, envStatic, scopem, [], None) (envNonRec, generalizedRecBinds, preGeneralizationRecBinds, tpenv, uncheckedRecBindsTable) rbind
+
+ let innerState = (tpenv, envStatic, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable)
+ rbind.RecBindingInfo.Index, innerState)
+
+ let outerState = (tpenv, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable, envNonRec)
+ MutRecShape.Lets defnBs, outerState
+
+ | MutRecShape.Tycon (TyconBindingsPhase2A(tyconOpt, declKind, _, tcref, copyOfTyconTypars, thisTy, defnAs)) ->
+
+ let isExtrinsic = (declKind = ExtrinsicExtensionBinding)
+ let envForTycon = MakeInnerEnvForTyconRef envForDecls tcref isExtrinsic
+ let envForTycon = if isExtrinsic then envForTycon else AddLocalTyconRefs true g cenv.amap tcref.Range [tcref] envForTycon
+ // Set up the environment so use-before-definition warnings are given, at least
+ // until we reach a Phase2AIncrClassCtorJustAfterSuperInit.
+ let envForTycon = { envForTycon with eCtorInfo = Some (InitialImplicitCtorInfo()) }
+
+ let reqdThisValTyOpt = Some thisTy
+
+ // Loop through the definition elements in a type...
+ // State:
+ // envInstance: the environment in scope in instance members
+ // envStatic: the environment in scope in static members
+ // envNonRec: the environment relevant to generalization
+ // generalizedRecBinds: part of the incremental generalization state
+ // preGeneralizationRecBinds: part of the incremental generalization state
+ // uncheckedRecBindsTable: part of the incremental generalization state
+ let defnBs, (tpenv, _, _, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable) =
+
+ let initialInnerState = (tpenv, envForTycon, envForTycon, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable)
+ (initialInnerState, defnAs) ||> List.mapFold (fun innerState defnA ->
+
+ let (tpenv, envInstance, envStatic, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable) = innerState
+
+ match defnA with
+ // Phase2B for the definition of an implicit constructor. Enrich the instance environments
+ // with the implicit ctor args.
+ | Phase2AIncrClassCtor incrClassCtorLhs ->
+
+ let envInstance = AddDeclaredTypars CheckForDuplicateTypars incrClassCtorLhs.InstanceCtorDeclaredTypars envInstance
+ let envStatic = AddDeclaredTypars CheckForDuplicateTypars incrClassCtorLhs.InstanceCtorDeclaredTypars envStatic
+ let envInstance = match incrClassCtorLhs.InstanceCtorSafeThisValOpt with Some v -> AddLocalVal cenv.tcSink scopem v envInstance | None -> envInstance
+ let envInstance = List.foldBack AddLocalValPrimitive incrClassCtorLhs.InstanceCtorArgs envInstance
+ let envNonRec = match incrClassCtorLhs.InstanceCtorSafeThisValOpt with Some v -> AddLocalVal cenv.tcSink scopem v envNonRec | None -> envNonRec
+ let envNonRec = List.foldBack AddLocalValPrimitive incrClassCtorLhs.InstanceCtorArgs envNonRec
+ let safeThisValBindOpt = TcLetrecComputeCtorSafeThisValBind cenv incrClassCtorLhs.InstanceCtorSafeThisValOpt
+
+ let innerState = (tpenv, envInstance, envStatic, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable)
+ Phase2BIncrClassCtor (incrClassCtorLhs, safeThisValBindOpt), innerState
+
+ // Phase2B: typecheck the argument to an 'inherits' call and build the new object expr for the inherit-call
+ | Phase2AInherit (synBaseTy, arg, baseValOpt, m) ->
+ let baseTy, tpenv = TcType cenv NoNewTypars CheckCxs ItemOccurence.Use envInstance tpenv synBaseTy
+ let baseTy = baseTy |> convertToTypeWithMetadataIfPossible g
+ let inheritsExpr, tpenv =
+ try
+ TcNewExpr cenv envInstance tpenv baseTy (Some synBaseTy.Range) true arg m
+ with e ->
+ errorRecovery e m
+ mkUnit g m, tpenv
+ let envInstance = match baseValOpt with Some baseVal -> AddLocalVal cenv.tcSink scopem baseVal envInstance | None -> envInstance
+ let envNonRec = match baseValOpt with Some baseVal -> AddLocalVal cenv.tcSink scopem baseVal envNonRec | None -> envNonRec
+ let innerState = (tpenv, envInstance, envStatic, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable)
+ Phase2BInherit (inheritsExpr, baseValOpt), innerState
+
+ // Phase2B: let and let rec value and function definitions
+ | Phase2AIncrClassBindings (tcref, binds, isStatic, isRec, bindsm) ->
+ let envForBinding = if isStatic then envStatic else envInstance
+ let binds, bindRs, env, tpenv =
+ if isRec then
+
+ // Type check local recursive binding
+ let binds = binds |> List.map (fun bind -> RecDefnBindingInfo(ExprContainerInfo, NoNewSlots, ClassLetBinding isStatic, bind))
+ let binds, env, tpenv = TcLetrec ErrorOnOverrides cenv envForBinding tpenv (binds, scopem(*bindsm*), scopem)
+ let bindRs = [IncrClassBindingGroup(binds, isStatic, true)]
+ binds, bindRs, env, tpenv
+ else
+
+ // Type check local binding
+ let binds, env, tpenv = TcLetBindings cenv envForBinding ExprContainerInfo (ClassLetBinding isStatic) tpenv (binds, bindsm, scopem)
+ let binds, bindRs =
+ binds
+ |> List.map (function
+ | TMDefLet(bind, _) -> [bind], IncrClassBindingGroup([bind], isStatic, false)
+ | TMDefDo(e, _) -> [], IncrClassDo(e, isStatic)
+ | _ -> error(InternalError("unexpected definition kind", tcref.Range)))
+ |> List.unzip
+ List.concat binds, bindRs, env, tpenv
+
+ let envNonRec = (envNonRec, binds) ||> List.fold (fun acc bind -> AddLocalValPrimitive bind.Var acc)
+
+ // Check to see that local bindings and members don't have the same name and check some other adhoc conditions
+ for bind in binds do
+ if not isStatic && HasFSharpAttributeOpt g g.attrib_DllImportAttribute bind.Var.Attribs then
+ errorR(Error(FSComp.SR.tcDllImportNotAllowed(), bind.Var.Range))
+
+ let nm = bind.Var.DisplayName
+ let ty = generalizedTyconRef tcref
+ let ad = envNonRec.AccessRights
+ match TryFindIntrinsicMethInfo cenv.infoReader bind.Var.Range ad nm ty,
+ TryFindPropInfo cenv.infoReader bind.Var.Range ad nm ty with
+ | [], [] -> ()
+ | _ -> errorR (Error(FSComp.SR.tcMemberAndLocalClassBindingHaveSameName nm, bind.Var.Range))
+
+ // Also add static entries to the envInstance if necessary
+ let envInstance = (if isStatic then (binds, envInstance) ||> List.foldBack (fun b e -> AddLocalVal cenv.tcSink scopem b.Var e) else env)
+ let envStatic = (if isStatic then env else envStatic)
+ let innerState = (tpenv, envInstance, envStatic, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable)
+ Phase2BIncrClassBindings bindRs, innerState
+
+ | Phase2AIncrClassCtorJustAfterSuperInit ->
+ let innerState = (tpenv, envInstance, envStatic, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable)
+ Phase2BIncrClassCtorJustAfterSuperInit, innerState
+
+ | Phase2AIncrClassCtorJustAfterLastLet ->
+ let innerState = (tpenv, envInstance, envStatic, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable)
+ Phase2BIncrClassCtorJustAfterLastLet, innerState
+
+
+#if OPEN_IN_TYPE_DECLARATIONS
+ | Phase2AOpen(target, m) ->
+ let envInstance = TcOpenDecl cenv m scopem envInstance target
+ let envStatic = TcOpenDecl cenv m scopem envStatic target
+ let innerState = (tpenv, envInstance, envStatic, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable)
+ Phase2BOpen, innerState
+#endif
+
+
+ // Note: this path doesn't add anything the environment, because the member is already available off via its type
+
+ | Phase2AMember rbind ->
+
+ // Phase2B: Typecheck member binding, generalize them later, when all type constraints are known
+ // static members are checked under envStatic.
+ // envStatic contains class typars and the (ungeneralized) members on the class(es).
+ // envStatic has no instance-variables (local let-bindings or ctor args).
+
+ let v = rbind.RecBindingInfo .Val
+ let envForBinding = if v.IsInstanceMember then envInstance else envStatic
+
+ // Type variables derived from the type definition (or implicit constructor) are always generalizable (we check their generalizability later).
+ // Note they may be solved to be equi-recursive.
+ let extraGeneralizableTypars = copyOfTyconTypars
+
+ // Inside the incremental class syntax we assert the type of the 'this' variable to be precisely the same type as the
+ // this variable for the implicit class constructor. For static members, we assert the type variables associated
+ // for the class to be identical to those used for the implicit class constructor and the static class constructor.
+ //
+ // See TcLetrecBinding where this information is consumed.
+
+ // Type check the member and apply early generalization.
+ // We ignore the tpenv returned by checking each member. Each member gets checked in a fresh, clean tpenv
+ let (envNonRec, generalizedRecBinds, preGeneralizationRecBinds, _, uncheckedRecBindsTable) =
+ TcLetrecBinding (cenv, envForBinding, scopem, extraGeneralizableTypars, reqdThisValTyOpt) (envNonRec, generalizedRecBinds, preGeneralizationRecBinds, tpenv, uncheckedRecBindsTable) rbind
+
+ let innerState = (tpenv, envInstance, envStatic, envNonRec, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable)
+ Phase2BMember rbind.RecBindingInfo.Index, innerState)
+
+ let defnBs = MutRecShape.Tycon (TyconBindingsPhase2B(tyconOpt, tcref, defnBs))
+ let outerState = (tpenv, generalizedRecBinds, preGeneralizationRecBinds, uncheckedRecBindsTable, envNonRec)
+ defnBs, outerState)
+
+ // There should be no bindings that have not been generalized since checking the vary last binding always
+ // results in the generalization of all remaining ungeneralized bindings, since there are no remaining unchecked bindings
+ // to prevent the generalization
+ assert preGeneralizationRecBinds.IsEmpty
+
+ defnsBs, generalizedRecBinds, tpenv
+
+
+ // Choose type scheme implicit constructors and adjust their recursive types.
+ // Fixup recursive references to members.
+ let TcMutRecBindings_Phase2C_FixupRecursiveReferences (cenv: cenv) (denv, defnsBs: MutRecDefnsPhase2BData, generalizedTyparsForRecursiveBlock: Typar list, generalizedRecBinds: PostGeneralizationRecursiveBinding list, scopem) =
+ let g = cenv.g
+
+ // Build an index ---> binding map
+ let generalizedBindingsMap = generalizedRecBinds |> List.map (fun pgrbind -> (pgrbind.RecBindingInfo.Index, pgrbind)) |> Map.ofList
+
+ defnsBs |> MutRecShapes.mapTyconsAndLets
+
+ // Phase2C: Fixup member bindings
+ (fun (TyconBindingsPhase2B(tyconOpt, tcref, defnBs)) ->
+
+ let defnCs =
+ defnBs |> List.map (fun defnB ->
+
+ // Phase2C: Generalise implicit ctor val
+ match defnB with
+ | Phase2BIncrClassCtor (incrClassCtorLhs, safeThisValBindOpt) ->
+ let valscheme = incrClassCtorLhs.InstanceCtorValScheme
+ let valscheme = ChooseCanonicalValSchemeAfterInference g denv valscheme scopem
+ AdjustRecType incrClassCtorLhs.InstanceCtorVal valscheme
+ Phase2CIncrClassCtor (incrClassCtorLhs, safeThisValBindOpt)
+
+ | Phase2BInherit (inheritsExpr, basevOpt) ->
+ Phase2CInherit (inheritsExpr, basevOpt)
+
+ | Phase2BIncrClassBindings bindRs ->
+ Phase2CIncrClassBindings bindRs
+
+ | Phase2BIncrClassCtorJustAfterSuperInit ->
+ Phase2CIncrClassCtorJustAfterSuperInit
+
+ | Phase2BIncrClassCtorJustAfterLastLet ->
+ Phase2CIncrClassCtorJustAfterLastLet
+
+ | Phase2BMember idx ->
+ // Phase2C: Fixup member bindings
+ let generalizedBinding = generalizedBindingsMap.[idx]
+ let vxbind = TcLetrecAdjustMemberForSpecialVals cenv generalizedBinding
+ let pgbrind = FixupLetrecBind cenv denv generalizedTyparsForRecursiveBlock vxbind
+ Phase2CMember pgbrind)
+ TyconBindingsPhase2C(tyconOpt, tcref, defnCs))
+
+ // Phase2C: Fixup let bindings
+ (fun bindIdxs ->
+ [ for idx in bindIdxs do
+ let generalizedBinding = generalizedBindingsMap.[idx]
+ let vxbind = TcLetrecAdjustMemberForSpecialVals cenv generalizedBinding
+ yield FixupLetrecBind cenv denv generalizedTyparsForRecursiveBlock vxbind ])
+
+
+ // --- Extract field bindings from let-bindings
+ // --- Extract method bindings from let-bindings
+ // --- Extract bindings for implicit constructors
+ let TcMutRecBindings_Phase2D_ExtractImplicitFieldAndMethodBindings (cenv: cenv) envMutRec tpenv (denv, generalizedTyparsForRecursiveBlock, defnsCs: MutRecDefnsPhase2CData) =
+ let g = cenv.g
+
+ // let (fixupValueExprBinds, methodBinds) =
+ (envMutRec, defnsCs) ||> MutRecShapes.mapTyconsWithEnv (fun envForDecls (TyconBindingsPhase2C(tyconOpt, tcref, defnCs)) ->
+ match defnCs with
+ | Phase2CIncrClassCtor (incrClassCtorLhs, safeThisValBindOpt) :: defnCs ->
+
+ // Determine is static fields in this type need to be "protected" against invalid recursive initialization
+ let safeStaticInitInfo =
+ // Safe static init checks are not added to FSharp.Core. The FailInit helper is not defined in some places, and
+ // there are some minor concerns about performance w.r.t. these static bindings:
+ //
+ // set.fs (also map.fs)
+ // static let empty: Set<'T> =
+ // let comparer = LanguagePrimitives.FastGenericComparer<'T>
+ // new Set<'T>(comparer, SetEmpty)
+ //
+ // prim-types.fs:
+ // type TypeInfo<'T>() =
+ // static let info =
+ // let ty = typeof<'T>
+ // ...
+ // and some others in prim-types.fs
+ //
+ // REVIEW: consider allowing an optimization switch to turn off these checks
+
+ let needsSafeStaticInit = not g.compilingFslib
+
+ // We only need safe static init checks if there are some static field bindings (actually, we look for non-method bindings)
+ let hasStaticBindings =
+ defnCs |> List.exists (function
+ | Phase2CIncrClassBindings groups ->
+ groups |> List.exists (function
+ | IncrClassBindingGroup(binds, isStatic, _) ->
+ isStatic && (binds |> List.exists (IncrClassReprInfo.IsMethodRepr cenv >> not))
+ | _ -> false)
+ | _ -> false)
+
+ if needsSafeStaticInit && hasStaticBindings then
+ let rfield = MakeSafeInitField g envForDecls tcref.Range true
+ SafeInitField(mkRecdFieldRef tcref rfield.Name, rfield)
+ else
+ NoSafeInitInfo
+
+
+ // This is the type definition we're processing
+ let tcref = incrClassCtorLhs.TyconRef
+
+ // Assumes inherit call immediately follows implicit ctor. Checked by CheckMembersForm
+ let inheritsExpr, inheritsIsVisible, _, defnCs =
+ match defnCs |> List.partition (function Phase2CInherit _ -> true | _ -> false) with
+ | [Phase2CInherit (inheritsExpr, baseValOpt)], defnCs ->
+ inheritsExpr, true, baseValOpt, defnCs
+
+ | _ ->
+ if tcref.IsStructOrEnumTycon then
+ mkUnit g tcref.Range, false, None, defnCs
+ else
+ let inheritsExpr, _ = TcNewExpr cenv envForDecls tpenv g.obj_ty None true (SynExpr.Const (SynConst.Unit, tcref.Range)) tcref.Range
+ inheritsExpr, false, None, defnCs
+
+ let envForTycon = MakeInnerEnvForTyconRef envForDecls tcref false
+
+ // Compute the cpath used when creating the hidden fields
+ let cpath = envForTycon.eAccessPath
+
+ let localDecs =
+ defnCs |> List.filter (function
+ | Phase2CIncrClassBindings _
+ | Phase2CIncrClassCtorJustAfterSuperInit
+ | Phase2CIncrClassCtorJustAfterLastLet -> true
+ | _ -> false)
+ let memberBindsWithFixups = defnCs |> List.choose (function Phase2CMember pgrbind -> Some pgrbind | _ -> None)
+
+ // Extend localDecs with "let safeThisVal = ref null" if there is a safeThisVal
+ let localDecs =
+ match safeThisValBindOpt with
+ | None -> localDecs
+ | Some bind -> Phase2CIncrClassBindings [IncrClassBindingGroup([bind], false, false)] :: localDecs
+
+ // Carve out the initialization sequence and decide on the localRep
+ let ctorBodyLambdaExpr, cctorBodyLambdaExprOpt, methodBinds, localReps =
+
+ let localDecs =
+ [ for localDec in localDecs do
+ match localDec with
+ | Phase2CIncrClassBindings binds -> yield Phase2CBindings binds
+ | Phase2CIncrClassCtorJustAfterSuperInit -> yield Phase2CCtorJustAfterSuperInit
+ | Phase2CIncrClassCtorJustAfterLastLet -> yield Phase2CCtorJustAfterLastLet
+ | _ -> () ]
+ let memberBinds = memberBindsWithFixups |> List.map (fun x -> x.Binding)
+ MakeCtorForIncrClassConstructionPhase2C(cenv, envForTycon, incrClassCtorLhs, inheritsExpr, inheritsIsVisible, localDecs, memberBinds, generalizedTyparsForRecursiveBlock, safeStaticInitInfo)
+
+ // Generate the (value, expr) pairs for the implicit
+ // object constructor and implicit static initializer
+ let ctorValueExprBindings =
+ [ (let ctorValueExprBinding = TBind(incrClassCtorLhs.InstanceCtorVal, ctorBodyLambdaExpr, NoDebugPointAtStickyBinding)
+ let rbind = { ValScheme = incrClassCtorLhs.InstanceCtorValScheme ; Binding = ctorValueExprBinding }
+ FixupLetrecBind cenv envForDecls.DisplayEnv generalizedTyparsForRecursiveBlock rbind) ]
+ @
+ ( match cctorBodyLambdaExprOpt with
+ | None -> []
+ | Some cctorBodyLambdaExpr ->
+ [ (let _, cctorVal, cctorValScheme = incrClassCtorLhs.StaticCtorValInfo.Force()
+ let cctorValueExprBinding = TBind(cctorVal, cctorBodyLambdaExpr, NoDebugPointAtStickyBinding)
+ let rbind = { ValScheme = cctorValScheme; Binding = cctorValueExprBinding }
+ FixupLetrecBind cenv envForDecls.DisplayEnv generalizedTyparsForRecursiveBlock rbind) ] )
+
+ // Publish the fields of the representation to the type
+ localReps.PublishIncrClassFields (cenv, denv, cpath, incrClassCtorLhs, safeStaticInitInfo) (* mutation *)
+
+ // Fixup members
+ let memberBindsWithFixups =
+ memberBindsWithFixups |> List.map (fun pgrbind ->
+ let (TBind(v, x, spBind)) = pgrbind.Binding
+
+ // Work out the 'this' variable and type instantiation for field fixups.
+ // We use the instantiation from the instance member if any. Note: It is likely this is not strictly needed
+ // since we unify the types of the 'this' variables with those of the ctor declared typars.
+ let thisValOpt = GetInstanceMemberThisVariable (v, x)
+
+ // Members have at least as many type parameters as the enclosing class. Just grab the type variables for the type.
+ let thisTyInst = List.map mkTyparTy (List.truncate (tcref.Typars(v.Range).Length) v.Typars)
+
+ let x = localReps.FixupIncrClassExprPhase2C cenv thisValOpt safeStaticInitInfo thisTyInst x
+
+ { pgrbind with Binding = TBind(v, x, spBind) } )
+
+ tyconOpt, ctorValueExprBindings @ memberBindsWithFixups, methodBinds
+
+ // Cover the case where this is not a class with an implicit constructor
+ | defnCs ->
+ let memberBindsWithFixups = defnCs |> List.choose (function Phase2CMember pgrbind -> Some pgrbind | _ -> None)
+ tyconOpt, memberBindsWithFixups, [])
+
+ /// Check a "module X = A.B.C" module abbreviation declaration
+ let TcModuleAbbrevDecl (cenv: cenv) scopem (env: TcEnv) (id, p, m) =
+ let ad = env.AccessRights
+ let resolved =
+ match p with
+ | [] -> Result []
+ | id :: rest -> ResolveLongIdentAsModuleOrNamespace cenv.tcSink ResultCollectionSettings.AllResults cenv.amap m true OpenQualified env.NameEnv ad id rest false
+ let mvvs = ForceRaise resolved
+ if isNil mvvs then env else
+ let modrefs = mvvs |> List.map p23
+ if not (isNil modrefs) && modrefs |> List.forall (fun modref -> modref.IsNamespace) then
+ errorR(Error(FSComp.SR.tcModuleAbbreviationForNamespace(fullDisplayTextOfModRef (List.head modrefs)), m))
+ let modrefs = modrefs |> List.filter (fun mvv -> not mvv.IsNamespace)
+ if isNil modrefs then env else
+ modrefs |> List.iter (fun modref -> CheckEntityAttributes cenv.g modref m |> CommitOperationResult)
+ let env = AddModuleAbbreviationAndReport cenv.tcSink scopem id modrefs env
+ env
+
+ /// Update the contents accessible via the recursive namespace declaration, if any
+ let TcMutRecDefns_UpdateNSContents mutRecNSInfo =
+ match mutRecNSInfo with
+ | Some (Some (mspecNS: ModuleOrNamespace), mtypeAcc) ->
+ mspecNS.entity_modul_contents <- MaybeLazy.Strict !mtypeAcc
+ | _ -> ()
+
+ /// Updates the types of the modules to contain the contents so far
+ let TcMutRecDefns_UpdateModuleContents mutRecNSInfo defns =
+ defns |> MutRecShapes.iterModules (fun (MutRecDefnsPhase2DataForModule (mtypeAcc, mspec), _) ->
+ mspec.entity_modul_contents <- MaybeLazy.Strict !mtypeAcc)
+
+ TcMutRecDefns_UpdateNSContents mutRecNSInfo
+
+ /// Compute the active environments within each nested module.
+ let TcMutRecDefns_ComputeEnvs getTyconOpt getVals (cenv: cenv) report scopem m envInitial mutRecShape =
+ (envInitial, mutRecShape) ||> MutRecShapes.computeEnvs
+ (fun envAbove (MutRecDefnsPhase2DataForModule (mtypeAcc, mspec)) -> MakeInnerEnvWithAcc true envAbove mspec.Id mtypeAcc mspec.ModuleOrNamespaceType.ModuleOrNamespaceKind)
+ (fun envAbove decls ->
+
+ // Collect the type definitions, exception definitions, modules and "open" declarations
+ let tycons = decls |> List.choose (function MutRecShape.Tycon d -> getTyconOpt d | _ -> None)
+ let mspecs = decls |> List.choose (function MutRecShape.Module (MutRecDefnsPhase2DataForModule (_, mspec), _) -> Some mspec | _ -> None)
+ let moduleAbbrevs = decls |> List.choose (function MutRecShape.ModuleAbbrev (MutRecDataForModuleAbbrev (id, mp, m)) -> Some (id, mp, m) | _ -> None)
+ let opens = decls |> List.choose (function MutRecShape.Open (MutRecDataForOpen (target, m, moduleRange)) -> Some (target, m, moduleRange) | _ -> None)
+ let lets = decls |> List.collect (function MutRecShape.Lets binds -> getVals binds | _ -> [])
+ let exns = tycons |> List.filter (fun (tycon: Tycon) -> tycon.IsExceptionDecl)
+
+ // Add the type definitions, exceptions, modules and "open" declarations.
+ // The order here is sensitive. The things added first will be resolved in an environment
+ // where not everything has been added. The things added last will be preferred in name
+ // resolution.
+ //
+ // 'open' declarations ('open M') may refer to modules being defined ('M') and so must be
+ // processed in an environment where 'M' is present. However, in later processing the names of
+ // modules being defined ('M') take precedence over those coming from 'open' declarations.
+ // So add the names of the modules being defined to the environment twice - once to allow
+ // the processing of 'open M', and once to allow the correct name resolution of 'M'.
+ //
+ // Module abbreviations being defined ('module M = A.B.C') are not available for use in 'open'
+ // declarations. So
+ // namespace rec N =
+ // open M
+ // module M = FSharp.Core.Operators
+ // is not allowed.
+
+ let envForDecls = envAbove
+ // Add the modules being defined
+ let envForDecls = (envForDecls, mspecs) ||> List.fold ((if report then AddLocalSubModuleAndReport cenv.tcSink scopem else AddLocalSubModule) cenv.g cenv.amap m)
+ // Process the 'open' declarations
+ let envForDecls = (envForDecls, opens) ||> List.fold (fun env (target, m, moduleRange) -> TcOpenDecl cenv m moduleRange env target)
+ // Add the type definitions being defined
+ let envForDecls = (if report then AddLocalTyconsAndReport cenv.tcSink scopem else AddLocalTycons) cenv.g cenv.amap m tycons envForDecls
+ // Add the exception definitions being defined
+ let envForDecls = (envForDecls, exns) ||> List.fold (AddLocalExnDefnAndReport cenv.tcSink scopem)
+ // Add the modules again (but don't report them a second time)
+ let envForDecls = (envForDecls, mspecs) ||> List.fold (AddLocalSubModule cenv.g cenv.amap m)
+ // Add the module abbreviations
+ let envForDecls = (envForDecls, moduleAbbrevs) ||> List.fold (TcModuleAbbrevDecl cenv scopem)
+ // Add the values and members
+ let envForDecls = AddLocalVals cenv.tcSink scopem lets envForDecls
+ envForDecls)
+
+ /// Phase 2: Check the members and 'let' definitions in a mutually recursive group of definitions.
+ let TcMutRecDefns_Phase2_Bindings (cenv: cenv) envInitial tpenv bindsm scopem mutRecNSInfo (envMutRecPrelimWithReprs: TcEnv) (mutRecDefns: MutRecDefnsPhase2Info) =
+ let g = cenv.g
+ let denv = envMutRecPrelimWithReprs.DisplayEnv
+
+ // Phase2A: create member prelimRecValues for "recursive" items, i.e. ctor val and member vals
+ // Phase2A: also processes their arg patterns - collecting type assertions
+ let (defnsAs, uncheckedRecBinds, tpenv) = TcMutRecBindings_Phase2A_CreateRecursiveValuesAndCheckArgumentPatterns cenv tpenv (envMutRecPrelimWithReprs, mutRecDefns)
+
+ // Now basic member values are created we can compute the final attributes (i.e. in the case where attributes refer to constructors being defined)
+ mutRecDefns |> MutRecShapes.iterTycons (fun (MutRecDefnsPhase2InfoForTycon(_, _, _, _, _, fixupFinalAttrs)) ->
+ fixupFinalAttrs())
+
+ // Updates the types of the modules to contain the contents so far, which now includes values and members
+ TcMutRecDefns_UpdateModuleContents mutRecNSInfo defnsAs
+
+ // Updates the environments to include the values
+ // We must open all modules from scratch again because there may be extension methods and/or AutoOpen
+ let envMutRec, defnsAs =
+ (envInitial, MutRecShapes.dropEnvs defnsAs)
+ ||> TcMutRecDefns_ComputeEnvs
+ (fun (TyconBindingsPhase2A(tyconOpt, _, _, _, _, _, _)) -> tyconOpt)
+ (fun binds -> [ for bind in binds -> bind.RecBindingInfo.Val ])
+ cenv false scopem scopem
+ ||> MutRecShapes.extendEnvs (fun envForDecls decls ->
+
+ let prelimRecValues =
+ decls |> List.collect (function
+ | MutRecShape.Tycon (TyconBindingsPhase2A(_, _, prelimRecValues, _, _, _, _)) -> prelimRecValues
+ | MutRecShape.Lets binds -> [ for bind in binds -> bind.RecBindingInfo.Val ]
+ | _ -> [])
+
+ let ctorVals =
+ decls |> MutRecShapes.topTycons |> List.collect (fun (TyconBindingsPhase2A(_, _, _, _, _, _, defnAs)) ->
+ [ for defnB in defnAs do
+ match defnB with
+ | Phase2AIncrClassCtor incrClassCtorLhs -> yield incrClassCtorLhs.InstanceCtorVal
+ | _ -> () ])
+
+ let envForDeclsUpdated =
+ envForDecls
+ |> AddLocalVals cenv.tcSink scopem prelimRecValues
+ |> AddLocalVals cenv.tcSink scopem ctorVals
+
+ envForDeclsUpdated)
+
+ // Phase2B: type check pass, convert from ast to tast and collects type assertions, and generalize
+ let defnsBs, generalizedRecBinds, tpenv = TcMutRecBindings_Phase2B_TypeCheckAndIncrementalGeneralization cenv tpenv envInitial (envMutRec, defnsAs, uncheckedRecBinds, scopem)
+
+ let generalizedTyparsForRecursiveBlock =
+ generalizedRecBinds
+ |> List.map (fun pgrbind -> pgrbind.GeneralizedTypars)
+ |> unionGeneralizedTypars
+
+ // Check the escape condition for all extraGeneralizableTypars.
+ // First collect up all the extraGeneralizableTypars.
+ let allExtraGeneralizableTypars =
+ defnsAs |> MutRecShapes.collectTycons |> List.collect (fun (TyconBindingsPhase2A(_, _, _, _, copyOfTyconTypars, _, defnAs)) ->
+ [ yield! copyOfTyconTypars
+ for defnA in defnAs do
+ match defnA with
+ | Phase2AMember rbind -> yield! rbind.RecBindingInfo.EnclosingDeclaredTypars
+ | _ -> () ])
+
+ // Now check they don't escape the overall scope of the recursive set of types
+ if not (isNil allExtraGeneralizableTypars) then
+ let freeInInitialEnv = GeneralizationHelpers.ComputeUngeneralizableTypars envInitial
+ for extraTypar in allExtraGeneralizableTypars do
+ if Zset.memberOf freeInInitialEnv extraTypar then
+ let ty = mkTyparTy extraTypar
+ error(Error(FSComp.SR.tcNotSufficientlyGenericBecauseOfScope(NicePrint.prettyStringOfTy denv ty), extraTypar.Range))
+
+ // Solve any type variables in any part of the overall type signature of the class whose
+ // constraints involve generalized type variables.
+ //
+ // This includes property, member and constructor argument types that couldn't be fully generalized because they
+ // involve generalized copies of class type variables.
+ let unsolvedTyparsForRecursiveBlockInvolvingGeneralizedVariables =
+ let genSet = (freeInTypes CollectAllNoCaching [ for tp in generalizedTyparsForRecursiveBlock -> mkTyparTy tp ]).FreeTypars
+ //printfn "genSet.Count = %d" genSet.Count
+ let allTypes =
+ [ for pgrbind in generalizedRecBinds do
+ yield pgrbind.RecBindingInfo.Val.Type
+ for (TyconBindingsPhase2B(_tyconOpt, _tcref, defnBs)) in MutRecShapes.collectTycons defnsBs do
+ for defnB in defnBs do
+ match defnB with
+ | Phase2BIncrClassCtor (incrClassCtorLhs, _) ->
+ yield incrClassCtorLhs.InstanceCtorVal.Type
+ | _ ->
+ ()
+ ]
+ //printfn "allTypes.Length = %d" allTypes.Length
+ let unsolvedTypars = freeInTypesLeftToRight g true allTypes
+ //printfn "unsolvedTypars.Length = %d" unsolvedTypars.Length
+ //for x in unsolvedTypars do
+ // printfn "unsolvedTypar: %s #%d" x.DisplayName x.Stamp
+ let unsolvedTyparsInvolvingGeneralizedVariables =
+ unsolvedTypars |> List.filter (fun tp ->
+ let freeInTypar = (freeInType CollectAllNoCaching (mkTyparTy tp)).FreeTypars
+ // Check it is not one of the generalized variables...
+ not (genSet.Contains tp) &&
+ // Check it involves a generalized variable in one of its constraints...
+ freeInTypar.Exists(fun otherTypar -> genSet.Contains otherTypar))
+ //printfn "unsolvedTyparsInvolvingGeneralizedVariables.Length = %d" unsolvedTyparsInvolvingGeneralizedVariables.Length
+ //for x in unsolvedTypars do
+ // printfn "unsolvedTyparsInvolvingGeneralizedVariable: %s #%d" x.DisplayName x.Stamp
+ unsolvedTyparsInvolvingGeneralizedVariables
+
+ for tp in unsolvedTyparsForRecursiveBlockInvolvingGeneralizedVariables do
+ //printfn "solving unsolvedTyparsInvolvingGeneralizedVariable: %s #%d" tp.DisplayName tp.Stamp
+ if (tp.Rigidity <> TyparRigidity.Rigid) && not tp.IsSolved then
+ ConstraintSolver.ChooseTyparSolutionAndSolve cenv.css denv tp
+
+ // Now that we know what we've generalized we can adjust the recursive references
+ let defnsCs = TcMutRecBindings_Phase2C_FixupRecursiveReferences cenv (denv, defnsBs, generalizedTyparsForRecursiveBlock, generalizedRecBinds, scopem)
+
+ // --- Extract field bindings from let-bindings
+ // --- Extract method bindings from let-bindings
+ // --- Extract bindings for implicit constructors
+ let defnsDs = TcMutRecBindings_Phase2D_ExtractImplicitFieldAndMethodBindings cenv envMutRec tpenv (denv, generalizedTyparsForRecursiveBlock, defnsCs)
+
+ // Phase2E - rewrite values to initialization graphs
+ let defnsEs =
+ EliminateInitializationGraphs
+ //(fun morpher (tyconOpt, fixupValueExprBinds, methodBinds) -> (tyconOpt, morpher fixupValueExprBinds @ methodBinds))
+ g true denv defnsDs
+ (fun morpher shape -> shape |> MutRecShapes.iterTyconsAndLets (p23 >> morpher) morpher)
+ MutRecShape.Lets
+ (fun morpher shape -> shape |> MutRecShapes.mapTyconsAndLets ((fun (tyconOpt, fixupValueExprBinds, methodBinds) -> tyconOpt, (morpher fixupValueExprBinds @ methodBinds))) morpher)
+ bindsm
+
+ defnsEs, envMutRec
+
+/// Check and generalize the interface implementations, members, 'let' definitions in a mutually recursive group of definitions.
+let TcMutRecDefns_Phase2 (cenv: cenv) envInitial bindsm scopem mutRecNSInfo (envMutRec: TcEnv) (mutRecDefns: MutRecDefnsPhase2Data) =
+ let g = cenv.g
+ let interfacesFromTypeDefn envForTycon tyconMembersData =
+ let (MutRecDefnsPhase2DataForTycon(_, _, declKind, tcref, _, _, declaredTyconTypars, members, _, _, _)) = tyconMembersData
+ let overridesOK = DeclKind.CanOverrideOrImplement declKind
+ members |> List.collect (function
+ | SynMemberDefn.Interface(ity, defnOpt, _) ->
+ let _, ty = if tcref.Deref.IsExceptionDecl then [], g.exn_ty else generalizeTyconRef tcref
+ let m = ity.Range
+ if tcref.IsTypeAbbrev then error(Error(FSComp.SR.tcTypeAbbreviationsCannotHaveInterfaceDeclaration(), m))
+ if tcref.IsEnumTycon then error(Error(FSComp.SR.tcEnumerationsCannotHaveInterfaceDeclaration(), m))
+
+ let ity' =
+ let envinner = AddDeclaredTypars CheckForDuplicateTypars declaredTyconTypars envForTycon
+ TcTypeAndRecover cenv NoNewTypars CheckCxs ItemOccurence.UseInType envinner emptyUnscopedTyparEnv ity |> fst
+ if not (isInterfaceTy g ity') then errorR(Error(FSComp.SR.tcTypeIsNotInterfaceType0(), ity.Range))
+
+ if not (tcref.HasInterface g ity') then
+ error(Error(FSComp.SR.tcAllImplementedInterfacesShouldBeDeclared(), ity.Range))
+
+ let generatedCompareToValues = tcref.GeneratedCompareToValues.IsSome
+ let generatedHashAndEqualsWithComparerValues = tcref.GeneratedHashAndEqualsWithComparerValues.IsSome
+ let generatedCompareToWithComparerValues = tcref.GeneratedCompareToWithComparerValues.IsSome
+
+ if (generatedCompareToValues && typeEquiv g ity' g.mk_IComparable_ty) ||
+ (generatedCompareToWithComparerValues && typeEquiv g ity' g.mk_IStructuralComparable_ty) ||
+ (generatedCompareToValues && typeEquiv g ity' ((mkAppTy g.system_GenericIComparable_tcref [ty]))) ||
+ (generatedHashAndEqualsWithComparerValues && typeEquiv g ity' ((mkAppTy g.system_GenericIEquatable_tcref [ty]))) ||
+ (generatedHashAndEqualsWithComparerValues && typeEquiv g ity' g.mk_IStructuralEquatable_ty) then
+ errorR(Error(FSComp.SR.tcDefaultImplementationForInterfaceHasAlreadyBeenAdded(), ity.Range))
+
+ if overridesOK = WarnOnOverrides then
+ warning(IntfImplInIntrinsicAugmentation(ity.Range))
+ if overridesOK = ErrorOnOverrides then
+ errorR(IntfImplInExtrinsicAugmentation(ity.Range))
+ match defnOpt with
+ | Some defn -> [ (ity', defn, m) ]
+ | _-> []
+
+ | _ -> [])
+
+ let interfaceMembersFromTypeDefn tyconMembersData (ity', defn, _) implTySet =
+ let (MutRecDefnsPhase2DataForTycon(_, parent, declKind, tcref, baseValOpt, safeInitInfo, declaredTyconTypars, _, _, newslotsOK, _)) = tyconMembersData
+ let containerInfo = ContainerInfo(parent, Some(MemberOrValContainerInfo(tcref, Some(ity', implTySet), baseValOpt, safeInitInfo, declaredTyconTypars)))
+ defn |> List.choose (fun mem ->
+ match mem with
+ | SynMemberDefn.Member(_, m) -> Some(TyconBindingDefn(containerInfo, newslotsOK, declKind, mem, m))
+ | SynMemberDefn.AutoProperty(_, _, _, _, _, _, _, _, _, _, m) -> Some(TyconBindingDefn(containerInfo, newslotsOK, declKind, mem, m))
+ | _ -> errorR(Error(FSComp.SR.tcMemberNotPermittedInInterfaceImplementation(), mem.Range)); None)
+
+ let tyconBindingsOfTypeDefn (MutRecDefnsPhase2DataForTycon(_, parent, declKind, tcref, baseValOpt, safeInitInfo, declaredTyconTypars, members, _, newslotsOK, _)) =
+ let containerInfo = ContainerInfo(parent, Some(MemberOrValContainerInfo(tcref, None, baseValOpt, safeInitInfo, declaredTyconTypars)))
+ members
+ |> List.choose (fun memb ->
+ match memb with
+ | SynMemberDefn.ImplicitCtor _
+ | SynMemberDefn.ImplicitInherit _
+ | SynMemberDefn.LetBindings _
+ | SynMemberDefn.AutoProperty _
+ | SynMemberDefn.Member _
+ | SynMemberDefn.Open _
+ -> Some(TyconBindingDefn(containerInfo, newslotsOK, declKind, memb, memb.Range))
+
+ // Interfaces exist in the member list - handled above in interfaceMembersFromTypeDefn
+ | SynMemberDefn.Interface _ -> None
+
+ // The following should have been List.unzip out already in SplitTyconDefn
+ | SynMemberDefn.AbstractSlot _
+ | SynMemberDefn.ValField _
+ | SynMemberDefn.Inherit _ -> error(InternalError("Unexpected declaration element", memb.Range))
+ | SynMemberDefn.NestedType _ -> error(Error(FSComp.SR.tcTypesCannotContainNestedTypes(), memb.Range)))
+
+ let tpenv = emptyUnscopedTyparEnv
+
+ try
+ // Some preliminary checks
+ mutRecDefns |> MutRecShapes.iterTycons (fun tyconData ->
+ let (MutRecDefnsPhase2DataForTycon(_, _, declKind, tcref, _, _, _, members, m, newslotsOK, _)) = tyconData
+ let tcaug = tcref.TypeContents
+ if tcaug.tcaug_closed && declKind <> ExtrinsicExtensionBinding then
+ error(InternalError("Intrinsic augmentations of types are only permitted in the same file as the definition of the type", m))
+ members |> List.iter (fun mem ->
+ match mem with
+ | SynMemberDefn.Member _ -> ()
+ | SynMemberDefn.Interface _ -> ()
+ | SynMemberDefn.Open _
+ | SynMemberDefn.AutoProperty _
+ | SynMemberDefn.LetBindings _ // accept local definitions
+ | SynMemberDefn.ImplicitCtor _ // accept implicit ctor pattern, should be first!
+ | SynMemberDefn.ImplicitInherit _ when newslotsOK = NewSlotsOK -> () // accept implicit ctor pattern, should be first!
+ // The rest should have been removed by splitting, they belong to "core" (they are "shape" of type, not implementation)
+ | _ -> error(Error(FSComp.SR.tcDeclarationElementNotPermittedInAugmentation(), mem.Range))))
+
+
+ let binds: MutRecDefnsPhase2Info =
+ (envMutRec, mutRecDefns) ||> MutRecShapes.mapTyconsWithEnv (fun envForDecls tyconData ->
+ let (MutRecDefnsPhase2DataForTycon(tyconOpt, _, declKind, tcref, _, _, declaredTyconTypars, _, _, _, fixupFinalAttrs)) = tyconData
+ let envForDecls =
+ // This allows to implement protected interface methods if it's a DIM.
+ // Does not need to be hidden behind a lang version as it needs to be possible to
+ // implement protected interface methods in lower F# versions regardless if it's a DIM or not.
+ match tyconOpt with
+ | Some _ when declKind = DeclKind.ModuleOrMemberBinding ->
+ MakeInnerEnvForTyconRef envForDecls tcref false
+ | _ ->
+ envForDecls
+ let obinds = tyconBindingsOfTypeDefn tyconData
+ let ibinds =
+ let intfTypes = interfacesFromTypeDefn envForDecls tyconData
+ let slotImplSets = DispatchSlotChecking.GetSlotImplSets cenv.infoReader envForDecls.DisplayEnv envForDecls.AccessRights false (List.map (fun (ity, _, m) -> (ity, m)) intfTypes)
+ (intfTypes, slotImplSets) ||> List.map2 (interfaceMembersFromTypeDefn tyconData) |> List.concat
+ MutRecDefnsPhase2InfoForTycon(tyconOpt, tcref, declaredTyconTypars, declKind, obinds @ ibinds, fixupFinalAttrs))
+
+ MutRecBindingChecking.TcMutRecDefns_Phase2_Bindings cenv envInitial tpenv bindsm scopem mutRecNSInfo envMutRec binds
+
+ with e -> errorRecovery e scopem; [], envMutRec
+
+//-------------------------------------------------------------------------
+// Build augmentation declarations
+//-------------------------------------------------------------------------
+
+module AddAugmentationDeclarations =
+ let tcaugHasNominalInterface g (tcaug: TyconAugmentation) tcref =
+ tcaug.tcaug_interfaces |> List.exists (fun (x, _, _) ->
+ match tryTcrefOfAppTy g x with
+ | ValueSome tcref2 when tyconRefEq g tcref2 tcref -> true
+ | _ -> false)
+
+ let AddGenericCompareDeclarations (cenv: cenv) (env: TcEnv) (scSet: Set) (tycon: Tycon) =
+ let g = cenv.g
+ if AugmentWithHashCompare.TyconIsCandidateForAugmentationWithCompare g tycon && scSet.Contains tycon.Stamp then
+ let tcref = mkLocalTyconRef tycon
+ let tcaug = tycon.TypeContents
+ let _, ty = if tcref.Deref.IsExceptionDecl then [], g.exn_ty else generalizeTyconRef tcref
+ let m = tycon.Range
+ let genericIComparableTy = mkAppTy g.system_GenericIComparable_tcref [ty]
+
+
+ let hasExplicitIComparable = tycon.HasInterface g g.mk_IComparable_ty
+ let hasExplicitGenericIComparable = tcaugHasNominalInterface g tcaug g.system_GenericIComparable_tcref
+ let hasExplicitIStructuralComparable = tycon.HasInterface g g.mk_IStructuralComparable_ty
+
+ if hasExplicitIComparable then
+ errorR(Error(FSComp.SR.tcImplementsIComparableExplicitly(tycon.DisplayName), m))
+
+ elif hasExplicitGenericIComparable then
+ errorR(Error(FSComp.SR.tcImplementsGenericIComparableExplicitly(tycon.DisplayName), m))
+ elif hasExplicitIStructuralComparable then
+ errorR(Error(FSComp.SR.tcImplementsIStructuralComparableExplicitly(tycon.DisplayName), m))
+ else
+ let hasExplicitGenericIComparable = tycon.HasInterface g genericIComparableTy
+ let cvspec1, cvspec2 = AugmentWithHashCompare.MakeValsForCompareAugmentation g tcref
+ let cvspec3 = AugmentWithHashCompare.MakeValsForCompareWithComparerAugmentation g tcref
+
+ PublishInterface cenv env.DisplayEnv tcref m true g.mk_IStructuralComparable_ty
+ PublishInterface cenv env.DisplayEnv tcref m true g.mk_IComparable_ty
+ if not tycon.IsExceptionDecl && not hasExplicitGenericIComparable then
+ PublishInterface cenv env.DisplayEnv tcref m true genericIComparableTy
+ tcaug.SetCompare (mkLocalValRef cvspec1, mkLocalValRef cvspec2)
+ tcaug.SetCompareWith (mkLocalValRef cvspec3)
+ PublishValueDefn cenv env ModuleOrMemberBinding cvspec1
+ PublishValueDefn cenv env ModuleOrMemberBinding cvspec2
+ PublishValueDefn cenv env ModuleOrMemberBinding cvspec3
+
+ let AddGenericEqualityWithComparerDeclarations (cenv: cenv) (env: TcEnv) (seSet: Set) (tycon: Tycon) =
+ let g = cenv.g
+ if AugmentWithHashCompare.TyconIsCandidateForAugmentationWithEquals g tycon && seSet.Contains tycon.Stamp then
+ let tcref = mkLocalTyconRef tycon
+ let tcaug = tycon.TypeContents
+ let m = tycon.Range
+
+ let hasExplicitIStructuralEquatable = tycon.HasInterface g g.mk_IStructuralEquatable_ty
+
+ if hasExplicitIStructuralEquatable then
+ errorR(Error(FSComp.SR.tcImplementsIStructuralEquatableExplicitly(tycon.DisplayName), m))
+ else
+ let evspec1, evspec2, evspec3 = AugmentWithHashCompare.MakeValsForEqualityWithComparerAugmentation g tcref
+ PublishInterface cenv env.DisplayEnv tcref m true g.mk_IStructuralEquatable_ty
+ tcaug.SetHashAndEqualsWith (mkLocalValRef evspec1, mkLocalValRef evspec2, mkLocalValRef evspec3)
+ PublishValueDefn cenv env ModuleOrMemberBinding evspec1
+ PublishValueDefn cenv env ModuleOrMemberBinding evspec2
+ PublishValueDefn cenv env ModuleOrMemberBinding evspec3
+
+ let AddGenericCompareBindings (cenv: cenv) (tycon: Tycon) =
+ if (* AugmentWithHashCompare.TyconIsCandidateForAugmentationWithCompare cenv.g tycon && *) Option.isSome tycon.GeneratedCompareToValues then
+ AugmentWithHashCompare.MakeBindingsForCompareAugmentation cenv.g tycon
+ else
+ []
+
+ let AddGenericCompareWithComparerBindings (cenv: cenv) (tycon: Tycon) =
+ if (* AugmentWithHashCompare.TyconIsCandidateForAugmentationWithCompare cenv.g tycon && *) Option.isSome tycon.GeneratedCompareToWithComparerValues then
+ (AugmentWithHashCompare.MakeBindingsForCompareWithComparerAugmentation cenv.g tycon)
+ else
+ []
+
+ let AddGenericEqualityWithComparerBindings (cenv: cenv) (tycon: Tycon) =
+ if AugmentWithHashCompare.TyconIsCandidateForAugmentationWithEquals cenv.g tycon && Option.isSome tycon.GeneratedHashAndEqualsWithComparerValues then
+ (AugmentWithHashCompare.MakeBindingsForEqualityWithComparerAugmentation cenv.g tycon)
+ else
+ []
+
+ let AddGenericHashAndComparisonDeclarations (cenv: cenv) (env: TcEnv) scSet seSet tycon =
+ AddGenericCompareDeclarations cenv env scSet tycon
+ AddGenericEqualityWithComparerDeclarations cenv env seSet tycon
+
+ let AddGenericHashAndComparisonBindings cenv tycon =
+ AddGenericCompareBindings cenv tycon @ AddGenericCompareWithComparerBindings cenv tycon @ AddGenericEqualityWithComparerBindings cenv tycon
+
+ // We can only add the Equals override after we've done the augmentation because we have to wait until
+ // tycon.HasOverride can give correct results
+ let AddGenericEqualityBindings (cenv: cenv) (env: TcEnv) tycon =
+ let g = cenv.g
+ if AugmentWithHashCompare.TyconIsCandidateForAugmentationWithEquals g tycon then
+ let tcref = mkLocalTyconRef tycon
+ let tcaug = tycon.TypeContents
+ let _, ty = if tcref.Deref.IsExceptionDecl then [], g.exn_ty else generalizeTyconRef tcref
+ let m = tycon.Range
+
+ // Note: tycon.HasOverride only gives correct results after we've done the type augmentation
+ let hasExplicitObjectEqualsOverride = tycon.HasOverride g "Equals" [g.obj_ty]
+ let hasExplicitGenericIEquatable = tcaugHasNominalInterface g tcaug g.system_GenericIEquatable_tcref
+
+ if hasExplicitGenericIEquatable then
+ errorR(Error(FSComp.SR.tcImplementsIEquatableExplicitly(tycon.DisplayName), m))
+
+ // Note: only provide the equals method if Equals is not implemented explicitly, and
+ // we're actually generating Hash/Equals for this type
+ if not hasExplicitObjectEqualsOverride &&
+ Option.isSome tycon.GeneratedHashAndEqualsWithComparerValues then
+
+ let vspec1, vspec2 = AugmentWithHashCompare.MakeValsForEqualsAugmentation g tcref
+ tcaug.SetEquals (mkLocalValRef vspec1, mkLocalValRef vspec2)
+ if not tycon.IsExceptionDecl then
+ PublishInterface cenv env.DisplayEnv tcref m true (mkAppTy g.system_GenericIEquatable_tcref [ty])
+ PublishValueDefn cenv env ModuleOrMemberBinding vspec1
+ PublishValueDefn cenv env ModuleOrMemberBinding vspec2
+ AugmentWithHashCompare.MakeBindingsForEqualsAugmentation g tycon
+ else []
+ else []
+
+
+
+/// Infer 'comparison' and 'equality' constraints from type definitions
+module TyconConstraintInference =
+
+ /// Infer 'comparison' constraints from type definitions
+ let InferSetOfTyconsSupportingComparable (cenv: cenv) (denv: DisplayEnv) tyconsWithStructuralTypes =
+
+ let g = cenv.g
+ let tab = tyconsWithStructuralTypes |> List.map (fun (tycon: Tycon, structuralTypes) -> tycon.Stamp, (tycon, structuralTypes)) |> Map.ofList
+
+ // Initially, assume the equality relation is available for all structural type definitions
+ let initialAssumedTycons =
+ set [ for (tycon, _) in tyconsWithStructuralTypes do
+ if AugmentWithHashCompare.TyconIsCandidateForAugmentationWithCompare cenv.g tycon then
+ yield tycon.Stamp ]
+
+ // Initially, don't assume that the equality relation is dependent on any type variables
+ let initialAssumedTypars = Set.empty
+
+ // Repeatedly eliminate structural type definitions whose structural component types no longer support
+ // comparison. On the way record type variables which are support the comparison relation.
+ let rec loop (assumedTycons: Set) (assumedTypars: Set) =
+ let mutable assumedTyparsAcc = assumedTypars
+
+ // Checks if a field type supports the 'comparison' constraint based on the assumptions about the type constructors
+ // and type parameters.
+ let rec checkIfFieldTypeSupportsComparison (tycon: Tycon) (ty: TType) =
+
+ // Is the field type a type parameter?
+ match tryDestTyparTy cenv.g ty with
+ | ValueSome tp ->
+ // Look for an explicit 'comparison' constraint
+ if tp.Constraints |> List.exists (function TyparConstraint.SupportsComparison _ -> true | _ -> false) then
+ true
+
+ // Within structural types, type parameters can be optimistically assumed to have comparison
+ // We record the ones for which we have made this assumption.
+ elif tycon.TyparsNoRange |> List.exists (fun tp2 -> typarRefEq tp tp2) then
+ assumedTyparsAcc <- assumedTyparsAcc.Add(tp.Stamp)
+ true
+
+ else
+ false
+ | _ ->
+ match ty with
+ // Look for array, UIntPtr and IntPtr types
+ | SpecialComparableHeadType g tinst ->
+ tinst |> List.forall (checkIfFieldTypeSupportsComparison tycon)
+
+ // Otherwise it's a nominal type
+ | _ ->
+
+ match ty with
+ | AppTy g (tcref, tinst) ->
+ // Check the basic requirement - IComparable/IStructuralComparable or assumed-comparable
+ (if initialAssumedTycons.Contains tcref.Stamp then
+ assumedTycons.Contains tcref.Stamp
+ else
+ ExistsSameHeadTypeInHierarchy g cenv.amap range0 ty g.mk_IComparable_ty ||
+ ExistsSameHeadTypeInHierarchy g cenv.amap range0 ty g.mk_IStructuralComparable_ty)
+ &&
+ // Check it isn't ruled out by the user
+ not (HasFSharpAttribute g g.attrib_NoComparisonAttribute tcref.Attribs)
+ &&
+ // Check the structural dependencies
+ (tinst, tcref.TyparsNoRange) ||> List.lengthsEqAndForall2 (fun ty tp ->
+ if tp.ComparisonConditionalOn || assumedTypars.Contains tp.Stamp then
+ checkIfFieldTypeSupportsComparison tycon ty
+ else
+ true)
+ | _ ->
+ false
+
+ let newSet =
+ assumedTycons |> Set.filter (fun tyconStamp ->
+ let (tycon, structuralTypes) = tab.[tyconStamp]
+
+ if cenv.g.compilingFslib &&
+ AugmentWithHashCompare.TyconIsCandidateForAugmentationWithCompare cenv.g tycon &&
+ not (HasFSharpAttribute g g.attrib_StructuralComparisonAttribute tycon.Attribs) &&
+ not (HasFSharpAttribute g g.attrib_NoComparisonAttribute tycon.Attribs) then
+ errorR(Error(FSComp.SR.tcFSharpCoreRequiresExplicit(), tycon.Range))
+
+ let res = (structuralTypes |> List.forall (fst >> checkIfFieldTypeSupportsComparison tycon))
+
+ // If the type was excluded, say why
+ if not res then
+ match TryFindFSharpBoolAttribute g g.attrib_StructuralComparisonAttribute tycon.Attribs with
+ | Some true ->
+ match structuralTypes |> List.tryFind (fst >> checkIfFieldTypeSupportsComparison tycon >> not) with
+ | None ->
+ assert false
+ failwith "unreachable"
+ | Some (ty, _) ->
+ if isTyparTy g ty then
+ errorR(Error(FSComp.SR.tcStructuralComparisonNotSatisfied1(tycon.DisplayName, NicePrint.prettyStringOfTy denv ty), tycon.Range))
+ else
+ errorR(Error(FSComp.SR.tcStructuralComparisonNotSatisfied2(tycon.DisplayName, NicePrint.prettyStringOfTy denv ty), tycon.Range))
+ | Some false ->
+ ()
+
+ | None ->
+ match structuralTypes |> List.tryFind (fst >> checkIfFieldTypeSupportsComparison tycon >> not) with
+ | None ->
+ assert false
+ failwith "unreachable"
+ | Some (ty, _) ->
+ // NOTE: these warnings are off by default - they are level 4 informational warnings
+ // PERF: this call to prettyStringOfTy is always being executed, even when the warning
+ // is not being reported (the normal case).
+ if isTyparTy g ty then
+ warning(Error(FSComp.SR.tcNoComparisonNeeded1(tycon.DisplayName, NicePrint.prettyStringOfTy denv ty, tycon.DisplayName), tycon.Range))
+ else
+ warning(Error(FSComp.SR.tcNoComparisonNeeded2(tycon.DisplayName, NicePrint.prettyStringOfTy denv ty, tycon.DisplayName), tycon.Range))
+
+
+ res)
+
+ if newSet = assumedTycons && assumedTypars = assumedTyparsAcc then
+ newSet, assumedTyparsAcc
+ else
+ loop newSet assumedTyparsAcc
+
+ let uneliminatedTycons, assumedTyparsActual = loop initialAssumedTycons initialAssumedTypars
+
+ // OK, we're done, Record the results for the type variable which provide the support
+ for tyconStamp in uneliminatedTycons do
+ let (tycon, _) = tab.[tyconStamp]
+ for tp in tycon.Typars(tycon.Range) do
+ if assumedTyparsActual.Contains(tp.Stamp) then
+ tp.SetComparisonDependsOn true
+
+ // Return the set of structural type definitions which support the relation
+ uneliminatedTycons
+
+ /// Infer 'equality' constraints from type definitions
+ let InferSetOfTyconsSupportingEquatable (cenv: cenv) (denv: DisplayEnv) (tyconsWithStructuralTypes:(Tycon * _) list) =
+
+ let g = cenv.g
+ let tab = tyconsWithStructuralTypes |> List.map (fun (tycon, c) -> tycon.Stamp, (tycon, c)) |> Map.ofList
+
+ // Initially, assume the equality relation is available for all structural type definitions
+ let initialAssumedTycons =
+ set [ for (tycon, _) in tyconsWithStructuralTypes do
+ if AugmentWithHashCompare.TyconIsCandidateForAugmentationWithEquals cenv.g tycon then
+ yield tycon.Stamp ]
+
+ // Initially, don't assume that the equality relation is dependent on any type variables
+ let initialAssumedTypars = Set.empty
+
+ // Repeatedly eliminate structural type definitions whose structural component types no longer support
+ // equality. On the way add type variables which are support the equality relation
+ let rec loop (assumedTycons: Set) (assumedTypars: Set) =
+ let mutable assumedTyparsAcc = assumedTypars
+
+ // Checks if a field type supports the 'equality' constraint based on the assumptions about the type constructors
+ // and type parameters.
+ let rec checkIfFieldTypeSupportsEquality (tycon: Tycon) (ty: TType) =
+ match tryDestTyparTy cenv.g ty with
+ | ValueSome tp ->
+ // Look for an explicit 'equality' constraint
+ if tp.Constraints |> List.exists (function TyparConstraint.SupportsEquality _ -> true | _ -> false) then
+ true
+
+ // Within structural types, type parameters can be optimistically assumed to have equality
+ // We record the ones for which we have made this assumption.
+ elif tycon.Typars(tycon.Range) |> List.exists (fun tp2 -> typarRefEq tp tp2) then
+ assumedTyparsAcc <- assumedTyparsAcc.Add(tp.Stamp)
+ true
+ else
+ false
+ | _ ->
+ match ty with
+ | SpecialEquatableHeadType g tinst ->
+ tinst |> List.forall (checkIfFieldTypeSupportsEquality tycon)
+ | SpecialNotEquatableHeadType g ->
+ false
+ | _ ->
+ // Check the basic requirement - any types except those eliminated
+ match ty with
+ | AppTy g (tcref, tinst) ->
+ (if initialAssumedTycons.Contains tcref.Stamp then
+ assumedTycons.Contains tcref.Stamp
+ elif AugmentWithHashCompare.TyconIsCandidateForAugmentationWithEquals g tcref.Deref then
+ Option.isSome tcref.GeneratedHashAndEqualsWithComparerValues
+ else
+ true)
+ &&
+ // Check it isn't ruled out by the user
+ not (HasFSharpAttribute g g.attrib_NoEqualityAttribute tcref.Attribs)
+ &&
+ // Check the structural dependencies
+ (tinst, tcref.TyparsNoRange) ||> List.lengthsEqAndForall2 (fun ty tp ->
+ if tp.EqualityConditionalOn || assumedTypars.Contains tp.Stamp then
+ checkIfFieldTypeSupportsEquality tycon ty
+ else
+ true)
+ | _ ->
+ false
+
+ let newSet =
+ assumedTycons |> Set.filter (fun tyconStamp ->
+
+ let (tycon, structuralTypes) = tab.[tyconStamp]
+
+ if cenv.g.compilingFslib &&
+ AugmentWithHashCompare.TyconIsCandidateForAugmentationWithEquals cenv.g tycon &&
+ not (HasFSharpAttribute g g.attrib_StructuralEqualityAttribute tycon.Attribs) &&
+ not (HasFSharpAttribute g g.attrib_NoEqualityAttribute tycon.Attribs) then
+ errorR(Error(FSComp.SR.tcFSharpCoreRequiresExplicit(), tycon.Range))
+
+ // Remove structural types with incomparable elements from the assumedTycons
+ let res = (structuralTypes |> List.forall (fst >> checkIfFieldTypeSupportsEquality tycon))
+
+ // If the type was excluded, say why
+ if not res then
+ match TryFindFSharpBoolAttribute g g.attrib_StructuralEqualityAttribute tycon.Attribs with
+ | Some true ->
+ if AugmentWithHashCompare.TyconIsCandidateForAugmentationWithEquals cenv.g tycon then
+ match structuralTypes |> List.tryFind (fst >> checkIfFieldTypeSupportsEquality tycon >> not) with
+ | None ->
+ assert false
+ failwith "unreachable"
+ | Some (ty, _) ->
+ if isTyparTy g ty then
+ errorR(Error(FSComp.SR.tcStructuralEqualityNotSatisfied1(tycon.DisplayName, NicePrint.prettyStringOfTy denv ty), tycon.Range))
+ else
+ errorR(Error(FSComp.SR.tcStructuralEqualityNotSatisfied2(tycon.DisplayName, NicePrint.prettyStringOfTy denv ty), tycon.Range))
+ else
+ ()
+ | Some false ->
+ ()
+ | None ->
+ if AugmentWithHashCompare.TyconIsCandidateForAugmentationWithEquals cenv.g tycon then
+ match structuralTypes |> List.tryFind (fst >> checkIfFieldTypeSupportsEquality tycon >> not) with
+ | None ->
+ assert false
+ failwith "unreachable"
+ | Some (ty, _) ->
+ if isTyparTy g ty then
+ warning(Error(FSComp.SR.tcNoEqualityNeeded1(tycon.DisplayName, NicePrint.prettyStringOfTy denv ty, tycon.DisplayName), tycon.Range))
+ else
+ warning(Error(FSComp.SR.tcNoEqualityNeeded2(tycon.DisplayName, NicePrint.prettyStringOfTy denv ty, tycon.DisplayName), tycon.Range))
+
+
+ res)
+
+ if newSet = assumedTycons && assumedTypars = assumedTyparsAcc then
+ newSet, assumedTyparsAcc
+ else
+ loop newSet assumedTyparsAcc
+
+ let uneliminatedTycons, assumedTyparsActual = loop initialAssumedTycons initialAssumedTypars
+
+ // OK, we're done, Record the results for the type variable which provide the support
+ for tyconStamp in uneliminatedTycons do
+ let (tycon, _) = tab.[tyconStamp]
+ for tp in tycon.Typars(tycon.Range) do
+ if assumedTyparsActual.Contains(tp.Stamp) then
+ tp.SetEqualityDependsOn true
+
+ // Return the set of structural type definitions which support the relation
+ uneliminatedTycons
+
+
+//-------------------------------------------------------------------------
+// Helpers for modules, types and exception declarations
+//-------------------------------------------------------------------------
+
+let ComputeModuleName (longPath: Ident list) =
+ if longPath.Length <> 1 then error(Error(FSComp.SR.tcInvalidModuleName(), (List.head longPath).idRange))
+ longPath.Head
+
+let CheckForDuplicateConcreteType env nm m =
+ let curr = GetCurrAccumulatedModuleOrNamespaceType env
+ if Map.containsKey nm curr.AllEntitiesByCompiledAndLogicalMangledNames then
+ // Use 'error' instead of 'errorR' here to avoid cascading errors - see bug 1177 in FSharp 1.0
+ error (Duplicate(FSComp.SR.tcTypeExceptionOrModule(), nm, m))
+
+let CheckForDuplicateModule env nm m =
+ let curr = GetCurrAccumulatedModuleOrNamespaceType env
+ if curr.ModulesAndNamespacesByDemangledName.ContainsKey nm then
+ errorR (Duplicate(FSComp.SR.tcTypeOrModule(), nm, m))
+
+
+//-------------------------------------------------------------------------
+// Bind exception definitions
+//-------------------------------------------------------------------------
+
+/// Check 'exception' declarations in implementations and signatures
+module TcExceptionDeclarations =
+
+ let TcExnDefnCore_Phase1A cenv env parent (SynExceptionDefnRepr(Attributes synAttrs, UnionCase(_, id, _, _, _, _), _, doc, vis, m)) =
+ let attrs = TcAttributes cenv env AttributeTargets.ExnDecl synAttrs
+ if not (String.isLeadingIdentifierCharacterUpperCase id.idText) then errorR(NotUpperCaseConstructor m)
+ let vis, cpath = ComputeAccessAndCompPath env None m vis None parent
+ let vis = TcRecdUnionAndEnumDeclarations.CombineReprAccess parent vis
+ CheckForDuplicateConcreteType env (id.idText + "Exception") id.idRange
+ CheckForDuplicateConcreteType env id.idText id.idRange
+ let repr = TExnFresh (Construct.MakeRecdFieldsTable [])
+ let doc = doc.ToXmlDoc(true, Some [])
+ Construct.NewExn cpath id vis repr attrs doc
+
+ let TcExnDefnCore_Phase1G_EstablishRepresentation (cenv: cenv) (env: TcEnv) parent (exnc: Entity) (SynExceptionDefnRepr(_, UnionCase(_, _, args, _, _, _), reprIdOpt, _, _, m)) =
+ let g = cenv.g
+ let args = match args with (UnionCaseFields args) -> args | _ -> error(Error(FSComp.SR.tcExplicitTypeSpecificationCannotBeUsedForExceptionConstructors(), m))
+ let ad = env.AccessRights
+ let id = exnc.Id
+
+ let args' =
+ args |> List.mapi (fun i (Field (idOpt = idOpt) as fdef) ->
+ match idOpt with
+ | Some fieldId ->
+ let tcref = mkLocalTyconRef exnc
+ let thisTypInst, _ = generalizeTyconRef tcref
+ let item = Item.RecdField (RecdFieldInfo (thisTypInst, RecdFieldRef (tcref, fieldId.idText)))
+ CallNameResolutionSink cenv.tcSink (fieldId.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Binding, env.AccessRights)
+ | _ -> ()
+
+ TcRecdUnionAndEnumDeclarations.TcAnonFieldDecl cenv env parent emptyUnscopedTyparEnv (mkExceptionFieldName i) fdef)
+ TcRecdUnionAndEnumDeclarations.ValidateFieldNames(args, args')
+ let repr =
+ match reprIdOpt with
+ | Some longId ->
+ let resolution =
+ ResolveExprLongIdent cenv.tcSink cenv.nameResolver m ad env.NameEnv TypeNameResolutionInfo.Default longId
+ |> ForceRaise
+ match resolution with
+ | _, Item.ExnCase exnc, [] ->
+ CheckTyconAccessible cenv.amap m env.AccessRights exnc |> ignore
+ if not (isNil args') then
+ errorR (Error(FSComp.SR.tcExceptionAbbreviationsShouldNotHaveArgumentList(), m))
+ TExnAbbrevRepr exnc
+ | _, Item.CtorGroup(_, meths), [] ->
+ // REVIEW: check this really is an exception type
+ match args' with
+ | [] -> ()
+ | _ -> error (Error(FSComp.SR.tcAbbreviationsFordotNetExceptionsCannotTakeArguments(), m))
+ let candidates =
+ meths |> List.filter (fun minfo ->
+ minfo.NumArgs = [args'.Length] &&
+ minfo.GenericArity = 0)
+ match candidates with
+ | [minfo] ->
+ match minfo.ApparentEnclosingType with
+ | AppTy g (tcref, _) as ety when (TypeDefinitelySubsumesTypeNoCoercion 0 g cenv.amap m g.exn_ty ety) ->
+ let tref = tcref.CompiledRepresentationForNamedType
+ TExnAsmRepr tref
+ | _ ->
+ error(Error(FSComp.SR.tcExceptionAbbreviationsMustReferToValidExceptions(), m))
+ | _ ->
+ error (Error(FSComp.SR.tcAbbreviationsFordotNetExceptionsMustHaveMatchingObjectConstructor(), m))
+ | _ ->
+ error (Error(FSComp.SR.tcNotAnException(), m))
+ | None ->
+ TExnFresh (Construct.MakeRecdFieldsTable args')
+
+ exnc.SetExceptionInfo repr
+
+ let item = Item.ExnCase(mkLocalTyconRef exnc)
+ CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Binding, env.AccessRights)
+ args'
+
+ let private TcExnDefnCore cenv env parent synExnDefnRepr =
+ let exnc = TcExnDefnCore_Phase1A cenv env parent synExnDefnRepr
+ let args' = TcExnDefnCore_Phase1G_EstablishRepresentation cenv env parent exnc synExnDefnRepr
+ exnc.TypeContents.tcaug_super <- Some cenv.g.exn_ty
+
+ PublishTypeDefn cenv env exnc
+
+ let structuralTypes = args' |> List.map (fun rf -> (rf.FormalType, rf.Range))
+ let scSet = TyconConstraintInference.InferSetOfTyconsSupportingComparable cenv env.DisplayEnv [(exnc, structuralTypes)]
+ let seSet = TyconConstraintInference.InferSetOfTyconsSupportingEquatable cenv env.DisplayEnv [(exnc, structuralTypes)]
+
+ // Augment the exception constructor with comparison and hash methods if needed
+ let binds =
+ match exnc.ExceptionInfo with
+ | TExnAbbrevRepr _ | TExnNone | TExnAsmRepr _ -> []
+ | TExnFresh _ ->
+ AddAugmentationDeclarations.AddGenericHashAndComparisonDeclarations cenv env scSet seSet exnc
+ AddAugmentationDeclarations.AddGenericHashAndComparisonBindings cenv exnc
+
+ binds, exnc
+
+
+ let TcExnDefn cenv envInitial parent (SynExceptionDefn(core, aug, m), scopem) =
+ let binds1, exnc = TcExnDefnCore cenv envInitial parent core
+ let envMutRec = AddLocalExnDefnAndReport cenv.tcSink scopem (AddLocalTycons cenv.g cenv.amap scopem [exnc] envInitial) exnc
+
+ let defns = [MutRecShape.Tycon(MutRecDefnsPhase2DataForTycon(Some exnc, parent, ModuleOrMemberBinding, mkLocalEntityRef exnc, None, NoSafeInitInfo, [], aug, m, NoNewSlots, (fun () -> ())))]
+ let binds2, envFinal = TcMutRecDefns_Phase2 cenv envInitial m scopem None envMutRec defns
+ let binds2flat = binds2 |> MutRecShapes.collectTycons |> List.collect snd
+ // Augment types with references to values that implement the pre-baked semantics of the type
+ let binds3 = AddAugmentationDeclarations.AddGenericEqualityBindings cenv envFinal exnc
+ binds1 @ binds2flat @ binds3, exnc, envFinal
+
+ let TcExnSignature cenv envInitial parent tpenv (SynExceptionSig(core, aug, _), scopem) =
+ let binds, exnc = TcExnDefnCore cenv envInitial parent core
+ let envMutRec = AddLocalExnDefnAndReport cenv.tcSink scopem (AddLocalTycons cenv.g cenv.amap scopem [exnc] envInitial) exnc
+ let ecref = mkLocalEntityRef exnc
+ let vals, _ = TcTyconMemberSpecs cenv envMutRec (ContainerInfo(parent, Some(MemberOrValContainerInfo(ecref, None, None, NoSafeInitInfo, [])))) ModuleOrMemberBinding tpenv aug
+ binds, vals, ecref, envMutRec
+
+
+
+/// Bind type definitions
+///
+/// We first establish the cores of a set of type definitions (i.e. everything
+/// about the type definitions that doesn't involve values or expressions)
+///
+/// This is a non-trivial multi-phase algorithm. The technique used
+/// is to gradually "fill in" the fields of the type constructors.
+///
+/// This use of mutation is very problematic. This has many dangers,
+/// since the process of filling in the fields
+/// involves creating, traversing and analyzing types that may recursively
+/// refer to the types being defined. However a functional version of this
+/// would need to re-implement certain type relations to work over a
+/// partial representation of types.
+module EstablishTypeDefinitionCores =
+
+ type TypeRealizationPass =
+ | FirstPass
+ | SecondPass
+
+ /// Compute the mangled name of a type definition. 'doErase' is true for all type definitions except type abbreviations.
+ let private ComputeTyconName (longPath: Ident list, doErase: bool, typars: Typars) =
+ if longPath.Length <> 1 then error(Error(FSComp.SR.tcInvalidTypeExtension(), longPath.Head.idRange))
+ let id = longPath.Head
+ let erasedArity =
+ if doErase then typars |> Seq.sumBy (fun tp -> if tp.IsErased then 0 else 1)
+ else typars.Length
+ mkSynId id.idRange (if erasedArity = 0 then id.idText else id.idText + "`" + string erasedArity)
+
+ let private GetTyconAttribs g attrs =
+ let hasClassAttr = HasFSharpAttribute g g.attrib_ClassAttribute attrs
+ let hasAbstractClassAttr = HasFSharpAttribute g g.attrib_AbstractClassAttribute attrs
+ let hasInterfaceAttr = HasFSharpAttribute g g.attrib_InterfaceAttribute attrs
+ let hasStructAttr = HasFSharpAttribute g g.attrib_StructAttribute attrs
+ let hasMeasureAttr = HasFSharpAttribute g g.attrib_MeasureAttribute attrs
+ (hasClassAttr, hasAbstractClassAttr, hasInterfaceAttr, hasStructAttr, hasMeasureAttr)
+
+ //-------------------------------------------------------------------------
+ // Type kind inference
+ //-------------------------------------------------------------------------
+
+ let private InferTyconKind g (kind, attrs, slotsigs, fields, inSig, isConcrete, m) =
+ let (hasClassAttr, hasAbstractClassAttr, hasInterfaceAttr, hasStructAttr, hasMeasureAttr) = GetTyconAttribs g attrs
+ let bi b = (if b then 1 else 0)
+ if (bi hasClassAttr + bi hasInterfaceAttr + bi hasStructAttr + bi hasMeasureAttr) > 1 ||
+ (bi hasAbstractClassAttr + bi hasInterfaceAttr + bi hasStructAttr + bi hasMeasureAttr) > 1 then
+ error(Error(FSComp.SR.tcAttributesOfTypeSpecifyMultipleKindsForType(), m))
+
+ match kind with
+ | TyconUnspecified ->
+ if hasClassAttr || hasAbstractClassAttr || hasMeasureAttr then TyconClass
+ elif hasInterfaceAttr then TyconInterface
+ elif hasStructAttr then TyconStruct
+ elif isConcrete || not (isNil fields) then TyconClass
+ elif isNil slotsigs && inSig then TyconHiddenRepr
+ else TyconInterface
+ | k ->
+ if hasClassAttr && not (match k with TyconClass -> true | _ -> false) ||
+ hasMeasureAttr && not (match k with TyconClass | TyconAbbrev | TyconHiddenRepr -> true | _ -> false) ||
+ hasInterfaceAttr && not (match k with TyconInterface -> true | _ -> false) ||
+ hasStructAttr && not (match k with TyconStruct | TyconRecord | TyconUnion -> true | _ -> false) then
+ error(Error(FSComp.SR.tcKindOfTypeSpecifiedDoesNotMatchDefinition(), m))
+ k
+
+ let private (|TyconCoreAbbrevThatIsReallyAUnion|_|) (hasMeasureAttr, envinner: TcEnv, id: Ident) (synTyconRepr) =
+ match synTyconRepr with
+ | SynTypeDefnSimpleRepr.TypeAbbrev(_, StripParenTypes (SynType.LongIdent(LongIdentWithDots([unionCaseName], _))), m)
+ when
+ (not hasMeasureAttr &&
+ (isNil (LookupTypeNameInEnvNoArity OpenQualified unionCaseName.idText envinner.NameEnv) ||
+ id.idText = unionCaseName.idText)) ->
+ Some(unionCaseName, m)
+ | _ ->
+ None
+
+ /// Get the component types that make a record, union or struct type.
+ ///
+ /// Used when determining if a structural type supports structural comparison.
+ let private GetStructuralElementsOfTyconDefn cenv env tpenv (MutRecDefnsPhase1DataForTycon(_, synTyconRepr, _, _, _, _)) tycon =
+ let thisTyconRef = mkLocalTyconRef tycon
+ let m = tycon.Range
+ let env = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars m) env
+ let env = MakeInnerEnvForTyconRef env thisTyconRef false
+ [ match synTyconRepr with
+ | SynTypeDefnSimpleRepr.None _ -> ()
+ | SynTypeDefnSimpleRepr.Union (_, unionCases, _) ->
+
+ for (UnionCase (_, _, args, _, _, m)) in unionCases do
+ match args with
+ | UnionCaseFields flds ->
+ for (Field(_, _, _, ty, _, _, _, m)) in flds do
+ let ty', _ = TcTypeAndRecover cenv NoNewTypars NoCheckCxs ItemOccurence.UseInType env tpenv ty
+ yield (ty', m)
+ | UnionCaseFullType (ty, arity) ->
+ let ty', _ = TcTypeAndRecover cenv NoNewTypars NoCheckCxs ItemOccurence.UseInType env tpenv ty
+ let curriedArgTys, _ = GetTopTauTypeInFSharpForm cenv.g (arity |> TranslateTopValSynInfo m (TcAttributes cenv env) |> TranslatePartialArity []).ArgInfos ty' m
+ if curriedArgTys.Length > 1 then
+ errorR(Error(FSComp.SR.tcIllegalFormForExplicitTypeDeclaration(), m))
+ for argTys in curriedArgTys do
+ for (argty, _) in argTys do
+ yield (argty, m)
+
+ | SynTypeDefnSimpleRepr.General (_, _, _, fields, _, _, implicitCtorSynPats, _) when tycon.IsFSharpStructOrEnumTycon -> // for structs
+ for (Field(_, isStatic, _, ty, _, _, _, m)) in fields do
+ if not isStatic then
+ let ty', _ = TcTypeAndRecover cenv NoNewTypars NoCheckCxs ItemOccurence.UseInType env tpenv ty
+ yield (ty', m)
+
+ match implicitCtorSynPats with
+ | None -> ()
+ | Some spats ->
+ let ctorArgNames, (_, names, _) = TcSimplePatsOfUnknownType cenv true NoCheckCxs env tpenv spats
+ for arg in ctorArgNames do
+ let ty = names.[arg].Type
+ let m = names.[arg].Ident.idRange
+ if not (isNil (ListSet.subtract typarEq (freeInTypeLeftToRight cenv.g false ty) tycon.TyparsNoRange)) then
+ errorR(Error(FSComp.SR.tcStructsMustDeclareTypesOfImplicitCtorArgsExplicitly(), m))
+ yield (ty, m)
+
+ | SynTypeDefnSimpleRepr.Record (_, fields, _) ->
+ for (Field(_, _, _, ty, _, _, _, m)) in fields do
+ let ty', _ = TcTypeAndRecover cenv NoNewTypars NoCheckCxs ItemOccurence.UseInType env tpenv ty
+ yield (ty', m)
+
+ | _ ->
+ () ]
+
+ let ComputeModuleOrNamespaceKind g isModule typeNames attribs nm =
+ if not isModule then Namespace
+ elif ModuleNameIsMangled g attribs || Set.contains nm typeNames then FSharpModuleWithSuffix
+ else ModuleOrType
+
+ let AdjustModuleName modKind nm = (match modKind with FSharpModuleWithSuffix -> nm+FSharpModuleSuffix | _ -> nm)
+
+ let InstanceMembersNeedSafeInitCheck (cenv: cenv) m thisTy =
+ ExistsInEntireHierarchyOfType
+ (fun ty -> not (isStructTy cenv.g ty) && (match tryTcrefOfAppTy cenv.g ty with ValueSome tcref when tcref.HasSelfReferentialConstructor -> true | _ -> false))
+ cenv.g
+ cenv.amap
+ m
+ AllowMultiIntfInstantiations.Yes
+ thisTy
+
+ // Make the "delayed reference" boolean value recording the safe initialization of a type in a hierarchy where there is a HasSelfReferentialConstructor
+ let ComputeInstanceSafeInitInfo (cenv: cenv) env m thisTy =
+ if InstanceMembersNeedSafeInitCheck cenv m thisTy then
+ let rfield = MakeSafeInitField cenv.g env m false
+ let tcref = tcrefOfAppTy cenv.g thisTy
+ SafeInitField (mkRecdFieldRef tcref rfield.Name, rfield)
+ else
+ NoSafeInitInfo
+
+
+ let TypeNamesInMutRecDecls cenv env (compDecls: MutRecShapes) =
+ [ for d in compDecls do
+ match d with
+ | MutRecShape.Tycon (MutRecDefnsPhase1DataForTycon(ComponentInfo(_, typars, _, ids, _, _, _, _), _, _, _, _, isAtOriginalTyconDefn), _) ->
+ if isAtOriginalTyconDefn && (TcTyparDecls cenv env typars |> List.forall (fun p -> p.Kind = TyparKind.Measure)) then
+ yield (List.last ids).idText
+ | _ -> () ]
+ |> set
+
+ let TypeNamesInNonMutRecDecls defs =
+ [ for def in defs do
+ match def with
+ | SynModuleDecl.Types (typeSpecs, _) ->
+ for (TypeDefn(ComponentInfo(_, typars, _, ids, _, _, _, _), trepr, _, _)) in typeSpecs do
+ if isNil typars then
+ match trepr with
+ | SynTypeDefnRepr.ObjectModel(TyconAugmentation, _, _) -> ()
+ | _ -> yield (List.last ids).idText
+ | _ -> () ]
+ |> set
+
+ // Collect the type names so we can implicitly add the compilation suffix to module names
+ let TypeNamesInNonMutRecSigDecls defs =
+ [ for def in defs do
+ match def with
+ | SynModuleSigDecl.Types (typeSpecs, _) ->
+ for (TypeDefnSig(ComponentInfo(_, typars, _, ids, _, _, _, _), trepr, extraMembers, _)) in typeSpecs do
+ if isNil typars then
+ match trepr with
+ | SynTypeDefnSigRepr.Simple((SynTypeDefnSimpleRepr.None _), _) when not (isNil extraMembers) -> ()
+ | _ -> yield (List.last ids).idText
+ | _ -> () ]
+ |> set
+
+ let TcTyconDefnCore_Phase1A_BuildInitialModule cenv envInitial parent typeNames compInfo decls =
+ let (ComponentInfo(Attributes attribs, _parms, _constraints, longPath, xml, _, vis, im)) = compInfo
+ let id = ComputeModuleName longPath
+ let modAttrs = TcAttributes cenv envInitial AttributeTargets.ModuleDecl attribs
+ let modKind = ComputeModuleOrNamespaceKind cenv.g true typeNames modAttrs id.idText
+ let modName = AdjustModuleName modKind id.idText
+
+ let vis, _ = ComputeAccessAndCompPath envInitial None id.idRange vis None parent
+
+ CheckForDuplicateModule envInitial id.idText id.idRange
+ let id = ident (modName, id.idRange)
+ CheckForDuplicateConcreteType envInitial id.idText im
+ CheckNamespaceModuleOrTypeName cenv.g id
+
+ let envForDecls, mtypeAcc = MakeInnerEnv true envInitial id modKind
+ let mty = Construct.NewEmptyModuleOrNamespaceType modKind
+ let doc = xml.ToXmlDoc(true, Some [])
+ let mspec = Construct.NewModuleOrNamespace (Some envInitial.eCompPath) vis id doc modAttrs (MaybeLazy.Strict mty)
+ let innerParent = Parent (mkLocalModRef mspec)
+ let innerTypeNames = TypeNamesInMutRecDecls cenv envForDecls decls
+ MutRecDefnsPhase2DataForModule (mtypeAcc, mspec), (innerParent, innerTypeNames, envForDecls)
+
+ /// Establish 'type C < T1... TN > = ...' including
+ /// - computing the mangled name for C
+ /// but
+ /// - we don't yet 'properly' establish constraints on type parameters
+ let private TcTyconDefnCore_Phase1A_BuildInitialTycon (cenv: cenv) env parent (MutRecDefnsPhase1DataForTycon(synTyconInfo, synTyconRepr, _, preEstablishedHasDefaultCtor, hasSelfReferentialCtor, _)) =
+ let (ComponentInfo (_, synTypars, _, id, doc, preferPostfix, synVis, _)) = synTyconInfo
+ let checkedTypars = TcTyparDecls cenv env synTypars
+ id |> List.iter (CheckNamespaceModuleOrTypeName cenv.g)
+ match synTyconRepr with
+ | SynTypeDefnSimpleRepr.Exception synExnDefnRepr ->
+ TcExceptionDeclarations.TcExnDefnCore_Phase1A cenv env parent synExnDefnRepr
+ | _ ->
+ let id = ComputeTyconName (id, (match synTyconRepr with SynTypeDefnSimpleRepr.TypeAbbrev _ -> false | _ -> true), checkedTypars)
+
+ // Augmentations of type definitions are allowed within the same file as long as no new type representation or abbreviation is given
+ CheckForDuplicateConcreteType env id.idText id.idRange
+ let vis, cpath = ComputeAccessAndCompPath env None id.idRange synVis None parent
+
+ // Establish the visibility of the representation, e.g.
+ // type R =
+ // private { f: int }
+ // member x.P = x.f + x.f
+ let synVisOfRepr =
+ match synTyconRepr with
+ | SynTypeDefnSimpleRepr.None _ -> None
+ | SynTypeDefnSimpleRepr.TypeAbbrev _ -> None
+ | SynTypeDefnSimpleRepr.Union (vis, _, _) -> vis
+ | SynTypeDefnSimpleRepr.LibraryOnlyILAssembly _ -> None
+ | SynTypeDefnSimpleRepr.Record (vis, _, _) -> vis
+ | SynTypeDefnSimpleRepr.General _ -> None
+ | SynTypeDefnSimpleRepr.Enum _ -> None
+ | SynTypeDefnSimpleRepr.Exception _ -> None
+
+ let visOfRepr, _ = ComputeAccessAndCompPath env None id.idRange synVisOfRepr None parent
+ let visOfRepr = combineAccess vis visOfRepr
+ // If we supported nested types and modules then additions would be needed here
+ let lmtyp = MaybeLazy.Strict (Construct.NewEmptyModuleOrNamespaceType ModuleOrType)
+
+ // '' documentation is allowed for delegates
+ let paramNames =
+ match synTyconRepr with
+ | SynTypeDefnSimpleRepr.General (TyconDelegate (_ty, arity), _, _, _, _, _, _, _) -> arity.ArgNames
+ | SynTypeDefnSimpleRepr.General (TyconUnspecified, _, _, _, _, _, Some synPats, _) ->
+ let rec patName (p: SynSimplePat) =
+ match p with
+ | SynSimplePat.Id (id, _, _, _, _, _) -> id.idText
+ | SynSimplePat.Typed(pat, _, _) -> patName pat
+ | SynSimplePat.Attrib(pat, _, _) -> patName pat
+
+ let rec pats (p: SynSimplePats) =
+ match p with
+ | SynSimplePats.SimplePats (ps, _) -> ps
+ | SynSimplePats.Typed (ps, _, _) -> pats ps
+
+ let patNames =
+ pats synPats
+ |> List.map patName
+
+ patNames
+ | _ -> []
+ let doc = doc.ToXmlDoc(true, Some paramNames )
+ Construct.NewTycon
+ (cpath, id.idText, id.idRange, vis, visOfRepr, TyparKind.Type, LazyWithContext.NotLazy checkedTypars,
+ doc, preferPostfix, preEstablishedHasDefaultCtor, hasSelfReferentialCtor, lmtyp)
+
+ //-------------------------------------------------------------------------
+ /// Establishing type definitions: early phase: work out the basic kind of the type definition
+ ///
+ /// On entry: the Tycon for the type definition has been created but many of its fields are not
+ /// yet filled in.
+ /// On exit: the entity_tycon_repr field of the tycon has been filled in with a dummy value that
+ /// indicates the kind of the type constructor
+ /// Also, some adhoc checks are made.
+ ///
+ /// synTyconInfo: Syntactic AST for the name, attributes etc. of the type constructor
+ /// synTyconRepr: Syntactic AST for the RHS of the type definition
+ let private TcTyconDefnCore_Phase1B_EstablishBasicKind (cenv: cenv) inSig envinner (MutRecDefnsPhase1DataForTycon(synTyconInfo, synTyconRepr, _, _, _, _)) (tycon: Tycon) =
+ let (ComponentInfo(Attributes synAttrs, typars, _, _, _, _, _, _)) = synTyconInfo
+ let m = tycon.Range
+ let id = tycon.Id
+
+ // 'Check' the attributes. We return the results to avoid having to re-check them in all other phases.
+ // Allow failure of constructor resolution because Vals for members in the same recursive group are not yet available
+ let attrs, getFinalAttrs = TcAttributesCanFail cenv envinner AttributeTargets.TyconDecl synAttrs
+ let hasMeasureAttr = HasFSharpAttribute cenv.g cenv.g.attrib_MeasureAttribute attrs
+
+ let isStructRecordOrUnionType =
+ match synTyconRepr with
+ | SynTypeDefnSimpleRepr.Record _
+ | TyconCoreAbbrevThatIsReallyAUnion (hasMeasureAttr, envinner, id) _
+ | SynTypeDefnSimpleRepr.Union _ ->
+ HasFSharpAttribute cenv.g cenv.g.attrib_StructAttribute attrs
+ | _ ->
+ false
+
+ tycon.SetIsStructRecordOrUnion isStructRecordOrUnionType
+
+ // Set the compiled name, if any
+ tycon.SetCompiledName (TryFindFSharpStringAttribute cenv.g cenv.g.attrib_CompiledNameAttribute attrs)
+
+ if hasMeasureAttr then
+ tycon.SetTypeOrMeasureKind TyparKind.Measure
+ if not (isNil typars) then error(Error(FSComp.SR.tcMeasureDefinitionsCannotHaveTypeParameters(), m))
+
+ let repr =
+ match synTyconRepr with
+ | SynTypeDefnSimpleRepr.Exception _ -> TNoRepr
+ | SynTypeDefnSimpleRepr.None m ->
+ // Run InferTyconKind to raise errors on inconsistent attribute sets
+ InferTyconKind cenv.g (TyconHiddenRepr, attrs, [], [], inSig, true, m) |> ignore
+ if not inSig && not hasMeasureAttr then
+ errorR(Error(FSComp.SR.tcTypeRequiresDefinition(), m))
+ if hasMeasureAttr then
+ TFSharpObjectRepr { fsobjmodel_kind = TTyconClass
+ fsobjmodel_vslots = []
+ fsobjmodel_rfields = Construct.MakeRecdFieldsTable [] }
+ else
+ TNoRepr
+
+ | TyconCoreAbbrevThatIsReallyAUnion (hasMeasureAttr, envinner, id) (_, m)
+ | SynTypeDefnSimpleRepr.Union (_, _, m) ->
+
+ // Run InferTyconKind to raise errors on inconsistent attribute sets
+ InferTyconKind cenv.g (TyconUnion, attrs, [], [], inSig, true, m) |> ignore
+
+ // Note: the table of union cases is initially empty
+ Construct.MakeUnionRepr []
+
+ | SynTypeDefnSimpleRepr.TypeAbbrev _ ->
+ // Run InferTyconKind to raise errors on inconsistent attribute sets
+ InferTyconKind cenv.g (TyconAbbrev, attrs, [], [], inSig, true, m) |> ignore
+ TNoRepr
+
+ | SynTypeDefnSimpleRepr.LibraryOnlyILAssembly (s, m) ->
+ let s = (s :?> ILType)
+ // Run InferTyconKind to raise errors on inconsistent attribute sets
+ InferTyconKind cenv.g (TyconILAssemblyCode, attrs, [], [], inSig, true, m) |> ignore
+ TAsmRepr s
+
+ | SynTypeDefnSimpleRepr.Record (_, _, m) ->
+
+ // Run InferTyconKind to raise errors on inconsistent attribute sets
+ InferTyconKind cenv.g (TyconRecord, attrs, [], [], inSig, true, m) |> ignore
+
+ // Note: the table of record fields is initially empty
+ TRecdRepr (Construct.MakeRecdFieldsTable [])
+
+ | SynTypeDefnSimpleRepr.General (kind, _, slotsigs, fields, isConcrete, _, _, _) ->
+ let kind = InferTyconKind cenv.g (kind, attrs, slotsigs, fields, inSig, isConcrete, m)
+ match kind with
+ | TyconHiddenRepr ->
+ TNoRepr
+ | _ ->
+ let kind =
+ match kind with
+ | TyconClass -> TTyconClass
+ | TyconInterface -> TTyconInterface
+ | TyconDelegate _ -> TTyconDelegate (MakeSlotSig("Invoke", cenv.g.unit_ty, [], [], [], None))
+ | TyconStruct -> TTyconStruct
+ | _ -> error(InternalError("should have inferred tycon kind", m))
+
+ let repr =
+ { fsobjmodel_kind = kind
+ fsobjmodel_vslots = []
+ fsobjmodel_rfields = Construct.MakeRecdFieldsTable [] }
+
+ TFSharpObjectRepr repr
+
+ | SynTypeDefnSimpleRepr.Enum _ ->
+ let kind = TTyconEnum
+ let repr =
+ { fsobjmodel_kind = kind
+ fsobjmodel_vslots = []
+ fsobjmodel_rfields = Construct.MakeRecdFieldsTable [] }
+
+ TFSharpObjectRepr repr
+
+ // OK, now fill in the (partially computed) type representation
+ tycon.entity_tycon_repr <- repr
+ attrs, getFinalAttrs
+
+#if !NO_EXTENSIONTYPING
+ /// Get the items on the r.h.s. of a 'type X = ABC<...>' definition
+ let private TcTyconDefnCore_GetGenerateDeclaration_Rhs (StripParenTypes rhsType) =
+ match rhsType with
+ | SynType.App (StripParenTypes (SynType.LongIdent(LongIdentWithDots(tc, _))), _, args, _commas, _, _postfix, m) -> Some(tc, args, m)
+ | SynType.LongIdent (LongIdentWithDots(tc, _) as lidwd) -> Some(tc, [], lidwd.Range)
+ | SynType.LongIdentApp (StripParenTypes (SynType.LongIdent (LongIdentWithDots(tc, _))), LongIdentWithDots(longId, _), _, args, _commas, _, m) -> Some(tc@longId, args, m)
+ | _ -> None
+
+ /// Check whether 'type X = ABC<...>' is a generative provided type definition
+ let private TcTyconDefnCore_TryAsGenerateDeclaration (cenv: cenv) (envinner: TcEnv) tpenv (tycon: Tycon, rhsType) =
+
+ let tcref = mkLocalTyconRef tycon
+ match TcTyconDefnCore_GetGenerateDeclaration_Rhs rhsType with
+ | None -> None
+ | Some (tc, args, m) ->
+ let ad = envinner.AccessRights
+ match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.UseInType OpenQualified envinner.NameEnv ad tc TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.Yes with
+ | Result (_, tcrefBeforeStaticArguments) when
+ tcrefBeforeStaticArguments.IsProvided &&
+ not tcrefBeforeStaticArguments.IsErased ->
+
+ let typeBeforeArguments =
+ match tcrefBeforeStaticArguments.TypeReprInfo with
+ | TProvidedTypeExtensionPoint info -> info.ProvidedType
+ | _ -> failwith "unreachable"
+
+ if ExtensionTyping.IsGeneratedTypeDirectReference (typeBeforeArguments, m) then
+ let optGeneratedTypePath = Some (tcref.CompilationPath.MangledPath @ [ tcref.LogicalName ])
+ let _hasNoArgs, providedTypeAfterStaticArguments, checkTypeName = TcProvidedTypeAppToStaticConstantArgs cenv envinner optGeneratedTypePath tpenv tcrefBeforeStaticArguments args m
+ let isGenerated = providedTypeAfterStaticArguments.PUntaint((fun st -> not st.IsErased), m)
+ if isGenerated then
+ Some (tcrefBeforeStaticArguments, providedTypeAfterStaticArguments, checkTypeName, args, m)
+ else
+ None // The provided type (after ApplyStaticArguments) must also be marked 'IsErased=false'
+ else
+ // This must be a direct reference to a generated type, otherwise it is a type abbreviation
+ None
+ | _ ->
+ None
+
+
+ /// Check and establish a 'type X = ABC<...>' provided type definition
+ let private TcTyconDefnCore_Phase1C_EstablishDeclarationForGeneratedSetOfTypes (cenv: cenv) inSig (tycon: Tycon, rhsType: SynType, tcrefForContainer: TyconRef, theRootType: Tainted, checkTypeName, args, m) =
+ // Explanation: We are definitely on the compilation thread here, we just have not propagated the token this far.
+ let ctok = AssumeCompilationThreadWithoutEvidence()
+
+ let tcref = mkLocalTyconRef tycon
+ try
+ let resolutionEnvironment =
+ if not (isNil args) then
+ checkTypeName()
+ let resolutionEnvironment =
+ match tcrefForContainer.TypeReprInfo with
+ | TProvidedTypeExtensionPoint info -> info.ResolutionEnvironment
+ | _ -> failwith "unreachable"
+ resolutionEnvironment
+
+ // Build up a mapping from System.Type --> TyconRef/ILTypeRef, to allow reverse-mapping
+ // of types
+
+ let previousContext = (theRootType.PApply ((fun x -> x.Context), m)).PUntaint ((fun x -> x), m)
+ let lookupILTypeRef, lookupTyconRef = previousContext.GetDictionaries()
+
+ let ctxt = ProvidedTypeContext.Create(lookupILTypeRef, lookupTyconRef)
+
+ // Create a new provided type which captures the reverse-remapping tables.
+ let theRootTypeWithRemapping = theRootType.PApply ((fun x -> ProvidedType.ApplyContext(x, ctxt)), m)
+
+ let isRootGenerated, rootProvAssemStaticLinkInfoOpt =
+ let stRootAssembly = theRootTypeWithRemapping.PApply((fun st -> st.Assembly), m)
+
+ cenv.amap.assemblyLoader.GetProvidedAssemblyInfo (ctok, m, stRootAssembly)
+
+ let isRootGenerated = isRootGenerated || theRootTypeWithRemapping.PUntaint((fun st -> not st.IsErased), m)
+
+ if not isRootGenerated then
+ let desig = theRootTypeWithRemapping.TypeProviderDesignation
+ let nm = theRootTypeWithRemapping.PUntaint((fun st -> st.FullName), m)
+ error(Error(FSComp.SR.etErasedTypeUsedInGeneration(desig, nm), m))
+
+ cenv.createsGeneratedProvidedTypes <- true
+
+ // In compiled code, all types in the set of generated types end up being both generated and relocated, unless relocation is suppressed
+ let isForcedSuppressRelocate = theRootTypeWithRemapping.PUntaint((fun st -> st.IsSuppressRelocate), m)
+ if isForcedSuppressRelocate && canAccessFromEverywhere tycon.Accessibility && not cenv.isScript then
+ errorR(Error(FSComp.SR.tcGeneratedTypesShouldBeInternalOrPrivate(), tcref.Range))
+
+ let isSuppressRelocate = cenv.g.isInteractive || isForcedSuppressRelocate
+
+ // Adjust the representation of the container type
+ let repr =
+ Construct.NewProvidedTyconRepr(resolutionEnvironment, theRootTypeWithRemapping,
+ Import.ImportProvidedType cenv.amap m,
+ isSuppressRelocate, m)
+ tycon.entity_tycon_repr <- repr
+ // Record the details so we can map System.Type --> TyconRef
+ let ilOrigRootTypeRef = GetOriginalILTypeRefOfProvidedType (theRootTypeWithRemapping, m)
+ theRootTypeWithRemapping.PUntaint ((fun st -> ignore(lookupTyconRef.Remove(st)) ; lookupTyconRef.Add(st, tcref)), m)
+
+ // Record the details so we can map System.Type --> ILTypeRef, including the relocation if any
+ if not isSuppressRelocate then
+ let ilTgtRootTyRef = tycon.CompiledRepresentationForNamedType
+ theRootTypeWithRemapping.PUntaint ((fun st -> ignore(lookupILTypeRef.Remove(st)) ; lookupILTypeRef.Add(st, ilTgtRootTyRef)), m)
+
+ // Iterate all nested types and force their embedding, to populate the mapping from System.Type --> TyconRef/ILTypeRef.
+ // This is only needed for generated types, because for other types the System.Type objects self-describe
+ // their corresponding F# type.
+ let rec doNestedType (eref: EntityRef) (st: Tainted) =
+
+ // Check the type is a generated type
+ let isGenerated, provAssemStaticLinkInfoOpt =
+ let stAssembly = st.PApply((fun st -> st.Assembly), m)
+ cenv.amap.assemblyLoader.GetProvidedAssemblyInfo (ctok, m, stAssembly)
+
+ let isGenerated = isGenerated || st.PUntaint((fun st -> not st.IsErased), m)
+
+ if not isGenerated then
+ let desig = st.TypeProviderDesignation
+ let nm = st.PUntaint((fun st -> st.FullName), m)
+ error(Error(FSComp.SR.etErasedTypeUsedInGeneration(desig, nm), m))
+
+ // Embed the type into the module we're compiling
+ let cpath = eref.CompilationPath.NestedCompPath eref.LogicalName ModuleOrNamespaceKind.ModuleOrType
+ let access = combineAccess tycon.Accessibility (if st.PUntaint((fun st -> st.IsPublic || st.IsNestedPublic), m) then taccessPublic else taccessPrivate cpath)
+
+ let nestedTycon = Construct.NewProvidedTycon(resolutionEnvironment, st,
+ Import.ImportProvidedType cenv.amap m,
+ isSuppressRelocate,
+ m=m, cpath=cpath, access=access)
+ eref.ModuleOrNamespaceType.AddProvidedTypeEntity nestedTycon
+
+ let nestedTyRef = eref.NestedTyconRef nestedTycon
+ let ilOrigTypeRef = GetOriginalILTypeRefOfProvidedType (st, m)
+
+ // Record the details so we can map System.Type --> TyconRef
+ st.PUntaint ((fun st -> ignore(lookupTyconRef.Remove(st)) ; lookupTyconRef.Add(st, nestedTyRef)), m)
+
+ if isGenerated then
+ let ilTgtTyRef = nestedTycon.CompiledRepresentationForNamedType
+ // Record the details so we can map System.Type --> ILTypeRef
+ st.PUntaint ((fun st -> ignore(lookupILTypeRef.Remove(st)) ; lookupILTypeRef.Add(st, ilTgtTyRef)), m)
+
+ // Record the details so we can build correct ILTypeDefs during static linking rewriting
+ if not isSuppressRelocate then
+ match provAssemStaticLinkInfoOpt with
+ | Some provAssemStaticLinkInfo -> provAssemStaticLinkInfo.ILTypeMap.[ilOrigTypeRef] <- ilTgtTyRef
+ | None -> ()
+
+ ProviderGeneratedType(ilOrigTypeRef, ilTgtTyRef, doNestedTypes nestedTyRef st)
+ else
+ ProviderGeneratedType(ilOrigTypeRef, ilOrigTypeRef, doNestedTypes nestedTyRef st)
+
+
+ //System.Diagnostics.Debug.Assert eref.TryDeref.IsSome
+
+ and doNestedTypes (eref: EntityRef) (st: Tainted) =
+ st.PApplyArray((fun st -> st.GetAllNestedTypes()), "GetAllNestedTypes", m)
+ |> Array.map (doNestedType eref)
+ |> Array.toList
+
+ let nested = doNestedTypes tcref theRootTypeWithRemapping
+ if not isSuppressRelocate then
+
+ let ilTgtRootTyRef = tycon.CompiledRepresentationForNamedType
+ match rootProvAssemStaticLinkInfoOpt with
+ | Some provAssemStaticLinkInfo -> provAssemStaticLinkInfo.ILTypeMap.[ilOrigRootTypeRef] <- ilTgtRootTyRef
+ | None -> ()
+
+ if not inSig then
+ cenv.amap.assemblyLoader.RecordGeneratedTypeRoot (ProviderGeneratedType(ilOrigRootTypeRef, ilTgtRootTyRef, nested))
+
+ with e ->
+ errorRecovery e rhsType.Range
+#endif
+
+ /// Establish any type abbreviations
+ ///
+ /// e.g. for
+ /// type B<'a when 'a: C> = DDD of C
+ /// and C = B
+ ///
+ /// we establish
+ ///
+ /// Entity('B)
+ /// TypeAbbrev = TType_app(Entity('int'), [])
+ ///
+ /// and for
+ ///
+ /// type C = B
+ ///
+ /// we establish
+ /// TypeAbbrev = TType_app(Entity('B'), [])
+ ///
+ /// Note that for
+ /// type PairOfInts = int * int
+ /// then after running this phase and checking for cycles, operations
+ // such as 'isRefTupleTy' will return reliable results, e.g. isRefTupleTy on the
+ /// TAST type for 'PairOfInts' will report 'true'
+ //
+ let private TcTyconDefnCore_Phase1C_Phase1E_EstablishAbbreviations (cenv: cenv) envinner inSig tpenv pass (MutRecDefnsPhase1DataForTycon(_, synTyconRepr, _, _, _, _)) (tycon: Tycon) (attrs: Attribs) =
+ let m = tycon.Range
+ let checkCxs = if (pass = SecondPass) then CheckCxs else NoCheckCxs
+ let firstPass = (pass = FirstPass)
+ try
+ let id = tycon.Id
+ let thisTyconRef = mkLocalTyconRef tycon
+
+ let hasMeasureAttr = HasFSharpAttribute cenv.g cenv.g.attrib_MeasureAttribute attrs
+ let hasMeasureableAttr = HasFSharpAttribute cenv.g cenv.g.attrib_MeasureableAttribute attrs
+ let envinner = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars m) envinner
+ let envinner = MakeInnerEnvForTyconRef envinner thisTyconRef false
+
+ match synTyconRepr with
+
+ // This unfortunate case deals with "type x = A"
+ // In F# this only defines a new type if A is not in scope
+ // as a type constructor, or if the form type A = A is used.
+ // "type x = | A" can always be used instead.
+ | TyconCoreAbbrevThatIsReallyAUnion (hasMeasureAttr, envinner, id) _ -> ()
+
+ | SynTypeDefnSimpleRepr.TypeAbbrev(ParserDetail.Ok, rhsType, m) ->
+
+#if !NO_EXTENSIONTYPING
+ // Check we have not already decided that this is a generative provided type definition. If we have already done this (i.e. this is the second pass
+ // for a generative provided type definition, then there is no more work to do).
+ if (match tycon.entity_tycon_repr with TNoRepr -> true | _ -> false) then
+
+ // Determine if this is a generative type definition.
+ match TcTyconDefnCore_TryAsGenerateDeclaration cenv envinner tpenv (tycon, rhsType) with
+ | Some (tcrefForContainer, providedTypeAfterStaticArguments, checkTypeName, args, m) ->
+ // If this is a generative provided type definition then establish the provided type and all its nested types. Only do this on the first pass.
+ if firstPass then
+ TcTyconDefnCore_Phase1C_EstablishDeclarationForGeneratedSetOfTypes cenv inSig (tycon, rhsType, tcrefForContainer, providedTypeAfterStaticArguments, checkTypeName, args, m)
+ | None ->
+#else
+ ignore inSig
+#endif
+
+ // This case deals with ordinary type and measure abbreviations
+ if not hasMeasureableAttr then
+ let kind = if hasMeasureAttr then TyparKind.Measure else TyparKind.Type
+ let ty, _ = TcTypeOrMeasureAndRecover (Some kind) cenv NoNewTypars checkCxs ItemOccurence.UseInType envinner tpenv rhsType
+
+ if not firstPass then
+ let ftyvs = freeInTypeLeftToRight cenv.g false ty
+ let typars = tycon.Typars m
+ if ftyvs.Length <> typars.Length then
+ errorR(Deprecated(FSComp.SR.tcTypeAbbreviationHasTypeParametersMissingOnType(), tycon.Range))
+
+ if firstPass then
+ tycon.SetTypeAbbrev (Some ty)
+
+ | _ -> ()
+
+ with e ->
+ errorRecovery e m
+
+ // Third phase: check and publish the super types. Run twice, once before constraints are established
+ // and once after
+ let private TcTyconDefnCore_Phase1D_Phase1F_EstablishSuperTypesAndInterfaceTypes cenv tpenv inSig pass (envMutRec, mutRecDefns: MutRecShape<(_ * (Tycon * (Attribs * _)) option), _, _> list) =
+ let checkCxs = if (pass = SecondPass) then CheckCxs else NoCheckCxs
+ let firstPass = (pass = FirstPass)
+
+ // Publish the immediately declared interfaces.
+ let tyconWithImplementsL =
+ (envMutRec, mutRecDefns) ||> MutRecShapes.mapTyconsWithEnv (fun envinner (origInfo, tyconAndAttrsOpt) ->
+ match origInfo, tyconAndAttrsOpt with
+ | (typeDefCore, _, _), Some (tycon, (attrs, _)) ->
+ let (MutRecDefnsPhase1DataForTycon(_, synTyconRepr, explicitImplements, _, _, _)) = typeDefCore
+ let m = tycon.Range
+ let tcref = mkLocalTyconRef tycon
+ let envinner = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars m) envinner
+ let envinner = MakeInnerEnvForTyconRef envinner tcref false
+
+ let implementedTys, _ = List.mapFold (mapFoldFst (TcTypeAndRecover cenv NoNewTypars checkCxs ItemOccurence.UseInType envinner)) tpenv explicitImplements
+
+ if firstPass then
+ tycon.entity_attribs <- attrs
+
+ let implementedTys, inheritedTys =
+ match synTyconRepr with
+ | SynTypeDefnSimpleRepr.Exception _ -> [], []
+ | SynTypeDefnSimpleRepr.General (kind, inherits, slotsigs, fields, isConcrete, _, _, m) ->
+ let kind = InferTyconKind cenv.g (kind, attrs, slotsigs, fields, inSig, isConcrete, m)
+
+ let inherits = inherits |> List.map (fun (ty, m, _) -> (ty, m))
+ let inheritedTys = fst (List.mapFold (mapFoldFst (TcTypeAndRecover cenv NoNewTypars checkCxs ItemOccurence.UseInType envinner)) tpenv inherits)
+ let implementedTys, inheritedTys =
+ match kind with
+ | TyconInterface ->
+ explicitImplements |> List.iter (fun (_, m) -> errorR(Error(FSComp.SR.tcInterfacesShouldUseInheritNotInterface(), m)))
+ (implementedTys @ inheritedTys), []
+ | _ -> implementedTys, inheritedTys
+ implementedTys, inheritedTys
+ | SynTypeDefnSimpleRepr.Enum _ | SynTypeDefnSimpleRepr.None _ | SynTypeDefnSimpleRepr.TypeAbbrev _
+
+ | SynTypeDefnSimpleRepr.Union _ | SynTypeDefnSimpleRepr.LibraryOnlyILAssembly _ | SynTypeDefnSimpleRepr.Record _ ->
+ // REVIEW: we could do the IComparable/IStructuralHash interface analysis here.
+ // This would let the type satisfy more recursive IComparable/IStructuralHash constraints
+ implementedTys, []
+
+ for (implementedTy, m) in implementedTys do
+ if firstPass && isErasedType cenv.g implementedTy then
+ errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m))
+
+ // Publish interfaces, but only on the first pass, to avoid a duplicate interface check
+ if firstPass then
+ implementedTys |> List.iter (fun (ty, m) -> PublishInterface cenv envinner.DisplayEnv tcref m false ty)
+
+ Some (attrs, inheritedTys, synTyconRepr, tycon)
+ | _ -> None)
+
+ // Publish the attributes and supertype
+ tyconWithImplementsL |> MutRecShapes.iterTycons (Option.iter (fun (attrs, inheritedTys, synTyconRepr, tycon) ->
+ let m = tycon.Range
+ try
+ let super =
+ match synTyconRepr with
+ | SynTypeDefnSimpleRepr.Exception _ -> Some cenv.g.exn_ty
+ | SynTypeDefnSimpleRepr.None _ -> None
+ | SynTypeDefnSimpleRepr.TypeAbbrev _ -> None
+ | SynTypeDefnSimpleRepr.LibraryOnlyILAssembly _ -> None
+ | SynTypeDefnSimpleRepr.Union _
+ | SynTypeDefnSimpleRepr.Record _ ->
+ if tycon.IsStructRecordOrUnionTycon then Some(cenv.g.system_Value_ty)
+ else None
+ | SynTypeDefnSimpleRepr.General (kind, _, slotsigs, fields, isConcrete, _, _, _) ->
+ let kind = InferTyconKind cenv.g (kind, attrs, slotsigs, fields, inSig, isConcrete, m)
+
+ match inheritedTys with
+ | [] ->
+ match kind with
+ | TyconStruct -> Some(cenv.g.system_Value_ty)
+ | TyconDelegate _ -> Some(cenv.g.system_MulticastDelegate_ty )
+ | TyconHiddenRepr | TyconClass | TyconInterface -> None
+ | _ -> error(InternalError("should have inferred tycon kind", m))
+
+ | [(ty, m)] ->
+ if not firstPass && not (match kind with TyconClass -> true | _ -> false) then
+ errorR (Error(FSComp.SR.tcStructsInterfacesEnumsDelegatesMayNotInheritFromOtherTypes(), m))
+ CheckSuperType cenv ty m
+ if isTyparTy cenv.g ty then
+ if firstPass then
+ errorR(Error(FSComp.SR.tcCannotInheritFromVariableType(), m))
+ Some cenv.g.obj_ty // a "super" that is a variable type causes grief later
+ else
+ Some ty
+ | _ ->
+ error(Error(FSComp.SR.tcTypesCannotInheritFromMultipleConcreteTypes(), m))
+
+ | SynTypeDefnSimpleRepr.Enum _ ->
+ Some(cenv.g.system_Enum_ty)
+
+ // Allow super type to be a function type but convert back to FSharpFunc to make sure it has metadata
+ // (We don't apply the same rule to tuple types, i.e. no F#-declared inheritors of those are permitted)
+ let super =
+ super |> Option.map (fun ty ->
+ if isFunTy cenv.g ty then
+ let (a,b) = destFunTy cenv.g ty
+ mkAppTy cenv.g.fastFunc_tcr [a; b]
+ else ty)
+
+ // Publish the super type
+ tycon.TypeContents.tcaug_super <- super
+
+ with e -> errorRecovery e m))
+
+ /// Establish the fields, dispatch slots and union cases of a type
+ let private TcTyconDefnCore_Phase1G_EstablishRepresentation (cenv: cenv) envinner tpenv inSig (MutRecDefnsPhase1DataForTycon(_, synTyconRepr, _, _, _, _)) (tycon: Tycon) (attrs: Attribs) =
+ let g = cenv.g
+ let m = tycon.Range
+ try
+ let id = tycon.Id
+ let thisTyconRef = mkLocalTyconRef tycon
+ let innerParent = Parent thisTyconRef
+ let thisTyInst, thisTy = generalizeTyconRef thisTyconRef
+
+ let hasAbstractAttr = HasFSharpAttribute g g.attrib_AbstractClassAttribute attrs
+ let hasSealedAttr =
+ // The special case is needed for 'unit' because the 'Sealed' attribute is not yet available when this type is defined.
+ if g.compilingFslib && id.idText = "Unit" then
+ Some true
+ else
+ TryFindFSharpBoolAttribute g g.attrib_SealedAttribute attrs
+ let hasMeasureAttr = HasFSharpAttribute g g.attrib_MeasureAttribute attrs
+
+ // REVIEW: for hasMeasureableAttr we need to be stricter about checking these
+ // are only used on exactly the right kinds of type definitions and not in conjunction with other attributes.
+ let hasMeasureableAttr = HasFSharpAttribute g g.attrib_MeasureableAttribute attrs
+ let hasCLIMutable = HasFSharpAttribute g g.attrib_CLIMutableAttribute attrs
+
+ let structLayoutAttr = TryFindFSharpInt32Attribute g g.attrib_StructLayoutAttribute attrs
+ let hasAllowNullLiteralAttr = TryFindFSharpBoolAttribute g g.attrib_AllowNullLiteralAttribute attrs = Some true
+
+ if hasAbstractAttr then
+ tycon.TypeContents.tcaug_abstract <- true
+
+ tycon.entity_attribs <- attrs
+ let noAbstractClassAttributeCheck() =
+ if hasAbstractAttr then errorR (Error(FSComp.SR.tcOnlyClassesCanHaveAbstract(), m))
+
+ let noAllowNullLiteralAttributeCheck() =
+ if hasAllowNullLiteralAttr then errorR (Error(FSComp.SR.tcRecordsUnionsAbbreviationsStructsMayNotHaveAllowNullLiteralAttribute(), m))
+
+
+ let allowNullLiteralAttributeCheck() =
+ if hasAllowNullLiteralAttr then
+ tycon.TypeContents.tcaug_super |> Option.iter (fun ty -> if not (TypeNullIsExtraValue g m ty) then errorR (Error(FSComp.SR.tcAllowNullTypesMayOnlyInheritFromAllowNullTypes(), m)))
+ tycon.ImmediateInterfaceTypesOfFSharpTycon |> List.iter (fun ty -> if not (TypeNullIsExtraValue g m ty) then errorR (Error(FSComp.SR.tcAllowNullTypesMayOnlyInheritFromAllowNullTypes(), m)))
+
+
+ let structLayoutAttributeCheck allowed =
+ let explicitKind = int32 System.Runtime.InteropServices.LayoutKind.Explicit
+ match structLayoutAttr with
+ | Some kind ->
+ if allowed then
+ if kind = explicitKind then
+ warning(PossibleUnverifiableCode m)
+ elif List.isEmpty (thisTyconRef.Typars m) then
+ errorR (Error(FSComp.SR.tcOnlyStructsCanHaveStructLayout(), m))
+ else
+ errorR (Error(FSComp.SR.tcGenericTypesCannotHaveStructLayout(), m))
+ | None -> ()
+
+ let hiddenReprChecks hasRepr =
+ structLayoutAttributeCheck false
+ if hasSealedAttr = Some false || (hasRepr && hasSealedAttr <> Some true && not (id.idText = "Unit" && g.compilingFslib) ) then
+ errorR(Error(FSComp.SR.tcRepresentationOfTypeHiddenBySignature(), m))
+ if hasAbstractAttr then
+ errorR (Error(FSComp.SR.tcOnlyClassesCanHaveAbstract(), m))
+
+ let noMeasureAttributeCheck() =
+ if hasMeasureAttr then errorR (Error(FSComp.SR.tcOnlyTypesRepresentingUnitsOfMeasureCanHaveMeasure(), m))
+
+ let noCLIMutableAttributeCheck() =
+ if hasCLIMutable then errorR (Error(FSComp.SR.tcThisTypeMayNotHaveACLIMutableAttribute(), m))
+
+ let noSealedAttributeCheck k =
+ if hasSealedAttr = Some true then errorR (Error(k(), m))
+
+ let noFieldsCheck(fields': RecdField list) =
+ match fields' with
+ | (rf :: _) -> errorR (Error(FSComp.SR.tcInterfaceTypesAndDelegatesCannotContainFields(), rf.Range))
+ | _ -> ()
+
+
+ let envinner = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars m) envinner
+ let envinner = MakeInnerEnvForTyconRef envinner thisTyconRef false
+
+
+ // Notify the Language Service about field names in record/class declaration
+ let ad = envinner.AccessRights
+ let writeFakeRecordFieldsToSink (fields: RecdField list) =
+ let nenv = envinner.NameEnv
+ // Record fields should be visible from IntelliSense, so add fake names for them (similarly to "let a = ..")
+ for fspec in fields do
+ if not fspec.IsCompilerGenerated then
+ let info = RecdFieldInfo(thisTyInst, thisTyconRef.MakeNestedRecdFieldRef fspec)
+ let nenv' = AddFakeNameToNameEnv fspec.Name nenv (Item.RecdField info)
+ // Name resolution gives better info for tooltips
+ let item = Item.RecdField(FreshenRecdFieldRef cenv.nameResolver m (thisTyconRef.MakeNestedRecdFieldRef fspec))
+ CallNameResolutionSink cenv.tcSink (fspec.Range, nenv, item, emptyTyparInst, ItemOccurence.Binding, ad)
+ // Environment is needed for completions
+ CallEnvSink cenv.tcSink (fspec.Range, nenv', ad)
+
+ // Notify the Language Service about constructors in discriminated union declaration
+ let writeFakeUnionCtorsToSink (unionCases: UnionCase list) =
+ let nenv = envinner.NameEnv
+ // Constructors should be visible from IntelliSense, so add fake names for them
+ for unionCase in unionCases do
+ let info = UnionCaseInfo(thisTyInst, mkUnionCaseRef thisTyconRef unionCase.Id.idText)
+ let nenv' = AddFakeNameToNameEnv unionCase.Id.idText nenv (Item.UnionCase(info, false))
+ // Report to both - as in previous function
+ let item = Item.UnionCase(info, false)
+ CallNameResolutionSink cenv.tcSink (unionCase.Range, nenv, item, emptyTyparInst, ItemOccurence.Binding, ad)
+ CallEnvSink cenv.tcSink (unionCase.Id.idRange, nenv', ad)
+
+ let typeRepr, baseValOpt, safeInitInfo =
+ match synTyconRepr with
+
+ | SynTypeDefnSimpleRepr.Exception synExnDefnRepr ->
+ let parent = Parent (mkLocalTyconRef tycon)
+ TcExceptionDeclarations.TcExnDefnCore_Phase1G_EstablishRepresentation cenv envinner parent tycon synExnDefnRepr |> ignore
+ TNoRepr, None, NoSafeInitInfo
+
+ | SynTypeDefnSimpleRepr.None _ ->
+ hiddenReprChecks false
+ noAllowNullLiteralAttributeCheck()
+ if hasMeasureAttr then
+ let repr = TFSharpObjectRepr { fsobjmodel_kind=TTyconClass
+ fsobjmodel_vslots=[]
+ fsobjmodel_rfields= Construct.MakeRecdFieldsTable [] }
+ repr, None, NoSafeInitInfo
+ else
+ TNoRepr, None, NoSafeInitInfo
+
+ // This unfortunate case deals with "type x = A"
+ // In F# this only defines a new type if A is not in scope
+ // as a type constructor, or if the form type A = A is used.
+ // "type x = | A" can always be used instead.
+ | TyconCoreAbbrevThatIsReallyAUnion (hasMeasureAttr, envinner, id) (unionCaseName, _) ->
+
+ structLayoutAttributeCheck false
+ noAllowNullLiteralAttributeCheck()
+ TcRecdUnionAndEnumDeclarations.CheckUnionCaseName cenv unionCaseName
+ let unionCase = Construct.NewUnionCase unionCaseName [] thisTy [] XmlDoc.Empty tycon.Accessibility
+ writeFakeUnionCtorsToSink [ unionCase ]
+ Construct.MakeUnionRepr [ unionCase ], None, NoSafeInitInfo
+
+ | SynTypeDefnSimpleRepr.TypeAbbrev(ParserDetail.ErrorRecovery, _rhsType, _) ->
+ TNoRepr, None, NoSafeInitInfo
+
+ | SynTypeDefnSimpleRepr.TypeAbbrev(ParserDetail.Ok, rhsType, _) ->
+ if hasSealedAttr = Some true then
+ errorR (Error(FSComp.SR.tcAbbreviatedTypesCannotBeSealed(), m))
+ noAbstractClassAttributeCheck()
+ noAllowNullLiteralAttributeCheck()
+ if hasMeasureableAttr then
+ let kind = if hasMeasureAttr then TyparKind.Measure else TyparKind.Type
+ let theTypeAbbrev, _ = TcTypeOrMeasureAndRecover (Some kind) cenv NoNewTypars CheckCxs ItemOccurence.UseInType envinner tpenv rhsType
+
+ TMeasureableRepr theTypeAbbrev, None, NoSafeInitInfo
+ // If we already computed a representation, e.g. for a generative type definition, then don't change it here.
+ elif (match tycon.TypeReprInfo with TNoRepr -> false | _ -> true) then
+ tycon.TypeReprInfo, None, NoSafeInitInfo
+ else
+ TNoRepr, None, NoSafeInitInfo
+
+ | SynTypeDefnSimpleRepr.Union (_, unionCases, _) ->
+ noCLIMutableAttributeCheck()
+ noMeasureAttributeCheck()
+ noSealedAttributeCheck FSComp.SR.tcTypesAreAlwaysSealedDU
+ noAbstractClassAttributeCheck()
+ noAllowNullLiteralAttributeCheck()
+ structLayoutAttributeCheck false
+ let unionCases = TcRecdUnionAndEnumDeclarations.TcUnionCaseDecls cenv envinner innerParent thisTy thisTyInst tpenv unionCases
+
+ if tycon.IsStructRecordOrUnionTycon && unionCases.Length > 1 then
+ let fieldNames = [ for uc in unionCases do for ft in uc.FieldTable.TrueInstanceFieldsAsList do yield ft.Name ]
+ if fieldNames |> List.distinct |> List.length <> fieldNames.Length then
+ errorR(Error(FSComp.SR.tcStructUnionMultiCaseDistinctFields(), m))
+
+ writeFakeUnionCtorsToSink unionCases
+ Construct.MakeUnionRepr unionCases, None, NoSafeInitInfo
+
+ | SynTypeDefnSimpleRepr.Record (_, fields, _) ->
+ noMeasureAttributeCheck()
+ noSealedAttributeCheck FSComp.SR.tcTypesAreAlwaysSealedRecord
+ noAbstractClassAttributeCheck()
+ noAllowNullLiteralAttributeCheck()
+ structLayoutAttributeCheck true // these are allowed for records
+ let recdFields = TcRecdUnionAndEnumDeclarations.TcNamedFieldDecls cenv envinner innerParent false tpenv fields
+ recdFields |> CheckDuplicates (fun f -> f.Id) "field" |> ignore
+ writeFakeRecordFieldsToSink recdFields
+ TRecdRepr (Construct.MakeRecdFieldsTable recdFields), None, NoSafeInitInfo
+
+ | SynTypeDefnSimpleRepr.LibraryOnlyILAssembly (s, _) ->
+ let s = (s :?> ILType)
+ noCLIMutableAttributeCheck()
+ noMeasureAttributeCheck()
+ noSealedAttributeCheck FSComp.SR.tcTypesAreAlwaysSealedAssemblyCode
+ noAllowNullLiteralAttributeCheck()
+ structLayoutAttributeCheck false
+ noAbstractClassAttributeCheck()
+ TAsmRepr s, None, NoSafeInitInfo
+
+ | SynTypeDefnSimpleRepr.General (kind, inherits, slotsigs, fields, isConcrete, isIncrClass, implicitCtorSynPats, _) ->
+ let userFields = TcRecdUnionAndEnumDeclarations.TcNamedFieldDecls cenv envinner innerParent isIncrClass tpenv fields
+ let implicitStructFields =
+ [ // For structs with an implicit ctor, determine the fields immediately based on the arguments
+ match implicitCtorSynPats with
+ | None ->
+ ()
+ | Some spats ->
+ if tycon.IsFSharpStructOrEnumTycon then
+ let ctorArgNames, (_, names, _) = TcSimplePatsOfUnknownType cenv true CheckCxs envinner tpenv spats
+ for arg in ctorArgNames do
+ let ty = names.[arg].Type
+ let id = names.[arg].Ident
+ let taccess = TAccess [envinner.eAccessPath]
+ yield Construct.NewRecdField false None id false ty false false [] [] XmlDoc.Empty taccess true ]
+
+ (userFields @ implicitStructFields) |> CheckDuplicates (fun f -> f.Id) "field" |> ignore
+ writeFakeRecordFieldsToSink userFields
+
+ let superTy = tycon.TypeContents.tcaug_super
+ let containerInfo = TyconContainerInfo(innerParent, thisTyconRef, thisTyconRef.Typars m, NoSafeInitInfo)
+ let kind = InferTyconKind g (kind, attrs, slotsigs, fields, inSig, isConcrete, m)
+ match kind with
+ | TyconHiddenRepr ->
+ hiddenReprChecks true
+ noAllowNullLiteralAttributeCheck()
+ TNoRepr, None, NoSafeInitInfo
+ | _ ->
+
+ // Note: for a mutually recursive set we can't check this condition
+ // until "isSealedTy" and "isClassTy" give reliable results.
+ superTy |> Option.iter (fun ty ->
+ let m = match inherits with | [] -> m | ((_, m, _) :: _) -> m
+ if isSealedTy g ty then
+ errorR(Error(FSComp.SR.tcCannotInheritFromSealedType(), m))
+ elif not (isClassTy g ty) then
+ errorR(Error(FSComp.SR.tcCannotInheritFromInterfaceType(), m)))
+
+ let kind =
+ match kind with
+ | TyconStruct ->
+ noCLIMutableAttributeCheck()
+ noSealedAttributeCheck FSComp.SR.tcTypesAreAlwaysSealedStruct
+ noAbstractClassAttributeCheck()
+ noAllowNullLiteralAttributeCheck()
+ if not (isNil slotsigs) then
+ errorR (Error(FSComp.SR.tcStructTypesCannotContainAbstractMembers(), m))
+ structLayoutAttributeCheck true
+
+ TTyconStruct
+ | TyconInterface ->
+ if hasSealedAttr = Some true then errorR (Error(FSComp.SR.tcInterfaceTypesCannotBeSealed(), m))
+ noCLIMutableAttributeCheck()
+ structLayoutAttributeCheck false
+ noAbstractClassAttributeCheck()
+ allowNullLiteralAttributeCheck()
+ noFieldsCheck userFields
+ TTyconInterface
+ | TyconClass ->
+ noCLIMutableAttributeCheck()
+ structLayoutAttributeCheck(not isIncrClass)
+ allowNullLiteralAttributeCheck()
+ TTyconClass
+ | TyconDelegate (ty, arity) ->
+ noCLIMutableAttributeCheck()
+ noSealedAttributeCheck FSComp.SR.tcTypesAreAlwaysSealedDelegate
+ structLayoutAttributeCheck false
+ noAllowNullLiteralAttributeCheck()
+ noAbstractClassAttributeCheck()
+ noFieldsCheck userFields
+ let ty', _ = TcTypeAndRecover cenv NoNewTypars CheckCxs ItemOccurence.UseInType envinner tpenv ty
+ let _, _, curriedArgInfos, returnTy, _ = GetTopValTypeInCompiledForm cenv.g (arity |> TranslateTopValSynInfo m (TcAttributes cenv envinner) |> TranslatePartialArity []) 0 ty' m
+ if curriedArgInfos.Length < 1 then error(Error(FSComp.SR.tcInvalidDelegateSpecification(), m))
+ if curriedArgInfos.Length > 1 then error(Error(FSComp.SR.tcDelegatesCannotBeCurried(), m))
+ let ttps = thisTyconRef.Typars m
+ let fparams = curriedArgInfos.Head |> List.map MakeSlotParam
+ TTyconDelegate (MakeSlotSig("Invoke", thisTy, ttps, [], [fparams], returnTy))
+ | _ ->
+ error(InternalError("should have inferred tycon kind", m))
+
+ let baseIdOpt =
+ match synTyconRepr with
+ | SynTypeDefnSimpleRepr.None _ -> None
+ | SynTypeDefnSimpleRepr.Exception _ -> None
+ | SynTypeDefnSimpleRepr.TypeAbbrev _ -> None
+ | SynTypeDefnSimpleRepr.Union _ -> None
+ | SynTypeDefnSimpleRepr.LibraryOnlyILAssembly _ -> None
+ | SynTypeDefnSimpleRepr.Record _ -> None
+ | SynTypeDefnSimpleRepr.Enum _ -> None
+ | SynTypeDefnSimpleRepr.General (_, inherits, _, _, _, _, _, _) ->
+ match inherits with
+ | [] -> None
+ | ((_, m, baseIdOpt) :: _) ->
+ match baseIdOpt with
+ | None -> Some(ident("base", m))
+ | Some id -> Some id
+
+ let abstractSlots =
+ [ for (valSpfn, memberFlags) in slotsigs do
+
+ let (ValSpfn(_, _, _, _, _valSynData, _, _, _, _, _, m)) = valSpfn
+
+ CheckMemberFlags None NewSlotsOK OverridesOK memberFlags m
+
+ let slots = fst (TcAndPublishValSpec (cenv, envinner, containerInfo, ModuleOrMemberBinding, Some memberFlags, tpenv, valSpfn))
+ // Multiple slots may be returned, e.g. for
+ // abstract P: int with get, set
+
+ for slot in slots do
+ yield mkLocalValRef slot ]
+
+ let baseValOpt = MakeAndPublishBaseVal cenv envinner baseIdOpt (superOfTycon g tycon)
+ let safeInitInfo = ComputeInstanceSafeInitInfo cenv envinner thisTyconRef.Range thisTy
+ let safeInitFields = match safeInitInfo with SafeInitField (_, fld) -> [fld] | NoSafeInitInfo -> []
+
+ let repr =
+ TFSharpObjectRepr
+ { fsobjmodel_kind = kind
+ fsobjmodel_vslots = abstractSlots
+ fsobjmodel_rfields = Construct.MakeRecdFieldsTable (userFields @ implicitStructFields @ safeInitFields) }
+ repr, baseValOpt, safeInitInfo
+
+ | SynTypeDefnSimpleRepr.Enum (decls, m) ->
+ let fieldTy, fields' = TcRecdUnionAndEnumDeclarations.TcEnumDecls cenv envinner innerParent thisTy decls
+ let kind = TTyconEnum
+ structLayoutAttributeCheck false
+ noCLIMutableAttributeCheck()
+ noSealedAttributeCheck FSComp.SR.tcTypesAreAlwaysSealedEnum
+ noAllowNullLiteralAttributeCheck()
+ let vid = ident("value__", m)
+ let vfld = Construct.NewRecdField false None vid false fieldTy false false [] [] XmlDoc.Empty taccessPublic true
+
+ let legitEnumTypes = [ g.int32_ty; g.int16_ty; g.sbyte_ty; g.int64_ty; g.char_ty; g.bool_ty; g.uint32_ty; g.uint16_ty; g.byte_ty; g.uint64_ty ]
+ if not (ListSet.contains (typeEquiv g) fieldTy legitEnumTypes) then
+ errorR(Error(FSComp.SR.tcInvalidTypeForLiteralEnumeration(), m))
+
+ writeFakeRecordFieldsToSink fields'
+ let repr =
+ TFSharpObjectRepr
+ { fsobjmodel_kind=kind
+ fsobjmodel_vslots=[]
+ fsobjmodel_rfields= Construct.MakeRecdFieldsTable (vfld :: fields') }
+ repr, None, NoSafeInitInfo
+
+ tycon.entity_tycon_repr <- typeRepr
+ // We check this just after establishing the representation
+ if TyconHasUseNullAsTrueValueAttribute g tycon && not (CanHaveUseNullAsTrueValueAttribute g tycon) then
+ errorR(Error(FSComp.SR.tcInvalidUseNullAsTrueValue(), m))
+
+ // validate ConditionalAttribute, should it be applied (it's only valid on a type if the type is an attribute type)
+ match attrs |> List.tryFind (IsMatchingFSharpAttribute g g.attrib_ConditionalAttribute) with
+ | Some _ ->
+ if not(ExistsInEntireHierarchyOfType (fun t -> typeEquiv g t (mkAppTy g.tcref_System_Attribute [])) g cenv.amap m AllowMultiIntfInstantiations.Yes thisTy) then
+ errorR(Error(FSComp.SR.tcConditionalAttributeUsage(), m))
+ | _ -> ()
+
+ (baseValOpt, safeInitInfo)
+ with e ->
+ errorRecovery e m
+ None, NoSafeInitInfo
+
+ /// Check that a set of type definitions is free of cycles in abbreviations
+ let private TcTyconDefnCore_CheckForCyclicAbbreviations tycons =
+
+ let edgesFrom (tycon: Tycon) =
+
+ let rec accInAbbrevType ty acc =
+ match stripTyparEqns ty with
+ | TType_anon (_,l)
+ | TType_tuple (_, l) -> accInAbbrevTypes l acc
+ | TType_ucase (UnionCaseRef(tc, _), tinst)
+ | TType_app (tc, tinst) ->
+ let tycon2 = tc.Deref
+ let acc = accInAbbrevTypes tinst acc
+ // Record immediate recursive references
+ if ListSet.contains (===) tycon2 tycons then
+ (tycon, tycon2) :: acc
+ // Expand the representation of abbreviations
+ elif tc.IsTypeAbbrev then
+ accInAbbrevType (reduceTyconRefAbbrev tc tinst) acc
+ // Otherwise H - explore the instantiation.
+ else
+ acc
+
+ | TType_fun (d, r) ->
+ accInAbbrevType d (accInAbbrevType r acc)
+
+ | TType_var _ -> acc
+
+ | TType_forall (_, r) -> accInAbbrevType r acc
+
+ | TType_measure ms -> accInMeasure ms acc
+
+ and accInMeasure ms acc =
+ match stripUnitEqns ms with
+ | Measure.Con tc when ListSet.contains (===) tc.Deref tycons ->
+ (tycon, tc.Deref) :: acc
+ | Measure.Con tc when tc.IsTypeAbbrev ->
+ accInMeasure (reduceTyconRefAbbrevMeasureable tc) acc
+ | Measure.Prod (ms1, ms2) -> accInMeasure ms1 (accInMeasure ms2 acc)
+ | Measure.Inv ms -> accInMeasure ms acc
+ | _ -> acc
+
+ and accInAbbrevTypes tys acc =
+ List.foldBack accInAbbrevType tys acc
+
+ match tycon.TypeAbbrev with
+ | None -> []
+ | Some ty -> accInAbbrevType ty []
+
+ let edges = List.collect edgesFrom tycons
+ let graph = Graph ((fun tc -> tc.Stamp), tycons, edges)
+ graph.IterateCycles (fun path ->
+ let tycon = path.Head
+ // The thing is cyclic. Set the abbreviation and representation to be "None" to stop later VS crashes
+ tycon.SetTypeAbbrev None
+ tycon.entity_tycon_repr <- TNoRepr
+ errorR(Error(FSComp.SR.tcTypeDefinitionIsCyclic(), tycon.Range)))
+
+
+ /// Check that a set of type definitions is free of inheritance cycles
+ let TcTyconDefnCore_CheckForCyclicStructsAndInheritance (cenv: cenv) tycons =
+ let g = cenv.g
+ // Overview:
+ // Given several tycons now being defined (the "initial" tycons).
+ // Look for cycles in inheritance and struct-field-containment.
+ //
+ // The graph is on the (initial) type constructors (not types (e.g. tycon instantiations)).
+ // Closing under edges:
+ // 1. (tycon, superTycon) -- tycon (initial) to the tycon of its super type.
+ // 2. (tycon, interfaceTycon) -- tycon (initial) to the tycon of an interface it implements.
+ // 3. (tycon, T) -- tycon (initial) is a struct with a field (static or instance) that would store a T<_>
+ // where storing T<_> means is T<_>
+ // or is a struct with an instance field that stores T<_>.
+ // The implementation only stores edges between (initial) tycons.
+ //
+ // The special case "S<'a> static field on S<'a>" is allowed, so no #3 edge is collected for this.
+ // Only static fields for current tycons need to be followed. Previous tycons are assumed (previously checked) OK.
+ //
+ // BEGIN: EARLIER COMMENT
+ // Of course structs are not allowed to contain instance fields of their own type:
+ // type S = struct { field x: S }
+ //
+ // In addition, see bug 3429. In the .NET IL structs are allowed to contain
+ // static fields of their exact generic type, e.g.
+ // type S = struct { static field x: S }
+ // type S = struct { static field x: S }
+ // but not
+ // type S = struct { static field x: S }
+ // type S = struct { static field x: S }
+ // etc.
+ //
+ // Ideally structs would allow static fields of any type. However
+ // this is a restriction and exemption that originally stems from
+ // the way the Microsoft desktop CLR class loader works.
+ // END: EARLIER COMMENT
+
+ // edgesFrom tycon collects (tycon, tycon2) edges, for edges as described above.
+ let edgesFrom (tycon: Tycon) =
+ // Record edge (tycon, tycon2), only when tycon2 is an "initial" tycon.
+ let insertEdgeToTycon tycon2 acc =
+ if ListSet.contains (===) tycon2 tycons && // note: only add if tycon2 is initial
+ not (List.exists (fun (tc, tc2) -> tc === tycon && tc2 === tycon2) acc) // note: only add if (tycon, tycon2) not already an edge
+ then
+ (tycon, tycon2) :: acc
+ else acc // note: all edges added are (tycon, _)
+ let insertEdgeToType ty acc =
+ match tryTcrefOfAppTy g ty with
+ | ValueSome tcref ->
+ insertEdgeToTycon tcref.Deref acc
+ | _ ->
+ acc
+
+ // collect edges from an a struct field (which is struct-contained in tycon)
+ let rec accStructField (structTycon: Tycon) structTyInst (fspec: RecdField) (doneTypes, acc) =
+ let fieldTy = actualTyOfRecdFieldForTycon structTycon structTyInst fspec
+ accStructFieldType structTycon structTyInst fspec fieldTy (doneTypes, acc)
+
+ // collect edges from an a struct field (given the field type, which may be expanded if it is a type abbreviation)
+ and accStructFieldType structTycon structTyInst fspec fieldTy (doneTypes, acc) =
+ let fieldTy = stripTyparEqns fieldTy
+ match fieldTy with
+ | TType_tuple (_isStruct , tinst2) when isStructTupleTy cenv.g fieldTy ->
+ // The field is a struct tuple. Check each element of the tuple.
+ // This case was added to resolve issues/3916
+ ((doneTypes, acc), tinst2)
+ ||> List.fold (fun acc' x -> accStructFieldType structTycon structTyInst fspec x acc')
+ | TType_app (tcref2 , tinst2) when tcref2.IsStructOrEnumTycon ->
+ // The field is a struct.
+ // An edge (tycon, tycon2) should be recorded, unless it is the "static self-typed field" case.
+ let tycon2 = tcref2.Deref
+ let specialCaseStaticField =
+ // The special case of "static field S<'a> in struct S<'a>" is permitted. (so no (S, S) edge to be collected).
+ fspec.IsStatic &&
+ (structTycon === tycon2) &&
+ (structTyInst, tinst2) ||> List.lengthsEqAndForall2 (fun ty1 ty2 ->
+ match tryDestTyparTy g ty1 with
+ | ValueSome destTypar1 ->
+ match tryDestTyparTy g ty2 with
+ | ValueSome destTypar2 -> typarEq destTypar1 destTypar2
+ | _ -> false
+ | _ -> false)
+ if specialCaseStaticField then
+ doneTypes, acc // no edge collected, no recursion.
+ else
+ let acc = insertEdgeToTycon tycon2 acc // collect edge (tycon, tycon2), if tycon2 is initial.
+ accStructInstanceFields fieldTy tycon2 tinst2 (doneTypes, acc) // recurse through struct field looking for more edges
+ | TType_app (tcref2, tinst2) when tcref2.IsTypeAbbrev ->
+ // The field is a type abbreviation. Expand and repeat.
+ accStructFieldType structTycon structTyInst fspec (reduceTyconRefAbbrev tcref2 tinst2) (doneTypes, acc)
+ | _ ->
+ doneTypes, acc
+
+ // collect edges from the fields of a given struct type.
+ and accStructFields includeStaticFields ty (structTycon: Tycon) tinst (doneTypes, acc) =
+ if List.exists (typeEquiv g ty) doneTypes then
+ // This type (type instance) has been seen before, so no need to collect the same edges again (and avoid loops!)
+ doneTypes, acc
+ else
+ // Only collect once from each type instance.
+ let doneTypes = ty :: doneTypes
+ let fspecs =
+ if structTycon.IsUnionTycon then
+ [ for uc in structTycon.UnionCasesArray do
+ for c in uc.FieldTable.FieldsByIndex do
+ yield c]
+ else
+ structTycon.AllFieldsAsList
+ let fspecs = fspecs |> List.filter (fun fspec -> includeStaticFields || not fspec.IsStatic)
+ let doneTypes, acc = List.foldBack (accStructField structTycon tinst) fspecs (doneTypes, acc)
+ doneTypes, acc
+ and accStructInstanceFields ty structTycon tinst (doneTypes, acc) = accStructFields false ty structTycon tinst (doneTypes, acc)
+ and accStructAllFields ty (structTycon: Tycon) tinst (doneTypes, acc) = accStructFields true ty structTycon tinst (doneTypes, acc)
+
+ let acc = []
+ let acc =
+ if tycon.IsStructOrEnumTycon then
+ let tinst, ty = generalizeTyconRef (mkLocalTyconRef tycon)
+ let _, acc = accStructAllFields ty tycon tinst ([], acc)
+ acc
+ else
+ acc
+
+ let acc =
+ // Note: only the nominal type counts
+ let super = superOfTycon g tycon
+ insertEdgeToType super acc
+ let acc =
+ // Note: only the nominal type counts
+ List.foldBack insertEdgeToType tycon.ImmediateInterfaceTypesOfFSharpTycon acc
+ acc
+ let edges = (List.collect edgesFrom tycons)
+ let graph = Graph ((fun tc -> tc.Stamp), tycons, edges)
+ graph.IterateCycles (fun path ->
+ let tycon = path.Head
+ // The thing is cyclic. Set the abbreviation and representation to be "None" to stop later VS crashes
+ tycon.SetTypeAbbrev None
+ tycon.entity_tycon_repr <- TNoRepr
+ errorR(Error(FSComp.SR.tcTypeDefinitionIsCyclicThroughInheritance(), tycon.Range)))
+
+
+ // Interlude between Phase1D and Phase1E - Check and publish the explicit constraints.
+ let TcMutRecDefns_CheckExplicitConstraints cenv tpenv m checkCxs envMutRecPrelim withEnvs =
+ (envMutRecPrelim, withEnvs) ||> MutRecShapes.iterTyconsWithEnv (fun envForDecls (origInfo, tyconOpt) ->
+ match origInfo, tyconOpt with
+ | (typeDefCore, _, _), Some (tycon: Tycon) ->
+ let (MutRecDefnsPhase1DataForTycon(synTyconInfo, _, _, _, _, _)) = typeDefCore
+ let (ComponentInfo(_, _, synTyconConstraints, _, _, _, _, _)) = synTyconInfo
+ let envForTycon = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars m) envForDecls
+ let thisTyconRef = mkLocalTyconRef tycon
+ let envForTycon = MakeInnerEnvForTyconRef envForTycon thisTyconRef false
+ try TcTyparConstraints cenv NoNewTypars checkCxs ItemOccurence.UseInType envForTycon tpenv synTyconConstraints |> ignore
+ with e -> errorRecovery e m
+ | _ -> ())
+
+
+ let TcMutRecDefns_Phase1 mkLetInfo (cenv: cenv) envInitial parent typeNames inSig tpenv m scopem mutRecNSInfo (mutRecDefns: MutRecShapes) =
+ // Phase1A - build Entity for type definitions, exception definitions and module definitions.
+ // Also for abbreviations of any of these. Augmentations are skipped in this phase.
+ let withEntities =
+ mutRecDefns
+ |> MutRecShapes.mapWithParent
+ (parent, typeNames, envInitial)
+ // Build the initial entity for each module definition
+ (fun (innerParent, typeNames, envForDecls) compInfo decls ->
+ TcTyconDefnCore_Phase1A_BuildInitialModule cenv envForDecls innerParent typeNames compInfo decls)
+
+ // Build the initial Tycon for each type definition
+ (fun (innerParent, _, envForDecls) (typeDefCore, tyconMemberInfo) ->
+ let (MutRecDefnsPhase1DataForTycon(_, _, _, _, _, isAtOriginalTyconDefn)) = typeDefCore
+ let tyconOpt =
+ if isAtOriginalTyconDefn then
+ Some (TcTyconDefnCore_Phase1A_BuildInitialTycon cenv envForDecls innerParent typeDefCore)
+ else
+ None
+ (typeDefCore, tyconMemberInfo, innerParent), tyconOpt)
+
+ // Bundle up the data for each 'val', 'member' or 'let' definition (just package up the data, no processing yet)
+ (fun (innerParent, _, _) synBinds ->
+ let containerInfo = ModuleOrNamespaceContainerInfo(match innerParent with Parent p -> p | _ -> failwith "unreachable")
+ mkLetInfo containerInfo synBinds)
+
+ // Phase1AB - Publish modules
+ let envTmp, withEnvs =
+ (envInitial, withEntities) ||> MutRecShapes.computeEnvs
+ (fun envAbove (MutRecDefnsPhase2DataForModule (mtypeAcc, mspec)) ->
+ PublishModuleDefn cenv envAbove mspec
+ MakeInnerEnvWithAcc true envAbove mspec.Id mtypeAcc mspec.ModuleOrNamespaceType.ModuleOrNamespaceKind)
+ (fun envAbove _ -> envAbove)
+
+ // Updates the types of the modules to contain the contents so far, which now includes the nested modules and types
+ MutRecBindingChecking.TcMutRecDefns_UpdateModuleContents mutRecNSInfo withEnvs
+
+ // Publish tycons
+ (envTmp, withEnvs) ||> MutRecShapes.iterTyconsWithEnv
+ (fun envAbove (_, tyconOpt) ->
+ tyconOpt |> Option.iter (fun tycon ->
+ // recheck these in case type is a duplicate in a mutually recursive set
+ CheckForDuplicateConcreteType envAbove tycon.LogicalName tycon.Range
+ PublishTypeDefn cenv envAbove tycon))
+
+ // Updates the types of the modules to contain the contents so far
+ MutRecBindingChecking.TcMutRecDefns_UpdateModuleContents mutRecNSInfo withEnvs
+
+ // Phase1AB - Compute the active environments within each nested module.
+ //
+ // Add the types to the environment. This does not add the fields and union cases (because we haven't established them yet).
+ // We re-add them to the original environment later on. We don't report them to the Language Service yet as we don't know if
+ // they are well-formed (e.g. free of abbreviation cycles)
+ let envMutRecPrelim, withEnvs = (envInitial, withEntities) ||> MutRecBindingChecking.TcMutRecDefns_ComputeEnvs snd (fun _ -> []) cenv false scopem m
+
+ // Phase 1B. Establish the kind of each type constructor
+ // Here we run InferTyconKind and record partial information about the kind of the type constructor.
+ // This means TyconObjModelKind is set, which means isSealedTy, isInterfaceTy etc. give accurate results.
+ let withAttrs =
+ (envMutRecPrelim, withEnvs) ||> MutRecShapes.mapTyconsWithEnv (fun envForDecls (origInfo, tyconOpt) ->
+ let res =
+ match origInfo, tyconOpt with
+ | (typeDefCore, _, _), Some tycon -> Some (tycon, TcTyconDefnCore_Phase1B_EstablishBasicKind cenv inSig envForDecls typeDefCore tycon)
+ | _ -> None
+ origInfo, res)
+
+ // Phase 1C. Establish the abbreviations (no constraint checking, because constraints not yet established)
+ (envMutRecPrelim, withAttrs) ||> MutRecShapes.iterTyconsWithEnv (fun envForDecls (origInfo, tyconAndAttrsOpt) ->
+ match origInfo, tyconAndAttrsOpt with
+ | (typeDefCore, _, _), Some (tycon, (attrs, _)) -> TcTyconDefnCore_Phase1C_Phase1E_EstablishAbbreviations cenv envForDecls inSig tpenv FirstPass typeDefCore tycon attrs
+ | _ -> ())
+
+ // Check for cyclic abbreviations. If this succeeds we can start reducing abbreviations safely.
+ let tycons = withEntities |> MutRecShapes.collectTycons |> List.choose snd
+
+ TcTyconDefnCore_CheckForCyclicAbbreviations tycons
+
+ // Phase 1D. Establish the super type and interfaces (no constraint checking, because constraints not yet established)
+ (envMutRecPrelim, withAttrs) |> TcTyconDefnCore_Phase1D_Phase1F_EstablishSuperTypesAndInterfaceTypes cenv tpenv inSig FirstPass
+
+ // Interlude between Phase1D and Phase1E - Add the interface and member declarations for
+ // hash/compare. Because this adds interfaces, this may let constraints
+ // be satisfied, so we have to do this prior to checking any constraints.
+ //
+ // First find all the field types in all the structural types
+ let tyconsWithStructuralTypes =
+ (envMutRecPrelim, withEnvs)
+ ||> MutRecShapes.mapTyconsWithEnv (fun envForDecls (origInfo, tyconOpt) ->
+ match origInfo, tyconOpt with
+ | (typeDefCore, _, _), Some tycon -> Some (tycon, GetStructuralElementsOfTyconDefn cenv envForDecls tpenv typeDefCore tycon)
+ | _ -> None)
+ |> MutRecShapes.collectTycons
+ |> List.choose id
+
+ let scSet = TyconConstraintInference.InferSetOfTyconsSupportingComparable cenv envMutRecPrelim.DisplayEnv tyconsWithStructuralTypes
+ let seSet = TyconConstraintInference.InferSetOfTyconsSupportingEquatable cenv envMutRecPrelim.DisplayEnv tyconsWithStructuralTypes
+
+ (envMutRecPrelim, withEnvs)
+ ||> MutRecShapes.iterTyconsWithEnv (fun envForDecls (_, tyconOpt) ->
+ tyconOpt |> Option.iter (AddAugmentationDeclarations.AddGenericHashAndComparisonDeclarations cenv envForDecls scSet seSet))
+
+ TcMutRecDefns_CheckExplicitConstraints cenv tpenv m NoCheckCxs envMutRecPrelim withEnvs
+
+ // No inferred constraints allowed on declared typars
+ (envMutRecPrelim, withEnvs) ||> MutRecShapes.iterTyconsWithEnv (fun envForDecls (_, tyconOpt) ->
+ tyconOpt |> Option.iter (fun tycon -> tycon.Typars m |> List.iter (SetTyparRigid envForDecls.DisplayEnv m)))
+
+ // Phase1E. OK, now recheck the abbreviations, super/interface and explicit constraints types (this time checking constraints)
+ (envMutRecPrelim, withAttrs) ||> MutRecShapes.iterTyconsWithEnv (fun envForDecls (origInfo, tyconAndAttrsOpt) ->
+ match origInfo, tyconAndAttrsOpt with
+ | (typeDefCore, _, _), Some (tycon, (attrs, _)) -> TcTyconDefnCore_Phase1C_Phase1E_EstablishAbbreviations cenv envForDecls inSig tpenv SecondPass typeDefCore tycon attrs
+ | _ -> ())
+
+ // Phase1F. Establish inheritance hierarchy
+ (envMutRecPrelim, withAttrs) |> TcTyconDefnCore_Phase1D_Phase1F_EstablishSuperTypesAndInterfaceTypes cenv tpenv inSig SecondPass
+
+ TcMutRecDefns_CheckExplicitConstraints cenv tpenv m CheckCxs envMutRecPrelim withEnvs
+
+ // Add exception definitions to the environments, which are used for checking exception abbreviations in representations
+ let envMutRecPrelim, withAttrs =
+ (envMutRecPrelim, withAttrs)
+ ||> MutRecShapes.extendEnvs (fun envForDecls decls ->
+ let tycons = decls |> List.choose (function MutRecShape.Tycon (_, Some (tycon, _)) -> Some tycon | _ -> None)
+ let exns = tycons |> List.filter (fun tycon -> tycon.IsExceptionDecl)
+ let envForDecls = (envForDecls, exns) ||> List.fold (AddLocalExnDefnAndReport cenv.tcSink scopem)
+ envForDecls)
+
+ // Phase1G. Establish inheritance hierarchy
+ // Now all the type parameters, abbreviations, constraints and kind information is established.
+ // Now do the representations. Each baseValOpt is a residue from the representation which is potentially available when
+ // checking the members.
+ let withBaseValsAndSafeInitInfos =
+ (envMutRecPrelim, withAttrs) ||> MutRecShapes.mapTyconsWithEnv (fun envForDecls (origInfo, tyconAndAttrsOpt) ->
+ let info =
+ match origInfo, tyconAndAttrsOpt with
+ | (typeDefCore, _, _), Some (tycon, (attrs, _)) -> TcTyconDefnCore_Phase1G_EstablishRepresentation cenv envForDecls tpenv inSig typeDefCore tycon attrs
+ | _ -> None, NoSafeInitInfo
+ let tyconOpt, fixupFinalAttrs =
+ match tyconAndAttrsOpt with
+ | None -> None, (fun () -> ())
+ | Some (tycon, (_prelimAttrs, getFinalAttrs)) -> Some tycon, (fun () -> tycon.entity_attribs <- getFinalAttrs())
+
+ (origInfo, tyconOpt, fixupFinalAttrs, info))
+
+ // Now check for cyclic structs and inheritance. It's possible these should be checked as separate conditions.
+ // REVIEW: checking for cyclic inheritance is happening too late. See note above.
+ TcTyconDefnCore_CheckForCyclicStructsAndInheritance cenv tycons
+
+
+ (tycons, envMutRecPrelim, withBaseValsAndSafeInitInfos)
+
+
+/// Bind declarations in implementation and signature files
+module TcDeclarations =
+
+ /// Given a type definition, compute whether its members form an extension of an existing type, and if so if it is an
+ /// intrinsic or extrinsic extension
+ let private ComputeTyconDeclKind (cenv: cenv) (envForDecls: TcEnv) tyconOpt isAtOriginalTyconDefn inSig m (synTypars: SynTyparDecl list) synTyparCxs longPath =
+ let g = cenv.g
+ let ad = envForDecls.AccessRights
+
+ let tcref =
+ match tyconOpt with
+ | Some tycon when isAtOriginalTyconDefn ->
+
+ // This records a name resolution of the type at the location
+ let resInfo = TypeNameResolutionStaticArgsInfo.FromTyArgs synTypars.Length
+ ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.Binding OpenQualified envForDecls.NameEnv ad longPath resInfo PermitDirectReferenceToGeneratedType.No
+ |> ignore
+
+ mkLocalTyconRef tycon
+
+ | _ ->
+ let resInfo = TypeNameResolutionStaticArgsInfo.FromTyArgs synTypars.Length
+ let _, tcref =
+ match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.Binding OpenQualified envForDecls.NameEnv ad longPath resInfo PermitDirectReferenceToGeneratedType.No with
+ | Result res -> res
+ | res when inSig && longPath.Length = 1 ->
+ errorR(Deprecated(FSComp.SR.tcReservedSyntaxForAugmentation(), m))
+ ForceRaise res
+ | res -> ForceRaise res
+ tcref
+
+ let isInterfaceOrDelegateOrEnum =
+ tcref.Deref.IsFSharpInterfaceTycon ||
+ tcref.Deref.IsFSharpDelegateTycon ||
+ tcref.Deref.IsFSharpEnumTycon
+
+ let reqTypars = tcref.Typars m
+
+ // Member definitions are intrinsic (added directly to the type) if:
+ // a) For interfaces, only if it is in the original defn.
+ // Augmentations to interfaces via partial type defns will always be extensions, e.g. extension members on interfaces.
+ // b) For other types, if the type is isInSameModuleOrNamespace
+ let declKind, typars =
+ if isAtOriginalTyconDefn then
+ ModuleOrMemberBinding, reqTypars
+
+ else
+ let isInSameModuleOrNamespace =
+ match envForDecls.eModuleOrNamespaceTypeAccumulator.Value.TypesByMangledName.TryGetValue tcref.LogicalName with
+ | true, tycon -> tyconOrder.Compare(tcref.Deref, tycon) = 0
+ | _ ->
+ //false
+ // There is a special case we allow when compiling FSharp.Core.dll which permits interface implementations across namespace fragments
+ g.compilingFslib && tcref.LogicalName.StartsWithOrdinal("Tuple`")
+
+ let nReqTypars = reqTypars.Length
+
+ let declaredTypars = TcTyparDecls cenv envForDecls synTypars
+ let envForTycon = AddDeclaredTypars CheckForDuplicateTypars declaredTypars envForDecls
+ let _tpenv = TcTyparConstraints cenv NoNewTypars CheckCxs ItemOccurence.UseInType envForTycon emptyUnscopedTyparEnv synTyparCxs
+ declaredTypars |> List.iter (SetTyparRigid envForDecls.DisplayEnv m)
+
+ if isInSameModuleOrNamespace && not isInterfaceOrDelegateOrEnum then
+ // For historical reasons we only give a warning for incorrect type parameters on intrinsic extensions
+ if nReqTypars <> synTypars.Length then
+ warning(Error(FSComp.SR.tcDeclaredTypeParametersForExtensionDoNotMatchOriginal(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m))
+ if not (typarsAEquiv g TypeEquivEnv.Empty reqTypars declaredTypars) then
+ warning(Error(FSComp.SR.tcDeclaredTypeParametersForExtensionDoNotMatchOriginal(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m))
+ // Note we return 'reqTypars' for intrinsic extensions since we may only have given warnings
+ IntrinsicExtensionBinding, reqTypars
+ else
+ if isInSameModuleOrNamespace && isInterfaceOrDelegateOrEnum then
+ errorR(Error(FSComp.SR.tcMembersThatExtendInterfaceMustBePlacedInSeparateModule(), tcref.Range))
+ if nReqTypars <> synTypars.Length then
+ error(Error(FSComp.SR.tcDeclaredTypeParametersForExtensionDoNotMatchOriginal(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m))
+ if not (typarsAEquiv g TypeEquivEnv.Empty reqTypars declaredTypars) then
+ errorR(Error(FSComp.SR.tcDeclaredTypeParametersForExtensionDoNotMatchOriginal(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m))
+ ExtrinsicExtensionBinding, declaredTypars
+
+
+ declKind, tcref, typars
+
+
+ let private isAugmentationTyconDefnRepr = function (SynTypeDefnSimpleRepr.General(TyconAugmentation, _, _, _, _, _, _, _)) -> true | _ -> false
+ let private isAutoProperty = function SynMemberDefn.AutoProperty _ -> true | _ -> false
+ let private isMember = function SynMemberDefn.Member _ -> true | _ -> false
+ let private isImplicitCtor = function SynMemberDefn.ImplicitCtor _ -> true | _ -> false
+ let private isImplicitInherit = function SynMemberDefn.ImplicitInherit _ -> true | _ -> false
+ let private isAbstractSlot = function SynMemberDefn.AbstractSlot _ -> true | _ -> false
+ let private isInterface = function SynMemberDefn.Interface _ -> true | _ -> false
+ let private isInherit = function SynMemberDefn.Inherit _ -> true | _ -> false
+ let private isField = function SynMemberDefn.ValField (_, _) -> true | _ -> false
+ let private isTycon = function SynMemberDefn.NestedType _ -> true | _ -> false
+
+ let private allFalse ps x = List.forall (fun p -> not (p x)) ps
+
+ /// Check the ordering on the bindings and members in a class construction
+ // Accepted forms:
+ //
+ // Implicit Construction:
+ // implicit_ctor
+ // optional implicit_inherit
+ // multiple bindings
+ // multiple member-binding(includes-overrides) or abstract-slot-declaration or interface-bindings
+ //
+ // Classic construction:
+ // multiple (binding or slotsig or field or interface or inherit).
+ // i.e. not local-bindings, implicit ctor or implicit inherit (or tycon?).
+ // atMostOne inherit.
+ let private CheckMembersForm ds =
+ match ds with
+ | d :: ds when isImplicitCtor d ->
+ // Implicit construction
+ let ds =
+ match ds with
+ | d :: ds when isImplicitInherit d -> ds // skip inherit call if it comes next
+ | _ -> ds
+
+ // Skip over 'let' and 'do' bindings
+ let _, ds = ds |> List.takeUntil (function SynMemberDefn.LetBindings _ -> false | _ -> true)
+
+ // Skip over 'let' and 'do' bindings
+ let _, ds = ds |> List.takeUntil (allFalse [isMember;isAbstractSlot;isInterface;isAutoProperty])
+
+ match ds with
+ | SynMemberDefn.Member (_, m) :: _ -> errorR(InternalError("List.takeUntil is wrong, have binding", m))
+ | SynMemberDefn.AbstractSlot (_, _, m) :: _ -> errorR(InternalError("List.takeUntil is wrong, have slotsig", m))
+ | SynMemberDefn.Interface (_, _, m) :: _ -> errorR(InternalError("List.takeUntil is wrong, have interface", m))
+ | SynMemberDefn.ImplicitCtor (_, _, _, _, _, m) :: _ -> errorR(InternalError("implicit class construction with two implicit constructions", m))
+ | SynMemberDefn.AutoProperty (_, _, _, _, _, _, _, _, _, _, m) :: _ -> errorR(InternalError("List.takeUntil is wrong, have auto property", m))
+ | SynMemberDefn.ImplicitInherit (_, _, _, m) :: _ -> errorR(Error(FSComp.SR.tcTypeDefinitionsWithImplicitConstructionMustHaveOneInherit(), m))
+ | SynMemberDefn.LetBindings (_, _, _, m) :: _ -> errorR(Error(FSComp.SR.tcTypeDefinitionsWithImplicitConstructionMustHaveLocalBindingsBeforeMembers(), m))
+ | SynMemberDefn.Inherit (_, _, m) :: _ -> errorR(Error(FSComp.SR.tcInheritDeclarationMissingArguments(), m))
+ | SynMemberDefn.NestedType (_, _, m) :: _ -> errorR(Error(FSComp.SR.tcTypesCannotContainNestedTypes(), m))
+ | _ -> ()
+ | ds ->
+ // Classic class construction
+ let _, ds = List.takeUntil (allFalse [isMember;isAbstractSlot;isInterface;isInherit;isField;isTycon]) ds
+ match ds with
+ | SynMemberDefn.Member (_, m) :: _ -> errorR(InternalError("CheckMembersForm: List.takeUntil is wrong", m))
+ | SynMemberDefn.ImplicitCtor (_, _, _, _, _, m) :: _ -> errorR(InternalError("CheckMembersForm: implicit ctor line should be first", m))
+ | SynMemberDefn.ImplicitInherit (_, _, _, m) :: _ -> errorR(Error(FSComp.SR.tcInheritConstructionCallNotPartOfImplicitSequence(), m))
+ | SynMemberDefn.AutoProperty(_, _, _, _, _, _, _, _, _, _, m) :: _ -> errorR(Error(FSComp.SR.tcAutoPropertyRequiresImplicitConstructionSequence(), m))
+ | SynMemberDefn.LetBindings (_, false, _, m) :: _ -> errorR(Error(FSComp.SR.tcLetAndDoRequiresImplicitConstructionSequence(), m))
+ | SynMemberDefn.AbstractSlot (_, _, m) :: _
+ | SynMemberDefn.Interface (_, _, m) :: _
+ | SynMemberDefn.Inherit (_, _, m) :: _
+ | SynMemberDefn.ValField (_, m) :: _
+ | SynMemberDefn.NestedType (_, _, m) :: _ -> errorR(InternalError("CheckMembersForm: List.takeUntil is wrong", m))
+ | _ -> ()
+
+
+ /// Separates the definition into core (shape) and body.
+ ///
+ /// core = synTyconInfo, simpleRepr, interfaceTypes
+ /// where simpleRepr can contain inherit type, declared fields and virtual slots.
+ /// body = members
+ /// where members contain methods/overrides, also implicit ctor, inheritCall and local definitions.
+ let rec private SplitTyconDefn (TypeDefn(synTyconInfo, trepr, extraMembers, _)) =
+ let implements1 = List.choose (function SynMemberDefn.Interface (ty, _, _) -> Some(ty, ty.Range) | _ -> None) extraMembers
+ match trepr with
+ | SynTypeDefnRepr.ObjectModel(kind, cspec, m) ->
+ CheckMembersForm cspec
+ let fields = cspec |> List.choose (function SynMemberDefn.ValField (f, _) -> Some f | _ -> None)
+ let implements2 = cspec |> List.choose (function SynMemberDefn.Interface (ty, _, _) -> Some(ty, ty.Range) | _ -> None)
+ let inherits =
+ cspec |> List.choose (function
+ | SynMemberDefn.Inherit (ty, idOpt, m) -> Some(ty, m, idOpt)
+ | SynMemberDefn.ImplicitInherit (ty, _, idOpt, m) -> Some(ty, m, idOpt)
+ | _ -> None)
+ //let nestedTycons = cspec |> List.choose (function SynMemberDefn.NestedType (x, _, _) -> Some x | _ -> None)
+ let slotsigs = cspec |> List.choose (function SynMemberDefn.AbstractSlot (x, y, _) -> Some(x, y) | _ -> None)
+
+ let members =
+ let membersIncludingAutoProps =
+ cspec |> List.filter (fun memb ->
+ match memb with
+ | SynMemberDefn.Interface _
+ | SynMemberDefn.Member _
+ | SynMemberDefn.LetBindings _
+ | SynMemberDefn.ImplicitCtor _
+ | SynMemberDefn.AutoProperty _
+ | SynMemberDefn.Open _
+ | SynMemberDefn.ImplicitInherit _ -> true
+ | SynMemberDefn.NestedType (_, _, m) -> error(Error(FSComp.SR.tcTypesCannotContainNestedTypes(), m)); false
+ // covered above
+ | SynMemberDefn.ValField _
+ | SynMemberDefn.Inherit _
+ | SynMemberDefn.AbstractSlot _ -> false)
+
+ // Convert auto properties to let bindings in the pre-list
+ let rec preAutoProps memb =
+ match memb with
+ | SynMemberDefn.AutoProperty(Attributes attribs, isStatic, id, tyOpt, propKind, _, xmlDoc, _access, synExpr, _mGetSet, mWholeAutoProp) ->
+ // Only the keep the field-targeted attributes
+ let attribs = attribs |> List.filter (fun a -> match a.Target with Some t when t.idText = "field" -> true | _ -> false)
+ let mLetPortion = synExpr.Range
+ let fldId = ident (CompilerGeneratedName id.idText, mLetPortion)
+ let headPat = SynPat.LongIdent (LongIdentWithDots([fldId], []), None, Some noInferredTypars, SynArgPats.Pats [], None, mLetPortion)
+ let retInfo = match tyOpt with None -> None | Some ty -> Some (SynReturnInfo((ty, SynInfo.unnamedRetVal), ty.Range))
+ let isMutable =
+ match propKind with
+ | MemberKind.PropertySet
+ | MemberKind.PropertyGetSet -> true
+ | _ -> false
+ let attribs = mkAttributeList attribs mWholeAutoProp
+ let binding = mkSynBinding (xmlDoc, headPat) (None, false, isMutable, mLetPortion, NoDebugPointAtInvisibleBinding, retInfo, synExpr, synExpr.Range, [], attribs, None)
+
+ [(SynMemberDefn.LetBindings ([binding], isStatic, false, mWholeAutoProp))]
+
+ | SynMemberDefn.Interface (_, Some membs, _) -> membs |> List.collect preAutoProps
+ | SynMemberDefn.LetBindings _
+ | SynMemberDefn.ImplicitCtor _
+ | SynMemberDefn.Open _
+ | SynMemberDefn.ImplicitInherit _ -> [memb]
+ | _ -> []
+
+ // Convert auto properties to member bindings in the post-list
+ let rec postAutoProps memb =
+ match memb with
+ | SynMemberDefn.AutoProperty(Attributes attribs, isStatic, id, tyOpt, propKind, memberFlags, xmlDoc, access, _synExpr, mGetSetOpt, _mWholeAutoProp) ->
+ let mMemberPortion = id.idRange
+ // Only the keep the non-field-targeted attributes
+ let attribs = attribs |> List.filter (fun a -> match a.Target with Some t when t.idText = "field" -> false | _ -> true)
+ let fldId = ident (CompilerGeneratedName id.idText, mMemberPortion)
+ let headPatIds = if isStatic then [id] else [ident ("__", mMemberPortion);id]
+ let headPat = SynPat.LongIdent (LongIdentWithDots(headPatIds, []), None, Some noInferredTypars, SynArgPats.Pats [], None, mMemberPortion)
+
+ match propKind, mGetSetOpt with
+ | MemberKind.PropertySet, Some m -> errorR(Error(FSComp.SR.parsMutableOnAutoPropertyShouldBeGetSetNotJustSet(), m))
+ | _ -> ()
+
+ [
+ match propKind with
+ | MemberKind.Member
+ | MemberKind.PropertyGet
+ | MemberKind.PropertyGetSet ->
+ let getter =
+ let rhsExpr = SynExpr.Ident fldId
+ let retInfo = match tyOpt with None -> None | Some ty -> Some (SynReturnInfo((ty, SynInfo.unnamedRetVal), ty.Range))
+ let attribs = mkAttributeList attribs mMemberPortion
+ let binding = mkSynBinding (xmlDoc, headPat) (access, false, false, mMemberPortion, NoDebugPointAtInvisibleBinding, retInfo, rhsExpr, rhsExpr.Range, [], attribs, Some (memberFlags MemberKind.Member))
+ SynMemberDefn.Member (binding, mMemberPortion)
+ yield getter
+ | _ -> ()
+
+ match propKind with
+ | MemberKind.PropertySet
+ | MemberKind.PropertyGetSet ->
+ let setter =
+ let vId = ident("v", mMemberPortion)
+ let headPat = SynPat.LongIdent (LongIdentWithDots(headPatIds, []), None, Some noInferredTypars, SynArgPats.Pats [mkSynPatVar None vId], None, mMemberPortion)
+ let rhsExpr = mkSynAssign (SynExpr.Ident fldId) (SynExpr.Ident vId)
+ //let retInfo = match tyOpt with None -> None | Some ty -> Some (SynReturnInfo((ty, SynInfo.unnamedRetVal), ty.Range))
+ let binding = mkSynBinding (xmlDoc, headPat) (access, false, false, mMemberPortion, NoDebugPointAtInvisibleBinding, None, rhsExpr, rhsExpr.Range, [], [], Some (memberFlags MemberKind.PropertySet))
+ SynMemberDefn.Member (binding, mMemberPortion)
+ yield setter
+ | _ -> ()]
+ | SynMemberDefn.Interface (ty, Some membs, m) ->
+ let membs' = membs |> List.collect postAutoProps
+ [SynMemberDefn.Interface (ty, Some membs', m)]
+ | SynMemberDefn.LetBindings _
+ | SynMemberDefn.ImplicitCtor _
+ | SynMemberDefn.Open _
+ | SynMemberDefn.ImplicitInherit _ -> []
+ | _ -> [memb]
+
+ let preMembers = membersIncludingAutoProps |> List.collect preAutoProps
+ let postMembers = membersIncludingAutoProps |> List.collect postAutoProps
+
+ preMembers @ postMembers
+
+ let isConcrete =
+ members |> List.exists (function
+ | SynMemberDefn.Member(Binding(_, _, _, _, _, _, SynValData(Some memberFlags, _, _), _, _, _, _, _), _) -> not memberFlags.IsDispatchSlot
+ | SynMemberDefn.Interface (_, defOpt, _) -> Option.isSome defOpt
+ | SynMemberDefn.LetBindings _ -> true
+ | SynMemberDefn.ImplicitCtor _ -> true
+ | SynMemberDefn.ImplicitInherit _ -> true
+ | _ -> false)
+
+ let isIncrClass =
+ members |> List.exists (function
+ | SynMemberDefn.ImplicitCtor _ -> true
+ | _ -> false)
+
+ let hasSelfReferentialCtor =
+ members |> List.exists (function
+ | SynMemberDefn.ImplicitCtor (_, _, _, thisIdOpt, _, _)
+ | SynMemberDefn.Member(Binding(_, _, _, _, _, _, SynValData(_, _, thisIdOpt), _, _, _, _, _), _) -> thisIdOpt.IsSome
+ | _ -> false)
+
+ let implicitCtorSynPats =
+ members |> List.tryPick (function
+ | SynMemberDefn.ImplicitCtor (_, _, (SynSimplePats.SimplePats _ as spats), _, _, _) -> Some spats
+ | _ -> None)
+
+ // An ugly bit of code to pre-determine if a type has a nullary constructor, prior to establishing the
+ // members of the type
+ let preEstablishedHasDefaultCtor =
+ members |> List.exists (function
+ | SynMemberDefn.Member(Binding(_, _, _, _, _, _, SynValData(Some memberFlags, _, _), SynPatForConstructorDecl SynPatForNullaryArgs, _, _, _, _), _) ->
+ memberFlags.MemberKind=MemberKind.Constructor
+ | SynMemberDefn.ImplicitCtor (_, _, SynSimplePats.SimplePats(spats, _), _, _, _) -> isNil spats
+ | _ -> false)
+ let repr = SynTypeDefnSimpleRepr.General(kind, inherits, slotsigs, fields, isConcrete, isIncrClass, implicitCtorSynPats, m)
+ let isAtOriginalTyconDefn = not (isAugmentationTyconDefnRepr repr)
+ let core = MutRecDefnsPhase1DataForTycon(synTyconInfo, repr, implements2@implements1, preEstablishedHasDefaultCtor, hasSelfReferentialCtor, isAtOriginalTyconDefn)
+
+ core, members @ extraMembers
+
+ | SynTypeDefnRepr.Simple(repr, _) ->
+ let members = []
+ let isAtOriginalTyconDefn = true
+ let core = MutRecDefnsPhase1DataForTycon(synTyconInfo, repr, implements1, false, false, isAtOriginalTyconDefn)
+ core, members @ extraMembers
+
+ | SynTypeDefnRepr.Exception r ->
+ let isAtOriginalTyconDefn = true
+ let core = MutRecDefnsPhase1DataForTycon(synTyconInfo, SynTypeDefnSimpleRepr.Exception r, implements1, false, false, isAtOriginalTyconDefn)
+ core, extraMembers
+
+ //-------------------------------------------------------------------------
+
+ /// Bind a collection of mutually recursive definitions in an implementation file
+ let TcMutRecDefinitions (cenv: cenv) envInitial parent typeNames tpenv m scopem mutRecNSInfo (mutRecDefns: MutRecDefnsInitialData) =
+
+ // Split the definitions into "core representations" and "members". The code to process core representations
+ // is shared between processing of signature files and implementation files.
+ let mutRecDefnsAfterSplit = mutRecDefns |> MutRecShapes.mapTycons SplitTyconDefn
+
+ // Create the entities for each module and type definition, and process the core representation of each type definition.
+ let tycons, envMutRecPrelim, mutRecDefnsAfterCore =
+ EstablishTypeDefinitionCores.TcMutRecDefns_Phase1
+ (fun containerInfo synBinds -> [ for synBind in synBinds -> RecDefnBindingInfo(containerInfo, NoNewSlots, ModuleOrMemberBinding, synBind) ])
+ cenv envInitial parent typeNames false tpenv m scopem mutRecNSInfo mutRecDefnsAfterSplit
+
+ // Package up the phase two information for processing members.
+ let mutRecDefnsAfterPrep =
+ (envMutRecPrelim, mutRecDefnsAfterCore)
+ ||> MutRecShapes.mapTyconsWithEnv (fun envForDecls ((typeDefnCore, members, innerParent), tyconOpt, fixupFinalAttrs, (baseValOpt, safeInitInfo)) ->
+ let (MutRecDefnsPhase1DataForTycon(synTyconInfo, _, _, _, _, isAtOriginalTyconDefn)) = typeDefnCore
+ let tyDeclRange = synTyconInfo.Range
+ let (ComponentInfo(_, typars, cs, longPath, _, _, _, _)) = synTyconInfo
+ let declKind, tcref, declaredTyconTypars = ComputeTyconDeclKind cenv envForDecls tyconOpt isAtOriginalTyconDefn false tyDeclRange typars cs longPath
+ let newslotsOK = (if isAtOriginalTyconDefn && tcref.IsFSharpObjectModelTycon then NewSlotsOK else NoNewSlots)
+
+ if (declKind = ExtrinsicExtensionBinding) && isByrefTyconRef cenv.g tcref then
+ error(Error(FSComp.SR.tcByrefsMayNotHaveTypeExtensions(), tyDeclRange))
+
+ if not (isNil members) && tcref.IsTypeAbbrev then
+ errorR(Error(FSComp.SR.tcTypeAbbreviationsCannotHaveAugmentations(), tyDeclRange))
+
+ let (ComponentInfo (attributes, _, _, _, _, _, _, _)) = synTyconInfo
+ if not (List.isEmpty attributes) && (declKind = ExtrinsicExtensionBinding || declKind = IntrinsicExtensionBinding) then
+ let attributeRange = (List.head attributes).Range
+ error(Error(FSComp.SR.tcAugmentationsCannotHaveAttributes(), attributeRange))
+
+ MutRecDefnsPhase2DataForTycon(tyconOpt, innerParent, declKind, tcref, baseValOpt, safeInitInfo, declaredTyconTypars, members, tyDeclRange, newslotsOK, fixupFinalAttrs))
+
+ // By now we've established the full contents of type definitions apart from their
+ // members and any fields determined by implicit construction. We know the kinds and
+ // representations of types and have established them as valid.
+ //
+ // We now reconstruct the active environments all over again - this will add the union cases and fields.
+ //
+ // Note: This environment reconstruction doesn't seem necessary. We're about to create Val's for all members,
+ // which does require type checking, but no more information than is already available.
+ let envMutRecPrelimWithReprs, withEnvs =
+ (envInitial, MutRecShapes.dropEnvs mutRecDefnsAfterPrep)
+ ||> MutRecBindingChecking.TcMutRecDefns_ComputeEnvs
+ (fun (MutRecDefnsPhase2DataForTycon(tyconOpt, _, _, _, _, _, _, _, _, _, _)) -> tyconOpt)
+ (fun _binds -> [ (* no values are available yet *) ])
+ cenv true scopem m
+
+ // Check the members and decide on representations for types with implicit constructors.
+ let withBindings, envFinal = TcMutRecDefns_Phase2 cenv envInitial m scopem mutRecNSInfo envMutRecPrelimWithReprs withEnvs
+
+ // Generate the hash/compare/equality bindings for all tycons.
+ //
+ // Note: generating these bindings must come after generating the members, since some in the case of structs some fields
+ // may be added by generating the implicit construction syntax
+ let withExtraBindings =
+ (envFinal, withBindings) ||> MutRecShapes.expandTyconsWithEnv (fun envForDecls (tyconOpt, _) ->
+ match tyconOpt with
+ | None -> [], []
+ | Some tycon ->
+ // We put the hash/compare bindings before the type definitions and the
+ // equality bindings after because tha is the order they've always been generated
+ // in, and there are code generation tests to check that.
+ let binds = AddAugmentationDeclarations.AddGenericHashAndComparisonBindings cenv tycon
+ let binds3 = AddAugmentationDeclarations.AddGenericEqualityBindings cenv envForDecls tycon
+ binds, binds3)
+
+ // Check for cyclic structs and inheritance all over again, since we may have added some fields to the struct when generating the implicit construction syntax
+ EstablishTypeDefinitionCores.TcTyconDefnCore_CheckForCyclicStructsAndInheritance cenv tycons
+
+ withExtraBindings, envFinal
+
+
+ //-------------------------------------------------------------------------
+
+ /// Separates the signature declaration into core (shape) and body.
+ let rec private SplitTyconSignature (TypeDefnSig(synTyconInfo, trepr, extraMembers, _)) =
+
+ let implements1 =
+ extraMembers |> List.choose (function SynMemberSig.Interface (f, m) -> Some(f, m) | _ -> None)
+
+ match trepr with
+ | SynTypeDefnSigRepr.ObjectModel(kind, cspec, m) ->
+ let fields = cspec |> List.choose (function SynMemberSig.ValField (f, _) -> Some f | _ -> None)
+ let implements2 = cspec |> List.choose (function SynMemberSig.Interface (ty, m) -> Some(ty, m) | _ -> None)
+ let inherits = cspec |> List.choose (function SynMemberSig.Inherit (ty, _) -> Some(ty, m, None) | _ -> None)
+ //let nestedTycons = cspec |> List.choose (function SynMemberSig.NestedType (x, _) -> Some x | _ -> None)
+ let slotsigs = cspec |> List.choose (function SynMemberSig.Member (v, fl, _) when fl.IsDispatchSlot -> Some(v, fl) | _ -> None)
+ let members = cspec |> List.filter (function
+ | SynMemberSig.Interface _ -> true
+ | SynMemberSig.Member (_, memberFlags, _) when not memberFlags.IsDispatchSlot -> true
+ | SynMemberSig.NestedType (_, m) -> error(Error(FSComp.SR.tcTypesCannotContainNestedTypes(), m)); false
+ | _ -> false)
+ let isConcrete =
+ members |> List.exists (function
+ | SynMemberSig.Member (_, memberFlags, _) -> memberFlags.MemberKind=MemberKind.Constructor
+ | _ -> false)
+
+ // An ugly bit of code to pre-determine if a type has a nullary constructor, prior to establishing the
+ // members of the type
+ let preEstablishedHasDefaultCtor =
+ members |> List.exists (function
+ | SynMemberSig.Member (valSpfn, memberFlags, _) ->
+ memberFlags.MemberKind=MemberKind.Constructor &&
+ // REVIEW: This is a syntactic approximation
+ (match valSpfn.SynType, valSpfn.SynInfo.CurriedArgInfos with
+ | StripParenTypes (SynType.Fun (StripParenTypes (SynType.LongIdent (LongIdentWithDots([id], _))), _, _)), [[_]] when id.idText = "unit" -> true
+ | _ -> false)
+ | _ -> false)
+
+ let hasSelfReferentialCtor = false
+
+ let repr = SynTypeDefnSimpleRepr.General(kind, inherits, slotsigs, fields, isConcrete, false, None, m)
+ let isAtOriginalTyconDefn = true
+ let tyconCore = MutRecDefnsPhase1DataForTycon (synTyconInfo, repr, implements2@implements1, preEstablishedHasDefaultCtor, hasSelfReferentialCtor, isAtOriginalTyconDefn)
+
+ tyconCore, (synTyconInfo, members@extraMembers)
+
+ // 'type X with ...' in a signature is always interpreted as an extrinsic extension.
+ // Representation-hidden types with members and interfaces are written 'type X = ...'
+ | SynTypeDefnSigRepr.Simple((SynTypeDefnSimpleRepr.None _ as r), _) when not (isNil extraMembers) ->
+ let isAtOriginalTyconDefn = false
+ let tyconCore = MutRecDefnsPhase1DataForTycon (synTyconInfo, r, implements1, false, false, isAtOriginalTyconDefn)
+ tyconCore, (synTyconInfo, extraMembers)
+
+ | SynTypeDefnSigRepr.Exception r ->
+ let isAtOriginalTyconDefn = true
+ let core = MutRecDefnsPhase1DataForTycon(synTyconInfo, SynTypeDefnSimpleRepr.Exception r, implements1, false, false, isAtOriginalTyconDefn)
+ core, (synTyconInfo, extraMembers)
+
+ | SynTypeDefnSigRepr.Simple(r, _) ->
+ let isAtOriginalTyconDefn = true
+ let tyconCore = MutRecDefnsPhase1DataForTycon (synTyconInfo, r, implements1, false, false, isAtOriginalTyconDefn)
+ tyconCore, (synTyconInfo, extraMembers)
+
+
+ let private TcMutRecSignatureDecls_Phase2 (cenv: cenv) scopem envMutRec mutRecDefns =
+ (envMutRec, mutRecDefns) ||> MutRecShapes.mapWithEnv
+ // Do this for the members in each 'type' declaration
+ (fun envForDecls ((tyconCore, (synTyconInfo, members), innerParent), tyconOpt, _fixupFinalAttrs, _) ->
+ let tpenv = emptyUnscopedTyparEnv
+ let (MutRecDefnsPhase1DataForTycon (_, _, _, _, _, isAtOriginalTyconDefn)) = tyconCore
+ let (ComponentInfo(_, typars, cs, longPath, _, _, _, m)) = synTyconInfo
+ let declKind, tcref, declaredTyconTypars = ComputeTyconDeclKind cenv envForDecls tyconOpt isAtOriginalTyconDefn true m typars cs longPath
+
+ let envForTycon = AddDeclaredTypars CheckForDuplicateTypars declaredTyconTypars envForDecls
+ let envForTycon = MakeInnerEnvForTyconRef envForTycon tcref (declKind = ExtrinsicExtensionBinding)
+
+ TcTyconMemberSpecs cenv envForTycon (TyconContainerInfo(innerParent, tcref, declaredTyconTypars, NoSafeInitInfo)) declKind tpenv members)
+
+ // Do this for each 'val' declaration in a module
+ (fun envForDecls (containerInfo, valSpec) ->
+ let tpenv = emptyUnscopedTyparEnv
+ let idvs, _ = TcAndPublishValSpec (cenv, envForDecls, containerInfo, ModuleOrMemberBinding, None, tpenv, valSpec)
+ let env = List.foldBack (AddLocalVal cenv.tcSink scopem) idvs envForDecls
+ env)
+
+
+ /// Bind a collection of mutually recursive declarations in a signature file
+ let TcMutRecSignatureDecls (cenv: cenv) envInitial parent typeNames tpenv m scopem mutRecNSInfo (mutRecSigs: MutRecSigsInitialData) =
+ let mutRecSigsAfterSplit = mutRecSigs |> MutRecShapes.mapTycons SplitTyconSignature
+ let _tycons, envMutRec, mutRecDefnsAfterCore =
+ EstablishTypeDefinitionCores.TcMutRecDefns_Phase1
+ (fun containerInfo valDecl -> (containerInfo, valDecl))
+ cenv envInitial parent typeNames true tpenv m scopem mutRecNSInfo mutRecSigsAfterSplit
+
+ // Updates the types of the modules to contain the contents so far, which now includes values and members
+ MutRecBindingChecking.TcMutRecDefns_UpdateModuleContents mutRecNSInfo mutRecDefnsAfterCore
+
+ // By now we've established the full contents of type definitions apart from their
+ // members and any fields determined by implicit construction. We know the kinds and
+ // representations of types and have established them as valid.
+ //
+ // We now reconstruct the active environments all over again - this will add the union cases and fields.
+ //
+ // Note: This environment reconstruction doesn't seem necessary. We're about to create Val's for all members,
+ // which does require type checking, but no more information than is already available.
+ let envMutRecPrelimWithReprs, withEnvs =
+ (envInitial, MutRecShapes.dropEnvs mutRecDefnsAfterCore)
+ ||> MutRecBindingChecking.TcMutRecDefns_ComputeEnvs
+ (fun (_, tyconOpt, _, _) -> tyconOpt)
+ (fun _binds -> [ (* no values are available yet *) ])
+ cenv true scopem m
+
+ let mutRecDefnsAfterVals = TcMutRecSignatureDecls_Phase2 cenv scopem envMutRecPrelimWithReprs withEnvs
+
+ // Updates the types of the modules to contain the contents so far, which now includes values and members
+ MutRecBindingChecking.TcMutRecDefns_UpdateModuleContents mutRecNSInfo mutRecDefnsAfterVals
+
+ envMutRec
+
+//-------------------------------------------------------------------------
+// Bind module types
+//-------------------------------------------------------------------------
+
+let rec TcSignatureElementNonMutRec cenv parent typeNames endm (env: TcEnv) synSigDecl: Eventually =
+ eventually {
+ try
+ match synSigDecl with
+ | SynModuleSigDecl.Exception (edef, m) ->
+ let scopem = unionRanges m.EndRange endm
+ let _, _, _, env = TcExceptionDeclarations.TcExnSignature cenv env parent emptyUnscopedTyparEnv (edef, scopem)
+ return env
+
+ | SynModuleSigDecl.Types (typeSpecs, m) ->
+ let scopem = unionRanges m endm
+ let mutRecDefns = typeSpecs |> List.map MutRecShape.Tycon
+ let env = TcDeclarations.TcMutRecSignatureDecls cenv env parent typeNames emptyUnscopedTyparEnv m scopem None mutRecDefns
+ return env
+
+ | SynModuleSigDecl.Open (target, m) ->
+ let scopem = unionRanges m.EndRange endm
+ let env = TcOpenDecl cenv m scopem env target
+ return env
+
+ | SynModuleSigDecl.Val (vspec, m) ->
+ let parentModule =
+ match parent with
+ | ParentNone -> error(NumberedError(FSComp.SR.tcNamespaceCannotContainValues(), vspec.RangeOfId))
+ | Parent p -> p
+ let containerInfo = ModuleOrNamespaceContainerInfo parentModule
+ let idvs, _ = TcAndPublishValSpec (cenv, env, containerInfo, ModuleOrMemberBinding, None, emptyUnscopedTyparEnv, vspec)
+ let scopem = unionRanges m endm
+ let env = List.foldBack (AddLocalVal cenv.tcSink scopem) idvs env
+ return env
+
+ | SynModuleSigDecl.NestedModule(ComponentInfo(Attributes attribs, _parms, _constraints, longPath, xml, _, vis, im) as compInfo, isRec, mdefs, m) ->
+ if isRec then
+ // Treat 'module rec M = ...' as a single mutually recursive definition group 'module M = ...'
+ let modDecl = SynModuleSigDecl.NestedModule(compInfo, false, mdefs, m)
+
+ return! TcSignatureElementsMutRec cenv parent typeNames endm None env [modDecl]
+ else
+ let id = ComputeModuleName longPath
+ let vis, _ = ComputeAccessAndCompPath env None im vis None parent
+ let attribs = TcAttributes cenv env AttributeTargets.ModuleDecl attribs
+ CheckNamespaceModuleOrTypeName cenv.g id
+ let modKind = EstablishTypeDefinitionCores.ComputeModuleOrNamespaceKind cenv.g true typeNames attribs id.idText
+ let modName = EstablishTypeDefinitionCores.AdjustModuleName modKind id.idText
+ CheckForDuplicateConcreteType env modName id.idRange
+
+ // Now typecheck the signature, accumulating and then recording the submodule description.
+ let id = ident (modName, id.idRange)
+
+ let mty = Construct.NewEmptyModuleOrNamespaceType modKind
+ let doc = xml.ToXmlDoc(true, Some [])
+ let mspec = Construct.NewModuleOrNamespace (Some env.eCompPath) vis id doc attribs (MaybeLazy.Strict mty)
+
+ let! (mtyp, _) = TcModuleOrNamespaceSignatureElementsNonMutRec cenv (Parent (mkLocalModRef mspec)) env (id, modKind, mdefs, m, xml)
+
+ mspec.entity_modul_contents <- MaybeLazy.Strict mtyp
+ let scopem = unionRanges m endm
+ PublishModuleDefn cenv env mspec
+ let env = AddLocalSubModuleAndReport cenv.tcSink scopem cenv.g cenv.amap m env mspec
+ return env
+
+ | SynModuleSigDecl.ModuleAbbrev (id, p, m) ->
+ let ad = env.AccessRights
+ let resolved =
+ match p with
+ | [] -> Result []
+ | id :: rest -> ResolveLongIdentAsModuleOrNamespace cenv.tcSink ResultCollectionSettings.AllResults cenv.amap m true OpenQualified env.NameEnv ad id rest false
+ let mvvs = ForceRaise resolved
+ let scopem = unionRanges m endm
+ let unfilteredModrefs = mvvs |> List.map p23
+
+ let modrefs = unfilteredModrefs |> List.filter (fun modref -> not modref.IsNamespace)
+
+ if not (List.isEmpty unfilteredModrefs) && List.isEmpty modrefs then
+ errorR(Error(FSComp.SR.tcModuleAbbreviationForNamespace(fullDisplayTextOfModRef (List.head unfilteredModrefs)), m))
+
+ if List.isEmpty modrefs then return env else
+ modrefs |> List.iter (fun modref -> CheckEntityAttributes cenv.g modref m |> CommitOperationResult)
+
+ let env = AddModuleAbbreviationAndReport cenv.tcSink scopem id modrefs env
+ return env
+
+ | SynModuleSigDecl.HashDirective _ ->
+ return env
+
+
+ | SynModuleSigDecl.NamespaceFragment (SynModuleOrNamespaceSig(longId, isRec, kind, defs, xml, attribs, vis, m)) ->
+
+ do for id in longId do
+ CheckNamespaceModuleOrTypeName cenv.g id
+
+ // Logically speaking, this changes
+ // module [rec] A.B.M
+ // ...
+ // to
+ // namespace [rec] A.B
+ // module M = ...
+ let enclosingNamespacePath, defs =
+ if kind.IsModule then
+ let nsp, modName = List.frontAndBack longId
+ let modDecl = [SynModuleSigDecl.NestedModule(ComponentInfo(attribs, [], [], [modName], xml, false, vis, m), false, defs, m)]
+ nsp, modDecl
+ else
+ longId, defs
+
+ let envNS = LocateEnv cenv.topCcu env enclosingNamespacePath
+ let envNS = ImplicitlyOpenOwnNamespace cenv.tcSink cenv.g cenv.amap m enclosingNamespacePath envNS
+
+ // For 'namespace rec' and 'module rec' we add the thing being defined
+ let mtypNS = !(envNS.eModuleOrNamespaceTypeAccumulator)
+ let mtypRoot, mspecNSs = BuildRootModuleType enclosingNamespacePath envNS.eCompPath mtypNS
+ let mspecNSOpt = List.tryHead mspecNSs
+
+ mspecNSs |> List.iter (fun mspec ->
+ let modref = mkLocalModRef mspec
+ let item = Item.ModuleOrNamespaces [modref]
+ CallNameResolutionSink cenv.tcSink (mspec.Range, env.NameEnv, item, emptyTyparInst, ItemOccurence.Binding, env.AccessRights))
+
+ // For 'namespace rec' and 'module rec' we add the thing being defined
+ let envNS = if isRec then AddLocalRootModuleOrNamespace cenv.tcSink cenv.g cenv.amap m envNS mtypRoot else envNS
+ let nsInfo = Some (mspecNSOpt, envNS.eModuleOrNamespaceTypeAccumulator)
+ let mutRecNSInfo = if isRec then nsInfo else None
+
+ let! envAtEnd = TcSignatureElements cenv ParentNone m.EndRange envNS xml mutRecNSInfo defs
+
+ MutRecBindingChecking.TcMutRecDefns_UpdateNSContents nsInfo
+
+ let env =
+ if isNil enclosingNamespacePath then
+ envAtEnd
+ else
+ let env = AddLocalRootModuleOrNamespace cenv.tcSink cenv.g cenv.amap m env mtypRoot
+
+ // If the namespace is an interactive fragment e.g. FSI_0002, then open FSI_0002 in the subsequent environment.
+ let env =
+ match TryStripPrefixPath cenv.g enclosingNamespacePath with
+ | Some(p, _) -> TcOpenModuleOrNamespaceDecl cenv.tcSink cenv.g cenv.amap m.EndRange env ([p], m.EndRange)
+ | None -> env
+
+ // Publish the combined module type
+ env.eModuleOrNamespaceTypeAccumulator := CombineCcuContentFragments m [!(env.eModuleOrNamespaceTypeAccumulator); mtypRoot]
+ env
+
+ return env
+
+ with e ->
+ errorRecovery e endm
+ return env
+ }
+
+
+and TcSignatureElements cenv parent endm env xml mutRecNSInfo defs =
+ eventually {
+ // Ensure the .Deref call in UpdateAccModuleOrNamespaceType succeeds
+ if cenv.compilingCanonicalFslibModuleType then
+ let doc = xml.ToXmlDoc(true, Some [])
+ ensureCcuHasModuleOrNamespaceAtPath cenv.topCcu env.ePath env.eCompPath doc
+
+ let typeNames = EstablishTypeDefinitionCores.TypeNamesInNonMutRecSigDecls defs
+ match mutRecNSInfo with
+ | Some _ ->
+ return! TcSignatureElementsMutRec cenv parent typeNames endm mutRecNSInfo env defs
+ | None ->
+ return! TcSignatureElementsNonMutRec cenv parent typeNames endm env defs
+ }
+
+and TcSignatureElementsNonMutRec cenv parent typeNames endm env defs =
+ Eventually.fold (TcSignatureElementNonMutRec cenv parent typeNames endm) env defs
+
+and TcSignatureElementsMutRec cenv parent typeNames m mutRecNSInfo envInitial (defs: SynModuleSigDecl list) =
+ eventually {
+ let m = match defs with [] -> m | _ -> defs |> List.map (fun d -> d.Range) |> List.reduce unionRanges
+ let scopem = (defs, m) ||> List.foldBack (fun h m -> unionRanges h.Range m)
+
+ let mutRecDefns =
+ let rec loop isNamespace moduleRange defs: MutRecSigsInitialData =
+ ((true, true), defs) ||> List.collectFold (fun (openOk, moduleAbbrevOk) def ->
+ match def with
+ | SynModuleSigDecl.Types (typeSpecs, _) ->
+ let decls = typeSpecs |> List.map MutRecShape.Tycon
+ decls, (false, false)
+
+ | SynModuleSigDecl.Open (target, m) ->
+ if not openOk then errorR(Error(FSComp.SR.tcOpenFirstInMutRec(), m))
+ let decls = [ MutRecShape.Open (MutRecDataForOpen(target, m, moduleRange)) ]
+ decls, (openOk, moduleAbbrevOk)
+
+ | SynModuleSigDecl.Exception (SynExceptionSig(exnRepr, members, _), _) ->
+ let ( SynExceptionDefnRepr(synAttrs, UnionCase(_, id, _args, _, _, _), _, doc, vis, m)) = exnRepr
+ let compInfo = ComponentInfo(synAttrs, [], [], [id], doc, false, vis, id.idRange)
+ let decls = [ MutRecShape.Tycon(SynTypeDefnSig.TypeDefnSig(compInfo, SynTypeDefnSigRepr.Exception exnRepr, members, m)) ]
+ decls, (false, false)
+
+ | SynModuleSigDecl.Val (vspec, _) ->
+ if isNamespace then error(NumberedError(FSComp.SR.tcNamespaceCannotContainValues(), vspec.RangeOfId))
+ let decls = [ MutRecShape.Lets vspec ]
+ decls, (false, false)
+
+ | SynModuleSigDecl.NestedModule(compInfo, isRec, synDefs, moduleRange) ->
+ if isRec then warning(Error(FSComp.SR.tcRecImplied(), compInfo.Range))
+ let mutRecDefs = loop false moduleRange synDefs
+ let decls = [MutRecShape.Module (compInfo, mutRecDefs)]
+ decls, (false, false)
+
+ | SynModuleSigDecl.HashDirective _ ->
+ [], (openOk, moduleAbbrevOk)
+
+ | SynModuleSigDecl.ModuleAbbrev (id, p, m) ->
+ if not moduleAbbrevOk then errorR(Error(FSComp.SR.tcModuleAbbrevFirstInMutRec(), m))
+ let decls = [ MutRecShape.ModuleAbbrev (MutRecDataForModuleAbbrev(id, p, m)) ]
+ decls, (false, moduleAbbrevOk)
+
+ | SynModuleSigDecl.NamespaceFragment _ ->
+ error(Error(FSComp.SR.tcUnsupportedMutRecDecl(), def.Range)))
+
+ |> fst
+ loop (match parent with ParentNone -> true | Parent _ -> false) m defs
+ return TcDeclarations.TcMutRecSignatureDecls cenv envInitial parent typeNames emptyUnscopedTyparEnv m scopem mutRecNSInfo mutRecDefns
+ }
+
+
+
+and TcModuleOrNamespaceSignatureElementsNonMutRec cenv parent env (id, modKind, defs, m: range, xml) =
+
+ eventually {
+ let endm = m.EndRange // use end of range for errors
+
+ // Create the module type that will hold the results of type checking....
+ let envForModule, mtypeAcc = MakeInnerEnv true env id modKind
+
+ // Now typecheck the signature, using mutation to fill in the submodule description.
+ let! envAtEnd = TcSignatureElements cenv parent endm envForModule xml None defs
+
+ // mtypeAcc has now accumulated the module type
+ return !mtypeAcc, envAtEnd
+ }
+
+//-------------------------------------------------------------------------
+// Bind definitions within modules
+//-------------------------------------------------------------------------
+
+
+let ElimModuleDoBinding bind =
+ match bind with
+ | SynModuleDecl.DoExpr (spExpr, expr, m) ->
+ let bind2 = Binding (None, StandaloneExpression, false, false, [], PreXmlDoc.Empty, SynInfo.emptySynValData, SynPat.Wild m, None, expr, m, spExpr)
+ SynModuleDecl.Let(false, [bind2], m)
+ | _ -> bind
+
+let TcMutRecDefnsEscapeCheck (binds: MutRecShapes<_, _, _>) env =
+ let freeInEnv = GeneralizationHelpers.ComputeUnabstractableTycons env
+ let checkTycon (tycon: Tycon) =
+ if not tycon.IsTypeAbbrev && Zset.contains tycon freeInEnv then
+ let nm = tycon.DisplayName
+ errorR(Error(FSComp.SR.tcTypeUsedInInvalidWay(nm, nm, nm), tycon.Range))
+
+ binds |> MutRecShapes.iterTycons (fst >> Option.iter checkTycon)
+
+ let freeInEnv = GeneralizationHelpers.ComputeUnabstractableTraitSolutions env
+ let checkBinds (binds: Binding list) =
+ for bind in binds do
+ if Zset.contains bind.Var freeInEnv then
+ let nm = bind.Var.DisplayName
+ errorR(Error(FSComp.SR.tcMemberUsedInInvalidWay(nm, nm, nm), bind.Var.Range))
+
+ binds |> MutRecShapes.iterTyconsAndLets (snd >> checkBinds) checkBinds
+
+// ignore solitary '()' expressions and 'do ()' bindings, since these are allowed in namespaces
+// for the purposes of attaching attributes to an assembly, e.g.
+// namespace A.B.C
+// []
+// do()
+
+let CheckLetOrDoInNamespace binds m =
+ match binds with
+ | [ Binding (None, (StandaloneExpression | DoBinding), false, false, [], _, _, _, None, (SynExpr.Do (SynExpr.Const (SynConst.Unit, _), _) | SynExpr.Const (SynConst.Unit, _)), _, _) ] ->
+ ()
+ | [] ->
+ error(NumberedError(FSComp.SR.tcNamespaceCannotContainValues(), m))
+ | _ ->
+ error(NumberedError(FSComp.SR.tcNamespaceCannotContainValues(), binds.Head.RangeOfHeadPat))
+
+/// The non-mutually recursive case for a declaration
+let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem env synDecl =
+ eventually {
+ cenv.synArgNameGenerator.Reset()
+ let tpenv = emptyUnscopedTyparEnv
+
+ //printfn "----------\nCHECKING, e = %+A\n------------------\n" e
+ try
+ match ElimModuleDoBinding synDecl with
+
+ | SynModuleDecl.ModuleAbbrev (id, p, m) ->
+ let env = MutRecBindingChecking.TcModuleAbbrevDecl cenv scopem env (id, p, m)
+ return ((fun e -> e), []), env, env
+
+ | SynModuleDecl.Exception (edef, m) ->
+ let binds, decl, env = TcExceptionDeclarations.TcExnDefn cenv env parent (edef, scopem)
+ return ((fun e -> TMDefRec(true, [decl], binds |> List.map ModuleOrNamespaceBinding.Binding, m) :: e), []), env, env
+
+ | SynModuleDecl.Types (typeDefs, m) ->
+ let scopem = unionRanges m scopem
+ let mutRecDefns = typeDefs |> List.map MutRecShape.Tycon
+ let mutRecDefnsChecked, envAfter = TcDeclarations.TcMutRecDefinitions cenv env parent typeNames tpenv m scopem None mutRecDefns
+ // Check the non-escaping condition as we build the expression on the way back up
+ let exprfWithEscapeCheck e =
+ TcMutRecDefnsEscapeCheck mutRecDefnsChecked env
+ TcMutRecDefsFinish cenv mutRecDefnsChecked m :: e
+
+ return (exprfWithEscapeCheck, []), envAfter, envAfter
+
+ | SynModuleDecl.Open (target, m) ->
+ let scopem = unionRanges m.EndRange scopem
+ let env = TcOpenDecl cenv m scopem env target
+ return ((fun e -> e), []), env, env
+
+ | SynModuleDecl.Let (letrec, binds, m) ->
+
+ match parent with
+ | ParentNone ->
+ CheckLetOrDoInNamespace binds m
+ return (id, []), env, env
+
+ | Parent parentModule ->
+ let containerInfo = ModuleOrNamespaceContainerInfo parentModule
+ if letrec then
+ let scopem = unionRanges m scopem
+ let binds = binds |> List.map (fun bind -> RecDefnBindingInfo(containerInfo, NoNewSlots, ModuleOrMemberBinding, bind))
+ let binds, env, _ = TcLetrec WarnOnOverrides cenv env tpenv (binds, m, scopem)
+ return ((fun e -> TMDefRec(true, [], binds |> List.map ModuleOrNamespaceBinding.Binding, m) :: e), []), env, env
+ else
+ let binds, env, _ = TcLetBindings cenv env containerInfo ModuleOrMemberBinding tpenv (binds, m, scopem)
+ return ((fun e -> binds@e), []), env, env
+
+ | SynModuleDecl.DoExpr _ -> return! failwith "unreachable"
+
+ | SynModuleDecl.Attributes (Attributes synAttrs, _) ->
+ let attrs, _ = TcAttributesWithPossibleTargets false cenv env AttributeTargets.Top synAttrs
+ return ((fun e -> e), attrs), env, env
+
+ | SynModuleDecl.HashDirective _ ->
+ return ((fun e -> e), []), env, env
+
+ | SynModuleDecl.NestedModule(compInfo, isRec, mdefs, isContinuingModule, m) ->
+
+ // Treat 'module rec M = ...' as a single mutually recursive definition group 'module M = ...'
+ if isRec then
+ assert (not isContinuingModule)
+ let modDecl = SynModuleDecl.NestedModule(compInfo, false, mdefs, isContinuingModule, m)
+ return! TcModuleOrNamespaceElementsMutRec cenv parent typeNames m env None [modDecl]
+ else
+ let (ComponentInfo(Attributes attribs, _parms, _constraints, longPath, xml, _, vis, im)) = compInfo
+ let id = ComputeModuleName longPath
+
+ let modAttrs = TcAttributes cenv env AttributeTargets.ModuleDecl attribs
+ let modKind = EstablishTypeDefinitionCores.ComputeModuleOrNamespaceKind cenv.g true typeNames modAttrs id.idText
+ let modName = EstablishTypeDefinitionCores.AdjustModuleName modKind id.idText
+ CheckForDuplicateConcreteType env modName im
+ CheckForDuplicateModule env id.idText id.idRange
+ let vis, _ = ComputeAccessAndCompPath env None id.idRange vis None parent
+
+ let endm = m.EndRange
+ let id = ident (modName, id.idRange)
+
+ CheckNamespaceModuleOrTypeName cenv.g id
+
+ let envForModule, mtypeAcc = MakeInnerEnv true env id modKind
+
+ // Create the new module specification to hold the accumulated results of the type of the module
+ // Also record this in the environment as the accumulator
+ let mty = Construct.NewEmptyModuleOrNamespaceType modKind
+ let doc = xml.ToXmlDoc(true, Some [])
+ let mspec = Construct.NewModuleOrNamespace (Some env.eCompPath) vis id doc modAttrs (MaybeLazy.Strict mty)
+
+ // Now typecheck.
+ let! mexpr, topAttrsNew, envAtEnd = TcModuleOrNamespaceElements cenv (Parent (mkLocalModRef mspec)) endm envForModule xml None mdefs
+
+ // Get the inferred type of the decls and record it in the mspec.
+ mspec.entity_modul_contents <- MaybeLazy.Strict !mtypeAcc
+ let modDefn = TMDefRec(false, [], [ModuleOrNamespaceBinding.Module(mspec, mexpr)], m)
+ PublishModuleDefn cenv env mspec
+ let env = AddLocalSubModuleAndReport cenv.tcSink scopem cenv.g cenv.amap m env mspec
+
+ // isContinuingModule is true for all of the following
+ // - the implicit module of a script
+ // - the major 'module' declaration for a file stating with 'module X.Y'
+ // - an interactive entry for F# Interactive
+ //
+ // In this case the envAtEnd is the environment at the end of this module, which doesn't contain the module definition itself
+ // but does contain the results of all the 'open' declarations and so on.
+ let envAtEnd = (if isContinuingModule then envAtEnd else env)
+
+ return ((fun modDefs -> modDefn :: modDefs), topAttrsNew), env, envAtEnd
+
+
+ | SynModuleDecl.NamespaceFragment(SynModuleOrNamespace(longId, isRec, kind, defs, xml, attribs, vis, m)) ->
+
+ if progress then dprintn ("Typecheck implementation " + textOfLid longId)
+ let endm = m.EndRange
+
+ do for id in longId do
+ CheckNamespaceModuleOrTypeName cenv.g id
+
+ // Logically speaking, this changes
+ // module [rec] A.B.M
+ // ...
+ // to
+ // namespace [rec] A.B
+ // module M = ...
+ let enclosingNamespacePath, defs =
+ if kind.IsModule then
+ let nsp, modName = List.frontAndBack longId
+ let modDecl = [SynModuleDecl.NestedModule(ComponentInfo(attribs, [], [], [modName], xml, false, vis, m), false, defs, true, m)]
+ nsp, modDecl
+ else
+ longId, defs
+
+ let envNS = LocateEnv cenv.topCcu env enclosingNamespacePath
+ let envNS = ImplicitlyOpenOwnNamespace cenv.tcSink cenv.g cenv.amap m enclosingNamespacePath envNS
+
+ let mtypNS = !(envNS.eModuleOrNamespaceTypeAccumulator)
+ let mtypRoot, mspecNSs = BuildRootModuleType enclosingNamespacePath envNS.eCompPath mtypNS
+ let mspecNSOpt = List.tryHead mspecNSs
+
+ mspecNSs |> List.iter (fun mspec ->
+ let modref = mkLocalModRef mspec
+ let item = Item.ModuleOrNamespaces [modref]
+ CallNameResolutionSink cenv.tcSink (mspec.Range, env.NameEnv, item, emptyTyparInst, ItemOccurence.Binding, env.AccessRights))
+
+ // For 'namespace rec' and 'module rec' we add the thing being defined
+ let envNS = if isRec then AddLocalRootModuleOrNamespace cenv.tcSink cenv.g cenv.amap m envNS mtypRoot else envNS
+ let nsInfo = Some (mspecNSOpt, envNS.eModuleOrNamespaceTypeAccumulator)
+ let mutRecNSInfo = if isRec then nsInfo else None
+
+ let! modExpr, topAttrs, envAtEnd = TcModuleOrNamespaceElements cenv parent endm envNS xml mutRecNSInfo defs
+
+ MutRecBindingChecking.TcMutRecDefns_UpdateNSContents nsInfo
+
+ let env =
+ if isNil enclosingNamespacePath then
+ envAtEnd
+ else
+ let env = AddLocalRootModuleOrNamespace cenv.tcSink cenv.g cenv.amap m env mtypRoot
+
+ // If the namespace is an interactive fragment e.g. FSI_0002, then open FSI_0002 in the subsequent environment
+ let env =
+ match TryStripPrefixPath cenv.g enclosingNamespacePath with
+ | Some(p, _) -> TcOpenModuleOrNamespaceDecl cenv.tcSink cenv.g cenv.amap m.EndRange env ([p], m.EndRange)
+ | None -> env
+
+ // Publish the combined module type
+ env.eModuleOrNamespaceTypeAccumulator := CombineCcuContentFragments m [!(env.eModuleOrNamespaceTypeAccumulator); mtypRoot]
+ env
+
+ let modExprRoot = BuildRootModuleExpr enclosingNamespacePath envNS.eCompPath modExpr
+
+ return ((fun modExprs -> modExprRoot :: modExprs), topAttrs), env, envAtEnd
+
+ with exn ->
+ errorRecovery exn synDecl.Range
+ return ((fun e -> e), []), env, env
+ }
+
+/// The non-mutually recursive case for a sequence of declarations
+and TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm (defsSoFar, env, envAtEnd) (moreDefs: SynModuleDecl list) =
+ eventually {
+ match moreDefs with
+ | (firstDef :: otherDefs) ->
+ // Lookahead one to find out the scope of the next declaration.
+ let scopem =
+ if isNil otherDefs then unionRanges firstDef.Range endm
+ else unionRanges (List.head otherDefs).Range endm
+
+ // Possibly better:
+ //let scopem = unionRanges h1.Range.EndRange endm
+
+ let! firstDef', env', envAtEnd' = TcModuleOrNamespaceElementNonMutRec cenv parent typeNames scopem env firstDef
+ // tail recursive
+ return! TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm ( (firstDef' :: defsSoFar), env', envAtEnd') otherDefs
+ | [] ->
+ return List.rev defsSoFar, envAtEnd
+ }
+
+/// The mutually recursive case for a sequence of declarations (and nested modules)
+and TcModuleOrNamespaceElementsMutRec (cenv: cenv) parent typeNames m envInitial mutRecNSInfo (defs: SynModuleDecl list) =
+ eventually {
+
+ let m = match defs with [] -> m | _ -> defs |> List.map (fun d -> d.Range) |> List.reduce unionRanges
+ let scopem = (defs, m) ||> List.foldBack (fun h m -> unionRanges h.Range m)
+
+ let (mutRecDefns, (_, _, Attributes synAttrs)) =
+ let rec loop isNamespace moduleRange attrs defs: (MutRecDefnsInitialData * _) =
+ ((true, true, attrs), defs) ||> List.collectFold (fun (openOk, moduleAbbrevOk, attrs) def ->
+ match ElimModuleDoBinding def with
+
+ | SynModuleDecl.Types (typeDefs, _) ->
+ let decls = typeDefs |> List.map MutRecShape.Tycon
+ decls, (false, false, attrs)
+
+ | SynModuleDecl.Let (letrec, binds, m) ->
+ let binds =
+ if isNamespace then
+ CheckLetOrDoInNamespace binds m; []
+ else
+ if letrec then [MutRecShape.Lets binds]
+ else List.map (List.singleton >> MutRecShape.Lets) binds
+ binds, (false, false, attrs)
+
+ | SynModuleDecl.NestedModule(compInfo, isRec, synDefs, _isContinuingModule, moduleRange) ->
+ if isRec then warning(Error(FSComp.SR.tcRecImplied(), compInfo.Range))
+ let mutRecDefs, (_, _, attrs) = loop false moduleRange attrs synDefs
+ let decls = [MutRecShape.Module (compInfo, mutRecDefs)]
+ decls, (false, false, attrs)
+
+ | SynModuleDecl.Open (target, m) ->
+ if not openOk then errorR(Error(FSComp.SR.tcOpenFirstInMutRec(), m))
+ let decls = [ MutRecShape.Open (MutRecDataForOpen(target, m, moduleRange)) ]
+ decls, (openOk, moduleAbbrevOk, attrs)
+
+ | SynModuleDecl.Exception (SynExceptionDefn(repr, members, _), _m) ->
+ let (SynExceptionDefnRepr(synAttrs, UnionCase(_, id, _args, _, _, _), _repr, doc, vis, m)) = repr
+ let compInfo = ComponentInfo(synAttrs, [], [], [id], doc, false, vis, id.idRange)
+ let decls = [ MutRecShape.Tycon(SynTypeDefn.TypeDefn(compInfo, SynTypeDefnRepr.Exception repr, members, m)) ]
+ decls, (false, false, attrs)
+
+ | SynModuleDecl.HashDirective _ ->
+ [ ], (openOk, moduleAbbrevOk, attrs)
+
+ | SynModuleDecl.Attributes (synAttrs, _) ->
+ [ ], (false, false, synAttrs)
+
+ | SynModuleDecl.ModuleAbbrev (id, p, m) ->
+ if not moduleAbbrevOk then errorR(Error(FSComp.SR.tcModuleAbbrevFirstInMutRec(), m))
+ let decls = [ MutRecShape.ModuleAbbrev (MutRecDataForModuleAbbrev(id, p, m)) ]
+ decls, (false, moduleAbbrevOk, attrs)
+
+ | SynModuleDecl.DoExpr _ -> failwith "unreachable: SynModuleDecl.DoExpr - ElimModuleDoBinding"
+
+ | (SynModuleDecl.NamespaceFragment _ as d) -> error(Error(FSComp.SR.tcUnsupportedMutRecDecl(), d.Range)))
+
+ loop (match parent with ParentNone -> true | Parent _ -> false) m [] defs
+
+ let tpenv = emptyUnscopedTyparEnv
+ let mutRecDefnsChecked, envAfter = TcDeclarations.TcMutRecDefinitions cenv envInitial parent typeNames tpenv m scopem mutRecNSInfo mutRecDefns
+
+ // Check the assembly attributes
+ let attrs, _ = TcAttributesWithPossibleTargets false cenv envAfter AttributeTargets.Top synAttrs
+
+ // Check the non-escaping condition as we build the list of module expressions on the way back up
+ let exprfWithEscapeCheck modExprs =
+ TcMutRecDefnsEscapeCheck mutRecDefnsChecked envInitial
+ let modExpr = TcMutRecDefsFinish cenv mutRecDefnsChecked m
+ modExpr :: modExprs
+
+ return (exprfWithEscapeCheck, attrs), envAfter, envAfter
+
+ }
+
+and TcMutRecDefsFinish cenv defs m =
+ let tycons = defs |> List.choose (function MutRecShape.Tycon (Some tycon, _) -> Some tycon | _ -> None)
+ let binds =
+ defs |> List.collect (function
+ | MutRecShape.Open _ -> []
+ | MutRecShape.ModuleAbbrev _ -> []
+ | MutRecShape.Tycon (_, binds)
+ | MutRecShape.Lets binds ->
+ binds |> List.map ModuleOrNamespaceBinding.Binding
+ | MutRecShape.Module ((MutRecDefnsPhase2DataForModule(mtypeAcc, mspec), _), mdefs) ->
+ let mexpr = TcMutRecDefsFinish cenv mdefs m
+ mspec.entity_modul_contents <- MaybeLazy.Strict !mtypeAcc
+ [ ModuleOrNamespaceBinding.Module(mspec, mexpr) ])
+
+ TMDefRec(true, tycons, binds, m)
+
+and TcModuleOrNamespaceElements cenv parent endm env xml mutRecNSInfo defs =
+ eventually {
+ // Ensure the deref_nlpath call in UpdateAccModuleOrNamespaceType succeeds
+ if cenv.compilingCanonicalFslibModuleType then
+ let doc = xml.ToXmlDoc(true, Some [])
+ ensureCcuHasModuleOrNamespaceAtPath cenv.topCcu env.ePath env.eCompPath doc
+
+ // Collect the type names so we can implicitly add the compilation suffix to module names
+ let typeNames = EstablishTypeDefinitionCores.TypeNamesInNonMutRecDecls defs
+
+ match mutRecNSInfo with
+ | Some _ ->
+ let! (exprf, topAttrsNew), _, envAtEnd = TcModuleOrNamespaceElementsMutRec cenv parent typeNames endm env mutRecNSInfo defs
+ // Apply the functions for each declaration to build the overall expression-builder
+ let mexpr = TMDefs(exprf [])
+ return (mexpr, topAttrsNew, envAtEnd)
+
+ | None ->
+
+ let! compiledDefs, envAtEnd = TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm ([], env, env) defs
+
+ // Apply the functions for each declaration to build the overall expression-builder
+ let mexpr = TMDefs(List.foldBack (fun (f, _) x -> f x) compiledDefs [])
+
+ // Collect up the attributes that are global to the file
+ let topAttrsNew = List.foldBack (fun (_, y) x -> y@x) compiledDefs []
+ return (mexpr, topAttrsNew, envAtEnd)
+ }
+
+
+//--------------------------------------------------------------------------
+// TypeCheckOneImplFile - Typecheck all the namespace fragments in a file.
+//--------------------------------------------------------------------------
+
+
+let ApplyAssemblyLevelAutoOpenAttributeToTcEnv g amap (ccu: CcuThunk) scopem env (p, root) =
+ let warn() =
+ warning(Error(FSComp.SR.tcAttributeAutoOpenWasIgnored(p, ccu.AssemblyName), scopem))
+ env
+ let p = splitNamespace p
+ if isNil p then warn() else
+ let h, t = List.frontAndBack p
+ let modref = mkNonLocalTyconRef (mkNonLocalEntityRef ccu (Array.ofList h)) t
+ match modref.TryDeref with
+ | ValueNone -> warn()
+ | ValueSome _ ->
+ let openTarget = SynOpenDeclTarget.ModuleOrNamespace([], scopem)
+ let openDecl = OpenDeclaration.Create (openTarget, [modref], [], scopem, false)
+ OpenModuleOrNamespaceRefs TcResultsSink.NoSink g amap scopem root env [modref] openDecl
+
+// Add the CCU and apply the "AutoOpen" attributes
+let AddCcuToTcEnv(g, amap, scopem, env, assemblyName, ccu, autoOpens, internalsVisibleToAttributes) =
+ let env = AddNonLocalCcu g amap scopem env assemblyName (ccu, internalsVisibleToAttributes)
+
+ // See https://fslang.uservoice.com/forums/245727-f-language/suggestions/6107641-make-microsoft-prefix-optional-when-using-core-f
+ // "Microsoft" is opened by default in FSharp.Core
+ let autoOpens =
+ let autoOpens = autoOpens |> List.map (fun p -> (p, false))
+ if ccuEq ccu g.fslibCcu then
+ // Auto open 'Microsoft' in FSharp.Core.dll. Even when using old versions of FSharp.Core.dll that do
+ // not have this attribute. The 'true' means 'treat all namespaces so revealed as "roots" accessible via
+ // global, e.g. global.FSharp.Collections'
+ ("Microsoft", true) :: autoOpens
+ else
+ autoOpens
+
+ let env = (env, autoOpens) ||> List.fold (ApplyAssemblyLevelAutoOpenAttributeToTcEnv g amap ccu scopem)
+ env
+
+let emptyTcEnv g =
+ let cpath = compPathInternal // allow internal access initially
+ { eNameResEnv = NameResolutionEnv.Empty g
+ eUngeneralizableItems = []
+ ePath = []
+ eCompPath = cpath // dummy
+ eAccessPath = cpath // dummy
+ eAccessRights = ComputeAccessRights cpath [] None // compute this field
+ eInternalsVisibleCompPaths = []
+ eContextInfo = ContextInfo.NoContext
+ eModuleOrNamespaceTypeAccumulator = ref (Construct.NewEmptyModuleOrNamespaceType Namespace)
+ eFamilyType = None
+ eCtorInfo = None
+ eCallerMemberName = None }
+
+let CreateInitialTcEnv(g, amap, scopem, assemblyName, ccus) =
+ (emptyTcEnv g, ccus) ||> List.fold (fun env (ccu, autoOpens, internalsVisible) ->
+ try
+ AddCcuToTcEnv(g, amap, scopem, env, assemblyName, ccu, autoOpens, internalsVisible)
+ with e ->
+ errorRecovery e scopem
+ env)
+
+type ConditionalDefines =
+ string list
+
+
+/// The attributes that don't get attached to any declaration
+type TopAttribs =
+ { mainMethodAttrs: Attribs
+ netModuleAttrs: Attribs
+ assemblyAttrs: Attribs }
+
+let EmptyTopAttrs =
+ { mainMethodAttrs=[]
+ netModuleAttrs=[]
+ assemblyAttrs =[] }
+
+let CombineTopAttrs topAttrs1 topAttrs2 =
+ { mainMethodAttrs = topAttrs1.mainMethodAttrs @ topAttrs2.mainMethodAttrs
+ netModuleAttrs = topAttrs1.netModuleAttrs @ topAttrs2.netModuleAttrs
+ assemblyAttrs = topAttrs1.assemblyAttrs @ topAttrs2.assemblyAttrs }
+
+let rec IterTyconsOfModuleOrNamespaceType f (mty: ModuleOrNamespaceType) =
+ mty.AllEntities |> QueueList.iter (fun tycon -> f tycon)
+ mty.ModuleAndNamespaceDefinitions |> List.iter (fun v ->
+ IterTyconsOfModuleOrNamespaceType f v.ModuleOrNamespaceType)
+
+
+// Defaults get applied before the module signature is checked and before the implementation conditions on virtuals/overrides.
+// Defaults get applied in priority order. Defaults listed last get priority 0 (lowest), 2nd last priority 1 etc.
+let ApplyDefaults (cenv: cenv) g denvAtEnd m mexpr extraAttribs =
+ try
+ let unsolved = FSharp.Compiler.FindUnsolved.UnsolvedTyparsOfModuleDef g cenv.amap denvAtEnd (mexpr, extraAttribs)
+
+ ConstraintSolver.CanonicalizePartialInferenceProblem cenv.css denvAtEnd m unsolved
+
+ // The priority order comes from the order of declaration of the defaults in FSharp.Core.
+ for priority = 10 downto 0 do
+ unsolved |> List.iter (fun tp ->
+ if not tp.IsSolved then
+ // Apply the first default. If we're defaulting one type variable to another then
+ // the defaults will be propagated to the new type variable.
+ ConstraintSolver.ApplyTyparDefaultAtPriority denvAtEnd cenv.css priority tp)
+
+ // OK, now apply defaults for any unsolved HeadTypeStaticReq
+ unsolved |> List.iter (fun tp ->
+ if not tp.IsSolved then
+ if (tp.StaticReq <> NoStaticReq) then
+ ConstraintSolver.ChooseTyparSolutionAndSolve cenv.css denvAtEnd tp)
+ with e -> errorRecovery e m
+
+let CheckValueRestriction denvAtEnd rootSigOpt implFileTypePriorToSig m =
+ if Option.isNone rootSigOpt then
+ let rec check (mty: ModuleOrNamespaceType) =
+ for v in mty.AllValsAndMembers do
+ let ftyvs = (freeInVal CollectTyparsNoCaching v).FreeTypars |> Zset.elements
+ if (not v.IsCompilerGenerated &&
+ not (ftyvs |> List.exists (fun tp -> tp.IsFromError)) &&
+ // Do not apply the value restriction to methods and functions
+ // Note, normally these completely generalize their argument types anyway. However,
+ // some methods (property getters/setters, constructors) can't be as generic
+ // as they might naturally be, and these can leave type variables unsolved. See
+ // for example FSharp 1.0 3661.
+ (match v.ValReprInfo with None -> true | Some tvi -> tvi.HasNoArgs)) then
+ match ftyvs with
+ | tp :: _ -> errorR (ValueRestriction(denvAtEnd, false, v, tp, v.Range))
+ | _ -> ()
+ mty.ModuleAndNamespaceDefinitions |> List.iter (fun v -> check v.ModuleOrNamespaceType)
+ try check implFileTypePriorToSig with e -> errorRecovery e m
+
+
+let SolveInternalUnknowns g (cenv: cenv) denvAtEnd mexpr extraAttribs =
+ let unsolved = FSharp.Compiler.FindUnsolved.UnsolvedTyparsOfModuleDef g cenv.amap denvAtEnd (mexpr, extraAttribs)
+
+ unsolved |> List.iter (fun tp ->
+ if (tp.Rigidity <> TyparRigidity.Rigid) && not tp.IsSolved then
+ ConstraintSolver.ChooseTyparSolutionAndSolve cenv.css denvAtEnd tp)
+
+let CheckModuleSignature g (cenv: cenv) m denvAtEnd rootSigOpt implFileTypePriorToSig implFileSpecPriorToSig mexpr =
+ match rootSigOpt with
+ | None ->
+ // Deep copy the inferred type of the module
+ let implFileTypePriorToSigCopied = copyModuleOrNamespaceType g CloneAll implFileTypePriorToSig
+
+ ModuleOrNamespaceExprWithSig(implFileTypePriorToSigCopied, mexpr, m)
+
+ | Some sigFileType ->
+
+ // We want to show imperative type variables in any types in error messages at this late point
+ let denv = { denvAtEnd with showImperativeTyparAnnotations=true }
+ begin
+ try
+
+ // As typechecked the signature and implementation use different tycons etc.
+ // Here we (a) check there are enough names, (b) match them up to build a renaming and
+ // (c) check signature conformance up to this renaming.
+ if not (SignatureConformance.CheckNamesOfModuleOrNamespace denv (mkLocalTyconRef implFileSpecPriorToSig) sigFileType) then
+ raise (ReportedError None)
+
+ // Compute the remapping from implementation to signature
+ let remapInfo, _ = ComputeRemappingFromInferredSignatureToExplicitSignature cenv.g implFileTypePriorToSig sigFileType
+
+ let aenv = { TypeEquivEnv.Empty with EquivTycons = TyconRefMap.OfList remapInfo.RepackagedEntities }
+
+ if not (SignatureConformance.Checker(cenv.g, cenv.amap, denv, remapInfo, true).CheckSignature aenv (mkLocalModRef implFileSpecPriorToSig) sigFileType) then (
+ // We can just raise 'ReportedError' since CheckModuleOrNamespace raises its own error
+ raise (ReportedError None)
+ )
+ with e -> errorRecovery e m
+ end
+
+ ModuleOrNamespaceExprWithSig(sigFileType, mexpr, m)
+
+
+/// Make the initial type checking environment for a single file with an empty accumulator for the overall contents for the file
+let MakeInitialEnv env =
+ // Note: here we allocate a new module type accumulator
+ let mtypeAcc = ref (Construct.NewEmptyModuleOrNamespaceType Namespace)
+ { env with eModuleOrNamespaceTypeAccumulator = mtypeAcc }, mtypeAcc
+
+/// Check an entire implementation file
+/// Typecheck, then close the inference scope and then check the file meets its signature (if any)
+let TypeCheckOneImplFile
+ // checkForErrors: A function to help us stop reporting cascading errors
+ (g, niceNameGen, amap, topCcu, checkForErrors, conditionalDefines, tcSink, isInternalTestSpanStackReferring)
+ env
+ (rootSigOpt: ModuleOrNamespaceType option)
+ (ParsedImplFileInput (_, isScript, qualNameOfFile, scopedPragmas, _, implFileFrags, isLastCompiland)) =
+
+ eventually {
+ let cenv =
+ cenv.Create (g, isScript, niceNameGen, amap, topCcu, false, Option.isSome rootSigOpt,
+ conditionalDefines, tcSink, (LightweightTcValForUsingInBuildMethodCall g), isInternalTestSpanStackReferring,
+ tcSequenceExpressionEntry=TcSequenceExpressionEntry,
+ tcArrayOrListSequenceExpression=TcArrayOrListSequenceExpression,
+ tcComputationExpression=TcComputationExpression)
+
+ let envinner, mtypeAcc = MakeInitialEnv env
+
+ let defs = [ for x in implFileFrags -> SynModuleDecl.NamespaceFragment x ]
+ let! mexpr, topAttrs, envAtEnd = TcModuleOrNamespaceElements cenv ParentNone qualNameOfFile.Range envinner PreXmlDoc.Empty None defs
+
+ let implFileTypePriorToSig = !mtypeAcc
+
+ let topAttrs =
+ let mainMethodAttrs, others = topAttrs |> List.partition (fun (possTargets, _) -> possTargets &&& AttributeTargets.Method <> enum 0)
+ let assemblyAttrs, others = others |> List.partition (fun (possTargets, _) -> possTargets &&& AttributeTargets.Assembly <> enum 0)
+ // REVIEW: consider checking if '_others' is empty
+ let netModuleAttrs, _others = others |> List.partition (fun (possTargets, _) -> possTargets &&& AttributeTargets.Module <> enum 0)
+ { mainMethodAttrs = List.map snd mainMethodAttrs
+ netModuleAttrs = List.map snd netModuleAttrs
+ assemblyAttrs = List.map snd assemblyAttrs}
+ let denvAtEnd = envAtEnd.DisplayEnv
+ let m = qualNameOfFile.Range
+
+ // This is a fake module spec
+ let implFileSpecPriorToSig = wrapModuleOrNamespaceType qualNameOfFile.Id (compPathOfCcu topCcu) implFileTypePriorToSig
+
+ let extraAttribs = topAttrs.mainMethodAttrs@topAttrs.netModuleAttrs@topAttrs.assemblyAttrs
+
+ conditionallySuppressErrorReporting (checkForErrors()) (fun () ->
+ ApplyDefaults cenv g denvAtEnd m mexpr extraAttribs)
+
+ // Check completion of all classes defined across this file.
+ // NOTE: this is not a great technique if inner signatures are permitted to hide
+ // virtual dispatch slots.
+ conditionallySuppressErrorReporting (checkForErrors()) (fun () ->
+ try implFileTypePriorToSig |> IterTyconsOfModuleOrNamespaceType (FinalTypeDefinitionChecksAtEndOfInferenceScope (cenv.infoReader, envAtEnd.NameEnv, cenv.tcSink, true, denvAtEnd))
+ with e -> errorRecovery e m)
+
+ // Check the value restriction. Only checked if there is no signature.
+ conditionallySuppressErrorReporting (checkForErrors()) (fun () ->
+ CheckValueRestriction denvAtEnd rootSigOpt implFileTypePriorToSig m)
+
+ // Solve unsolved internal type variables
+ conditionallySuppressErrorReporting (checkForErrors()) (fun () ->
+ SolveInternalUnknowns g cenv denvAtEnd mexpr extraAttribs)
+
+ // Check the module matches the signature
+ let implFileExprAfterSig =
+ conditionallySuppressErrorReporting (checkForErrors()) (fun () ->
+ CheckModuleSignature g cenv m denvAtEnd rootSigOpt implFileTypePriorToSig implFileSpecPriorToSig mexpr)
+
+ // Run any additional checks registered for post-type-inference
+ do
+ conditionallySuppressErrorReporting (checkForErrors()) (fun () ->
+ for check in cenv.postInferenceChecks do
+ try
+ check()
+ with e ->
+ errorRecovery e m)
+
+ // We ALWAYS run the PostTypeCheckSemanticChecks phase, though we if we have already encountered some
+ // errors we turn off error reporting. This is because it performs various fixups over the TAST, e.g.
+ // assigning nice names for inference variables.
+ let hasExplicitEntryPoint, anonRecdTypes =
+
+ conditionallySuppressErrorReporting (checkForErrors()) (fun () ->
+
+ try
+ let reportErrors = not (checkForErrors())
+ let tcVal = LightweightTcValForUsingInBuildMethodCall g
+ PostTypeCheckSemanticChecks.CheckTopImpl
+ (g, cenv.amap, reportErrors, cenv.infoReader,
+ env.eInternalsVisibleCompPaths, cenv.topCcu, tcVal, envAtEnd.DisplayEnv,
+ implFileExprAfterSig, extraAttribs, isLastCompiland,
+ isInternalTestSpanStackReferring)
+
+ with e ->
+ errorRecovery e m
+ false, StampMap.Empty)
+
+ // Warn on version attributes.
+ topAttrs.assemblyAttrs |> List.iter (function
+ | Attrib(tref, _, [ AttribExpr(Expr.Const (Const.String version, range, _), _) ], _, _, _, _) ->
+ let attrName = tref.CompiledRepresentationForNamedType.FullName
+ let isValid() =
+ try IL.parseILVersion version |> ignore; true
+ with _ -> false
+ match attrName with
+ | "System.Reflection.AssemblyFileVersionAttribute" //TODO compile error like c# compiler?
+ | "System.Reflection.AssemblyVersionAttribute" when not (isValid()) ->
+ warning(Error(FSComp.SR.fscBadAssemblyVersion(attrName, version), range))
+ | _ -> ()
+ | _ -> ())
+
+ let implFile = TImplFile (qualNameOfFile, scopedPragmas, implFileExprAfterSig, hasExplicitEntryPoint, isScript, anonRecdTypes)
+
+ return (topAttrs, implFile, implFileTypePriorToSig, envAtEnd, cenv.createsGeneratedProvidedTypes)
+ }
+
+
+
+/// Check an entire signature file
+let TypeCheckOneSigFile (g, niceNameGen, amap, topCcu, checkForErrors, conditionalDefines, tcSink, isInternalTestSpanStackReferring) tcEnv (ParsedSigFileInput (_, qualNameOfFile, _, _, sigFileFrags)) =
+ eventually {
+ let cenv =
+ cenv.Create
+ (g, false, niceNameGen, amap, topCcu, true, false, conditionalDefines, tcSink,
+ (LightweightTcValForUsingInBuildMethodCall g), isInternalTestSpanStackReferring,
+ tcSequenceExpressionEntry=TcSequenceExpressionEntry,
+ tcArrayOrListSequenceExpression=TcArrayOrListSequenceExpression,
+ tcComputationExpression=TcComputationExpression)
+
+ let envinner, mtypeAcc = MakeInitialEnv tcEnv
+
+ let specs = [ for x in sigFileFrags -> SynModuleSigDecl.NamespaceFragment x ]
+ let! tcEnv = TcSignatureElements cenv ParentNone qualNameOfFile.Range envinner PreXmlDoc.Empty None specs
+
+ let sigFileType = !mtypeAcc
+
+ if not (checkForErrors()) then
+ try sigFileType |> IterTyconsOfModuleOrNamespaceType (FinalTypeDefinitionChecksAtEndOfInferenceScope(cenv.infoReader, tcEnv.NameEnv, cenv.tcSink, false, tcEnv.DisplayEnv))
+ with e -> errorRecovery e qualNameOfFile.Range
+
+ return (tcEnv, sigFileType, cenv.createsGeneratedProvidedTypes)
+ }
diff --git a/src/fsharp/CheckDeclarations.fsi b/src/fsharp/CheckDeclarations.fsi
new file mode 100644
index 00000000000..5e9bce69113
--- /dev/null
+++ b/src/fsharp/CheckDeclarations.fsi
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+module internal FSharp.Compiler.CheckDeclarations
+
+open FSharp.Compiler
+open FSharp.Compiler.AbstractIL.Internal.Library
+open FSharp.Compiler.CheckExpressions
+open FSharp.Compiler.CompilerGlobalState
+open FSharp.Compiler.NameResolution
+open FSharp.Compiler.Import
+open FSharp.Compiler.SyntaxTree
+open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.Text
+open FSharp.Compiler.TypedTree
+
+val AddLocalRootModuleOrNamespace : NameResolution.TcResultsSink -> TcGlobals -> ImportMap -> range -> TcEnv -> ModuleOrNamespaceType -> TcEnv
+val CreateInitialTcEnv : TcGlobals * ImportMap * range * assemblyName: string * (CcuThunk * string list * string list) list -> TcEnv
+val AddCcuToTcEnv: TcGlobals * ImportMap * range * TcEnv * assemblyName: string * ccu: CcuThunk * autoOpens: string list * internalsVisibleToAttributes: string list -> TcEnv
+
+type TopAttribs =
+ { mainMethodAttrs: Attribs
+ netModuleAttrs: Attribs
+ assemblyAttrs: Attribs }
+
+type ConditionalDefines = string list
+
+val EmptyTopAttrs : TopAttribs
+val CombineTopAttrs : TopAttribs -> TopAttribs -> TopAttribs
+
+val TcOpenModuleOrNamespaceDecl: TcResultsSink -> TcGlobals -> ImportMap -> range -> TcEnv -> (LongIdent * range) -> TcEnv
+
+val AddLocalSubModule: g: TcGlobals -> amap: ImportMap -> m: range -> env: TcEnv -> modul: ModuleOrNamespace -> TcEnv
+
+val TypeCheckOneImplFile :
+ TcGlobals * NiceNameGenerator * ImportMap * CcuThunk * (unit -> bool) * ConditionalDefines option * NameResolution.TcResultsSink * bool
+ -> TcEnv
+ -> ModuleOrNamespaceType option
+ -> ParsedImplFileInput
+ -> Eventually
+
+val TypeCheckOneSigFile :
+ TcGlobals * NiceNameGenerator * ImportMap * CcuThunk * (unit -> bool) * ConditionalDefines option * NameResolution.TcResultsSink * bool
+ -> TcEnv
+ -> ParsedSigFileInput
+ -> Eventually
+
+exception ParameterlessStructCtor of range
+exception NotUpperCaseConstructor of range
diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs
new file mode 100644
index 00000000000..b30ae9cd30c
--- /dev/null
+++ b/src/fsharp/CheckExpressions.fs
@@ -0,0 +1,10946 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+/// The typechecker. Left-to-right constrained type checking
+/// with generalization at appropriate points.
+module internal FSharp.Compiler.CheckExpressions
+
+open System
+open System.Collections.Generic
+
+open Internal.Utilities
+
+open FSharp.Compiler
+open FSharp.Compiler.AbstractIL.IL
+open FSharp.Compiler.AbstractIL.Internal
+open FSharp.Compiler.AbstractIL.Internal.Library
+open FSharp.Compiler.AbstractIL.Internal.Library.ResultOrException
+open FSharp.Compiler.AccessibilityLogic
+open FSharp.Compiler.AttributeChecking
+open FSharp.Compiler.CompilerGlobalState
+open FSharp.Compiler.ConstraintSolver
+open FSharp.Compiler.ErrorLogger
+open FSharp.Compiler.Features
+open FSharp.Compiler.Infos
+open FSharp.Compiler.InfoReader
+open FSharp.Compiler.Lib
+open FSharp.Compiler.MethodCalls
+open FSharp.Compiler.MethodOverrides
+open FSharp.Compiler.NameResolution
+open FSharp.Compiler.PatternMatchCompilation
+open FSharp.Compiler.SourceCodeServices.PrettyNaming
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Rational
+open FSharp.Compiler.SyntaxTree
+open FSharp.Compiler.SyntaxTreeOps
+open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.Text
+open FSharp.Compiler.Text.Pos
+open FSharp.Compiler.Text.Range
+open FSharp.Compiler.TypedTree
+open FSharp.Compiler.TypedTreeBasics
+open FSharp.Compiler.TypedTreeOps
+open FSharp.Compiler.TypeRelations
+open FSharp.Compiler.XmlDoc
+
+#if !NO_EXTENSIONTYPING
+open FSharp.Compiler.ExtensionTyping
+#endif
+
+//-------------------------------------------------------------------------
+// Helpers that should be elsewhere
+//-------------------------------------------------------------------------
+
+let mkNilListPat (g: TcGlobals) m ty = TPat_unioncase(g.nil_ucref, [ty], [], m)
+let mkConsListPat (g: TcGlobals) ty ph pt = TPat_unioncase(g.cons_ucref, [ty], [ph;pt], unionRanges ph.Range pt.Range)
+
+//-------------------------------------------------------------------------
+// Errors.
+//-------------------------------------------------------------------------
+
+exception BakedInMemberConstraintName of string * range
+exception FunctionExpected of DisplayEnv * TType * range
+exception NotAFunction of DisplayEnv * TType * range * range
+exception NotAFunctionButIndexer of DisplayEnv * TType * string option * range * range
+exception Recursion of DisplayEnv * Ident * TType * TType * range
+exception RecursiveUseCheckedAtRuntime of DisplayEnv * ValRef * range
+exception LetRecEvaluatedOutOfOrder of DisplayEnv * ValRef * ValRef * range
+exception LetRecCheckedAtRuntime of range
+exception LetRecUnsound of DisplayEnv * ValRef list * range
+exception TyconBadArgs of DisplayEnv * TyconRef * int * range
+exception UnionCaseWrongArguments of DisplayEnv * int * int * range
+exception UnionCaseWrongNumberOfArgs of DisplayEnv * int * int * range
+exception FieldsFromDifferentTypes of DisplayEnv * RecdFieldRef * RecdFieldRef * range
+exception FieldGivenTwice of DisplayEnv * RecdFieldRef * range
+exception MissingFields of string list * range
+exception FunctionValueUnexpected of DisplayEnv * TType * range
+exception UnitTypeExpected of DisplayEnv * TType * range
+exception UnitTypeExpectedWithEquality of DisplayEnv * TType * range
+exception UnitTypeExpectedWithPossibleAssignment of DisplayEnv * TType * bool * string * range
+exception UnitTypeExpectedWithPossiblePropertySetter of DisplayEnv * TType * string * string * range
+exception UnionPatternsBindDifferentNames of range
+exception VarBoundTwice of Ident
+exception ValueRestriction of DisplayEnv * bool * Val * Typar * range
+exception ValNotMutable of DisplayEnv * ValRef * range
+exception ValNotLocal of DisplayEnv * ValRef * range
+exception InvalidRuntimeCoercion of DisplayEnv * TType * TType * range
+exception IndeterminateRuntimeCoercion of DisplayEnv * TType * TType * range
+exception IndeterminateStaticCoercion of DisplayEnv * TType * TType * range
+exception RuntimeCoercionSourceSealed of DisplayEnv * TType * range
+exception CoercionTargetSealed of DisplayEnv * TType * range
+exception UpcastUnnecessary of range
+exception TypeTestUnnecessary of range
+exception StaticCoercionShouldUseBox of DisplayEnv * TType * TType * range
+exception SelfRefObjCtor of bool * range
+exception VirtualAugmentationOnNullValuedType of range
+exception NonVirtualAugmentationOnNullValuedType of range
+exception UseOfAddressOfOperator of range
+exception DeprecatedThreadStaticBindingWarning of range
+exception IntfImplInIntrinsicAugmentation of range
+exception IntfImplInExtrinsicAugmentation of range
+exception OverrideInIntrinsicAugmentation of range
+exception OverrideInExtrinsicAugmentation of range
+exception NonUniqueInferredAbstractSlot of TcGlobals * DisplayEnv * string * MethInfo * MethInfo * range
+exception StandardOperatorRedefinitionWarning of string * range
+exception InvalidInternalsVisibleToAssemblyName of (*badName*)string * (*fileName option*) string option
+
+/// Represents information about the initialization field used to check that object constructors
+/// have completed before fields are accessed.
+type SafeInitData =
+ | SafeInitField of RecdFieldRef * RecdField
+ | NoSafeInitInfo
+
+/// Represents information about object constructors
+type CtorInfo =
+ { /// Object model constructors have a very specific form to satisfy .NET limitations.
+ /// For "new = \arg. { new C with ... }"
+ /// ctor = 3 indicates about to type check "\arg. (body)",
+ /// ctor = 2 indicates about to type check "body"
+ /// ctor = 1 indicates actually type checking the body expression
+ /// 0 indicates everywhere else, including auxiliary expressions such e1 in "let x = e1 in { new ... }"
+ /// REVIEW: clean up this rather odd approach ...
+ ctorShapeCounter: int
+
+ /// A handle to the ref cell to hold results of 'this' for 'type X() as x = ...' and 'new() as x = ...' constructs
+ /// in case 'x' is used in the arguments to the 'inherits' call.
+ safeThisValOpt: Val option
+
+ /// A handle to the boolean ref cell to hold success of initialized 'this' for 'type X() as x = ...' constructs
+ safeInitInfo: SafeInitData
+
+ /// Is the an implicit constructor or an explicit one?
+ ctorIsImplicit: bool
+ }
+
+/// Represents an item in the environment that may restrict the automatic generalization of later
+/// declarations because it refers to type inference variables. As type inference progresses
+/// these type inference variables may get solved.
+[]
+type UngeneralizableItem(computeFreeTyvars: (unit -> FreeTyvars)) =
+
+ // Flag is for: have we determined that this item definitely has
+ // no free type inference variables? This implies that
+ // (a) it will _never_ have any free type inference variables as further constraints are added to the system.
+ // (b) its set of FreeTycons will not change as further constraints are added to the system
+ let mutable willNeverHaveFreeTypars = false
+
+ // If WillNeverHaveFreeTypars then we can cache the computation of FreeTycons, since they are invariant.
+ let mutable cachedFreeLocalTycons = emptyFreeTycons
+
+ // If WillNeverHaveFreeTypars then we can cache the computation of FreeTraitSolutions, since they are invariant.
+ let mutable cachedFreeTraitSolutions = emptyFreeLocals
+
+ member item.GetFreeTyvars() =
+ let fvs = computeFreeTyvars()
+ if fvs.FreeTypars.IsEmpty then
+ willNeverHaveFreeTypars <- true
+ cachedFreeLocalTycons <- fvs.FreeTycons
+ cachedFreeTraitSolutions <- fvs.FreeTraitSolutions
+ fvs
+
+ member item.WillNeverHaveFreeTypars = willNeverHaveFreeTypars
+
+ member item.CachedFreeLocalTycons = cachedFreeLocalTycons
+
+ member item.CachedFreeTraitSolutions = cachedFreeTraitSolutions
+
+/// Represents the type environment at a particular scope. Includes the name
+/// resolution environment, the ungeneralizable items from earlier in the scope
+/// and other information about the scope.
+[]
+type TcEnv =
+ { /// Name resolution information
+ eNameResEnv: NameResolutionEnv
+
+ /// The list of items in the environment that may contain free inference
+ /// variables (which may not be generalized). The relevant types may
+ /// change as a result of inference equations being asserted, hence may need to
+ /// be recomputed.
+ eUngeneralizableItems: UngeneralizableItem list
+
+ // Two (!) versions of the current module path
+ // These are used to:
+ // - Look up the appropriate point in the corresponding signature
+ // see if an item is public or not
+ // - Change fslib canonical module type to allow compiler references to these items
+ // - Record the cpath for concrete modul_specs, tycon_specs and excon_specs so they can cache their generated IL representation where necessary
+ // - Record the pubpath of public, concrete {val, tycon, modul, excon}_specs.
+ // This information is used mainly when building non-local references
+ // to public items.
+ //
+ // Of the two, 'ePath' is the one that's barely used. It's only
+ // used by UpdateAccModuleOrNamespaceType to modify the CCU while compiling FSharp.Core
+ ePath: Ident list
+
+ eCompPath: CompilationPath
+
+ eAccessPath: CompilationPath
+
+ /// This field is computed from other fields, but we amortize the cost of computing it.
+ eAccessRights: AccessorDomain
+
+ /// Internals under these should be accessible
+ eInternalsVisibleCompPaths: CompilationPath list
+
+ /// Mutable accumulator for the current module type
+ eModuleOrNamespaceTypeAccumulator: ModuleOrNamespaceType ref
+
+ /// Context information for type checker
+ eContextInfo: ContextInfo
+
+ /// Here Some tcref indicates we can access protected members in all super types
+ eFamilyType: TyconRef option
+
+ // Information to enforce special restrictions on valid expressions
+ // for .NET constructors.
+ eCtorInfo: CtorInfo option
+
+ eCallerMemberName: string option
+ }
+
+ member tenv.DisplayEnv = tenv.eNameResEnv.DisplayEnv
+
+ member tenv.NameEnv = tenv.eNameResEnv
+
+ member tenv.AccessRights = tenv.eAccessRights
+
+ override tenv.ToString() = "TcEnv(...)"
+
+/// Compute the available access rights from a particular location in code
+let ComputeAccessRights eAccessPath eInternalsVisibleCompPaths eFamilyType =
+ AccessibleFrom (eAccessPath :: eInternalsVisibleCompPaths, eFamilyType)
+
+//-------------------------------------------------------------------------
+// Helpers related to determining if we're in a constructor and/or a class
+// that may be able to access "protected" members.
+//-------------------------------------------------------------------------
+
+let InitialExplicitCtorInfo (safeThisValOpt, safeInitInfo) =
+ { ctorShapeCounter = 3
+ safeThisValOpt = safeThisValOpt
+ safeInitInfo = safeInitInfo
+ ctorIsImplicit = false}
+
+let InitialImplicitCtorInfo () =
+ { ctorShapeCounter = 0
+ safeThisValOpt = None
+ safeInitInfo = NoSafeInitInfo
+ ctorIsImplicit = true }
+
+let EnterFamilyRegion tcref env =
+ let eFamilyType = Some tcref
+ { env with
+ eAccessRights = ComputeAccessRights env.eAccessPath env.eInternalsVisibleCompPaths eFamilyType // update this computed field
+ eFamilyType = eFamilyType }
+
+let ExitFamilyRegion env =
+ let eFamilyType = None
+ match env.eFamilyType with
+ | None -> env // optimization to avoid reallocation
+ | _ ->
+ { env with
+ eAccessRights = ComputeAccessRights env.eAccessPath env.eInternalsVisibleCompPaths eFamilyType // update this computed field
+ eFamilyType = eFamilyType }
+
+let AreWithinCtorShape env = match env.eCtorInfo with None -> false | Some ctorInfo -> ctorInfo.ctorShapeCounter > 0
+let AreWithinImplicitCtor env = match env.eCtorInfo with None -> false | Some ctorInfo -> ctorInfo.ctorIsImplicit
+let GetCtorShapeCounter env = match env.eCtorInfo with None -> 0 | Some ctorInfo -> ctorInfo.ctorShapeCounter
+let GetRecdInfo env = match env.eCtorInfo with None -> RecdExpr | Some ctorInfo -> if ctorInfo.ctorShapeCounter = 1 then RecdExprIsObjInit else RecdExpr
+
+let AdjustCtorShapeCounter f env = {env with eCtorInfo = Option.map (fun ctorInfo -> { ctorInfo with ctorShapeCounter = f ctorInfo.ctorShapeCounter }) env.eCtorInfo }
+let ExitCtorShapeRegion env = AdjustCtorShapeCounter (fun _ -> 0) env
+
+/// Add a type to the TcEnv, i.e. register it as ungeneralizable.
+let addFreeItemOfTy ty eUngeneralizableItems =
+ let fvs = freeInType CollectAllNoCaching ty
+ if isEmptyFreeTyvars fvs then eUngeneralizableItems
+ else UngeneralizableItem(fun () -> freeInType CollectAllNoCaching ty) :: eUngeneralizableItems
+
+/// Add the contents of a module type to the TcEnv, i.e. register the contents as ungeneralizable.
+/// Add a module type to the TcEnv, i.e. register it as ungeneralizable.
+let addFreeItemOfModuleTy mtyp eUngeneralizableItems =
+ let fvs = freeInModuleTy mtyp
+ if isEmptyFreeTyvars fvs then eUngeneralizableItems
+ else UngeneralizableItem(fun () -> freeInModuleTy mtyp) :: eUngeneralizableItems
+
+/// Add a table of values to the name resolution environment.
+let AddValMapToNameEnv vs nenv =
+ NameMap.foldBackRange (fun v nenv -> AddValRefToNameEnv nenv (mkLocalValRef v)) vs nenv
+
+/// Add a list of values to the name resolution environment.
+let AddValListToNameEnv vs nenv =
+ List.foldBack (fun v nenv -> AddValRefToNameEnv nenv (mkLocalValRef v)) vs nenv
+
+/// Add a local value to TcEnv
+let AddLocalValPrimitive (v: Val) env =
+ { env with
+ eNameResEnv = AddValRefToNameEnv env.eNameResEnv (mkLocalValRef v)
+ eUngeneralizableItems = addFreeItemOfTy v.Type env.eUngeneralizableItems }
+
+/// Add a table of local values to TcEnv
+let AddLocalValMap tcSink scopem (vals: Val NameMap) env =
+ let env =
+ if vals.IsEmpty then
+ env
+ else
+ { env with
+ eNameResEnv = AddValMapToNameEnv vals env.eNameResEnv
+ eUngeneralizableItems = NameMap.foldBackRange (typeOfVal >> addFreeItemOfTy) vals env.eUngeneralizableItems }
+ CallEnvSink tcSink (scopem, env.NameEnv, env.AccessRights)
+ env
+
+/// Add a list of local values to TcEnv and report them to the sink
+let AddLocalVals tcSink scopem (vals: Val list) env =
+ let env =
+ if isNil vals then
+ env
+ else
+ { env with
+ eNameResEnv = AddValListToNameEnv vals env.eNameResEnv
+ eUngeneralizableItems = List.foldBack (typeOfVal >> addFreeItemOfTy) vals env.eUngeneralizableItems }
+ CallEnvSink tcSink (scopem, env.NameEnv, env.AccessRights)
+ env
+
+/// Add a local value to TcEnv and report it to the sink
+let AddLocalVal tcSink scopem v env =
+ let env = { env with
+ eNameResEnv = AddValRefToNameEnv env.eNameResEnv (mkLocalValRef v)
+ eUngeneralizableItems = addFreeItemOfTy v.Type env.eUngeneralizableItems }
+ CallEnvSink tcSink (scopem, env.NameEnv, env.eAccessRights)
+ env
+
+/// Add a set of explicitly declared type parameters as being available in the TcEnv
+let AddDeclaredTypars check typars env =
+ if isNil typars then env else
+ let env = { env with eNameResEnv = AddDeclaredTyparsToNameEnv check env.eNameResEnv typars }
+ { env with eUngeneralizableItems = List.foldBack (mkTyparTy >> addFreeItemOfTy) typars env.eUngeneralizableItems }
+
+/// Environment of implicitly scoped type parameters, e.g. 'a in "(x: 'a)"
+
+type UnscopedTyparEnv = UnscopedTyparEnv of NameMap
+
+let emptyUnscopedTyparEnv: UnscopedTyparEnv = UnscopedTyparEnv Map.empty
+
+let AddUnscopedTypar n p (UnscopedTyparEnv tab) = UnscopedTyparEnv (Map.add n p tab)
+
+let TryFindUnscopedTypar n (UnscopedTyparEnv tab) = Map.tryFind n tab
+
+let HideUnscopedTypars typars (UnscopedTyparEnv tab) =
+ UnscopedTyparEnv (List.fold (fun acc (tp: Typar) -> Map.remove tp.Name acc) tab typars)
+
+/// Represents the compilation environment for typechecking a single file in an assembly.
+[]
+type TcFileState =
+ { g: TcGlobals
+
+ /// Push an entry every time a recursive value binding is used,
+ /// in order to be able to fix up recursive type applications as
+ /// we infer type parameters
+ mutable recUses: ValMultiMap<(Expr ref * range * bool)>
+
+ /// Checks to run after all inference is complete.
+ mutable postInferenceChecks: ResizeArray unit>
+
+ /// Set to true if this file causes the creation of generated provided types.
+ mutable createsGeneratedProvidedTypes: bool
+
+ /// Are we in a script? if so relax the reporting of discarded-expression warnings at the top level
+ isScript: bool
+
+ /// Environment needed to convert IL types to F# types in the importer.
+ amap: Import.ImportMap
+
+ /// Used to generate new syntactic argument names in post-parse syntactic processing
+ synArgNameGenerator: SynArgNameGenerator
+
+ tcSink: TcResultsSink
+
+ /// Holds a reference to the component being compiled.
+ /// This field is very rarely used (mainly when fixing up forward references to fslib.
+ topCcu: CcuThunk
+
+ /// Holds the current inference constraints
+ css: ConstraintSolverState
+
+ /// Are we compiling the signature of a module from fslib?
+ compilingCanonicalFslibModuleType: bool
+
+ /// Is this a .fsi file?
+ isSig: bool
+
+ /// Does this .fs file have a .fsi file?
+ haveSig: bool
+
+ /// Used to generate names
+ niceNameGen: NiceNameGenerator
+
+ /// Used to read and cache information about types and members
+ infoReader: InfoReader
+
+ /// Used to resolve names
+ nameResolver: NameResolver
+
+ /// The set of active conditional defines. The value is None when conditional erasure is disabled in tooling.
+ conditionalDefines: string list option
+
+ isInternalTestSpanStackReferring: bool
+ // forward call
+ TcSequenceExpressionEntry: TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> bool * bool ref * SynExpr -> range -> Expr * UnscopedTyparEnv
+ // forward call
+ TcArrayOrListSequenceExpression: TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> bool * SynExpr -> range -> Expr * UnscopedTyparEnv
+ // forward call
+ TcComputationExpression: TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv
+ }
+
+ /// Create a new compilation environment
+ static member Create
+ (g, isScript, niceNameGen, amap, topCcu, isSig, haveSig, conditionalDefines, tcSink, tcVal, isInternalTestSpanStackReferring,
+ tcSequenceExpressionEntry, tcArrayOrListSequenceExpression, tcComputationExpression) =
+ let infoReader = new InfoReader(g, amap)
+ let instantiationGenerator m tpsorig = ConstraintSolver.FreshenTypars m tpsorig
+ let nameResolver = new NameResolver(g, amap, infoReader, instantiationGenerator)
+ { g = g
+ amap = amap
+ recUses = ValMultiMap<_>.Empty
+ postInferenceChecks = ResizeArray()
+ createsGeneratedProvidedTypes = false
+ topCcu = topCcu
+ isScript = isScript
+ css = ConstraintSolverState.New(g, amap, infoReader, tcVal)
+ infoReader = infoReader
+ tcSink = tcSink
+ nameResolver = nameResolver
+ niceNameGen = niceNameGen
+ synArgNameGenerator = SynArgNameGenerator()
+ isSig = isSig
+ haveSig = haveSig
+ compilingCanonicalFslibModuleType = (isSig || not haveSig) && g.compilingFslib
+ conditionalDefines = conditionalDefines
+ isInternalTestSpanStackReferring = isInternalTestSpanStackReferring
+ TcSequenceExpressionEntry = tcSequenceExpressionEntry
+ TcArrayOrListSequenceExpression = tcArrayOrListSequenceExpression
+ TcComputationExpression = tcComputationExpression
+ }
+
+ override _.ToString() = ""
+
+type cenv = TcFileState
+
+let CopyAndFixupTypars m rigid tpsorig =
+ ConstraintSolver.FreshenAndFixupTypars m rigid [] [] tpsorig
+
+let UnifyTypes cenv (env: TcEnv) m actualTy expectedTy =
+ ConstraintSolver.AddCxTypeEqualsType env.eContextInfo env.DisplayEnv cenv.css m (tryNormalizeMeasureInType cenv.g actualTy) (tryNormalizeMeasureInType cenv.g expectedTy)
+
+/// Make an environment suitable for a module or namespace. Does not create a new accumulator but uses one we already have/
+let MakeInnerEnvWithAcc addOpenToNameEnv env nm mtypeAcc modKind =
+ let path = env.ePath @ [nm]
+ let cpath = env.eCompPath.NestedCompPath nm.idText modKind
+ { env with
+ ePath = path
+ eCompPath = cpath
+ eAccessPath = cpath
+ eAccessRights = ComputeAccessRights cpath env.eInternalsVisibleCompPaths env.eFamilyType // update this computed field
+ eNameResEnv =
+ if addOpenToNameEnv then
+ { env.NameEnv with eDisplayEnv = env.DisplayEnv.AddOpenPath (pathOfLid path) }
+ else
+ env.NameEnv
+ eModuleOrNamespaceTypeAccumulator = mtypeAcc }
+
+/// Make an environment suitable for a module or namespace, creating a new accumulator.
+let MakeInnerEnv addOpenToNameEnv env nm modKind =
+ // Note: here we allocate a new module type accumulator
+ let mtypeAcc = ref (Construct.NewEmptyModuleOrNamespaceType modKind)
+ MakeInnerEnvWithAcc addOpenToNameEnv env nm mtypeAcc modKind, mtypeAcc
+
+/// Make an environment suitable for processing inside a type definition
+let MakeInnerEnvForTyconRef env tcref isExtrinsicExtension =
+ if isExtrinsicExtension then
+ // Extension members don't get access to protected stuff
+ env
+ else
+ // Regular members get access to protected stuff
+ let env = EnterFamilyRegion tcref env
+ // Note: assumes no nesting
+ let eAccessPath = env.eCompPath.NestedCompPath tcref.LogicalName ModuleOrType
+ { env with
+ eAccessRights = ComputeAccessRights eAccessPath env.eInternalsVisibleCompPaths env.eFamilyType // update this computed field
+ eAccessPath = eAccessPath }
+
+/// Make an environment suitable for processing inside a member definition
+let MakeInnerEnvForMember env (v: Val) =
+ match v.MemberInfo with
+ | None -> env
+ | Some _ -> MakeInnerEnvForTyconRef env v.MemberApparentEntity v.IsExtensionMember
+
+/// Get the current accumulator for the namespace/module we're in
+let GetCurrAccumulatedModuleOrNamespaceType env = !(env.eModuleOrNamespaceTypeAccumulator)
+
+/// Set the current accumulator for the namespace/module we're in, updating the inferred contents
+let SetCurrAccumulatedModuleOrNamespaceType env x = env.eModuleOrNamespaceTypeAccumulator := x
+
+/// Set up the initial environment accounting for the enclosing "namespace X.Y.Z" definition
+let LocateEnv ccu env enclosingNamespacePath =
+ let cpath = compPathOfCcu ccu
+ let env =
+ {env with
+ ePath = []
+ eCompPath = cpath
+ eAccessPath = cpath
+ // update this computed field
+ eAccessRights = ComputeAccessRights cpath env.eInternalsVisibleCompPaths env.eFamilyType }
+ let env = List.fold (fun env id -> MakeInnerEnv false env id Namespace |> fst) env enclosingNamespacePath
+ let env = { env with eNameResEnv = { env.NameEnv with eDisplayEnv = env.DisplayEnv.AddOpenPath (pathOfLid env.ePath) } }
+ env
+
+
+//-------------------------------------------------------------------------
+// Helpers for unification
+//-------------------------------------------------------------------------
+
+/// When the context is matching the oldRange then this function shrinks it to newRange.
+/// This can be used to change context over no-op expressions like parens.
+let ShrinkContext env oldRange newRange =
+ match env.eContextInfo with
+ | ContextInfo.NoContext
+ | ContextInfo.RecordFields
+ | ContextInfo.TupleInRecordFields
+ | ContextInfo.ReturnInComputationExpression
+ | ContextInfo.YieldInComputationExpression
+ | ContextInfo.RuntimeTypeTest _
+ | ContextInfo.DowncastUsedInsteadOfUpcast _
+ | ContextInfo.SequenceExpression _ ->
+ env
+ | ContextInfo.CollectionElement (b,m) ->
+ if not (Range.equals m oldRange) then env else
+ { env with eContextInfo = ContextInfo.CollectionElement(b,newRange) }
+ | ContextInfo.FollowingPatternMatchClause m ->
+ if not (Range.equals m oldRange) then env else
+ { env with eContextInfo = ContextInfo.FollowingPatternMatchClause newRange }
+ | ContextInfo.PatternMatchGuard m ->
+ if not (Range.equals m oldRange) then env else
+ { env with eContextInfo = ContextInfo.PatternMatchGuard newRange }
+ | ContextInfo.IfExpression m ->
+ if not (Range.equals m oldRange) then env else
+ { env with eContextInfo = ContextInfo.IfExpression newRange }
+ | ContextInfo.OmittedElseBranch m ->
+ if not (Range.equals m oldRange) then env else
+ { env with eContextInfo = ContextInfo.OmittedElseBranch newRange }
+ | ContextInfo.ElseBranchResult m ->
+ if not (Range.equals m oldRange) then env else
+ { env with eContextInfo = ContextInfo.ElseBranchResult newRange }
+
+/// Optimized unification routine that avoids creating new inference
+/// variables unnecessarily
+let UnifyRefTupleType contextInfo cenv denv m ty ps =
+ let ptys =
+ if isRefTupleTy cenv.g ty then
+ let ptys = destRefTupleTy cenv.g ty
+ if List.length ps = List.length ptys then ptys
+ else NewInferenceTypes ps
+ else NewInferenceTypes ps
+
+ let contextInfo =
+ match contextInfo with
+ | ContextInfo.RecordFields -> ContextInfo.TupleInRecordFields
+ | _ -> contextInfo
+
+ AddCxTypeEqualsType contextInfo denv cenv.css m ty (TType_tuple (tupInfoRef, ptys))
+ ptys
+
+/// Allow the inference of structness from the known type, e.g.
+/// let (x: struct (int * int)) = (3,4)
+let UnifyTupleTypeAndInferCharacteristics contextInfo cenv denv m knownTy isExplicitStruct ps =
+ let tupInfo, ptys =
+ if isAnyTupleTy cenv.g knownTy then
+ let tupInfo, ptys = destAnyTupleTy cenv.g knownTy
+ let tupInfo = (if isExplicitStruct then tupInfoStruct else tupInfo)
+ let ptys =
+ if List.length ps = List.length ptys then ptys
+ else NewInferenceTypes ps
+ tupInfo, ptys
+ else
+ mkTupInfo isExplicitStruct, NewInferenceTypes ps
+
+ let contextInfo =
+ match contextInfo with
+ | ContextInfo.RecordFields -> ContextInfo.TupleInRecordFields
+ | _ -> contextInfo
+
+ let ty2 = TType_tuple (tupInfo, ptys)
+ AddCxTypeEqualsType contextInfo denv cenv.css m knownTy ty2
+ tupInfo, ptys
+
+// Allow inference of assembly-affinity and structness from the known type - even from another assembly. This is a rule of
+// the language design and allows effective cross-assembly use of anonymous types in some limited circumstances.
+let UnifyAnonRecdTypeAndInferCharacteristics contextInfo cenv denv m ty isExplicitStruct unsortedNames =
+ let anonInfo, ptys =
+ match tryDestAnonRecdTy cenv.g ty with
+ | ValueSome (anonInfo, ptys) ->
+ // Note: use the assembly of the known type, not the current assembly
+ // Note: use the structness of the known type, unless explicit
+ // Note: use the names of our type, since they are always explicit
+ let tupInfo = (if isExplicitStruct then tupInfoStruct else anonInfo.TupInfo)
+ let anonInfo = AnonRecdTypeInfo.Create(anonInfo.Assembly, tupInfo, unsortedNames)
+ let ptys =
+ if List.length ptys = Array.length unsortedNames then ptys
+ else NewInferenceTypes (Array.toList anonInfo.SortedNames)
+ anonInfo, ptys
+ | ValueNone ->
+ // Note: no known anonymous record type - use our assembly
+ let anonInfo = AnonRecdTypeInfo.Create(cenv.topCcu, mkTupInfo isExplicitStruct, unsortedNames)
+ anonInfo, NewInferenceTypes (Array.toList anonInfo.SortedNames)
+ let ty2 = TType_anon (anonInfo, ptys)
+ AddCxTypeEqualsType contextInfo denv cenv.css m ty ty2
+ anonInfo, ptys
+
+
+/// Optimized unification routine that avoids creating new inference
+/// variables unnecessarily
+let UnifyFunctionTypeUndoIfFailed cenv denv m ty =
+ match tryDestFunTy cenv.g ty with
+ | ValueNone ->
+ let domainTy = NewInferenceType ()
+ let resultTy = NewInferenceType ()
+ if AddCxTypeEqualsTypeUndoIfFailed denv cenv.css m ty (domainTy --> resultTy) then
+ ValueSome(domainTy, resultTy)
+ else
+ ValueNone
+ | r -> r
+
+/// Optimized unification routine that avoids creating new inference
+/// variables unnecessarily
+let UnifyFunctionType extraInfo cenv denv mFunExpr ty =
+ match UnifyFunctionTypeUndoIfFailed cenv denv mFunExpr ty with
+ | ValueSome res -> res
+ | ValueNone ->
+ match extraInfo with
+ | Some argm -> error (NotAFunction(denv, ty, mFunExpr, argm))
+ | None -> error (FunctionExpected(denv, ty, mFunExpr))
+
+let ReportImplicitlyIgnoredBoolExpression denv m ty expr =
+ let checkExpr m expr =
+ match expr with
+ | Expr.App (Expr.Val (vf, _, _), _, _, exprs, _) when vf.LogicalName = opNameEquals ->
+ match exprs with
+ | Expr.App (Expr.Val (propRef, _, _), _, _, Expr.Val (vf, _, _) :: _, _) :: _ ->
+ if propRef.IsPropertyGetterMethod then
+ let propertyName = propRef.PropertyName
+ let hasCorrespondingSetter =
+ match propRef.DeclaringEntity with
+ | Parent entityRef ->
+ entityRef.MembersOfFSharpTyconSorted
+ |> List.exists (fun valRef -> valRef.IsPropertySetterMethod && valRef.PropertyName = propertyName)
+ | _ -> false
+
+ if hasCorrespondingSetter then
+ UnitTypeExpectedWithPossiblePropertySetter (denv, ty, vf.DisplayName, propertyName, m)
+ else
+ UnitTypeExpectedWithEquality (denv, ty, m)
+ else
+ UnitTypeExpectedWithEquality (denv, ty, m)
+ | Expr.Op (TOp.ILCall (_, _, _, _, _, _, _, ilMethRef, _, _, _), _, Expr.Val (vf, _, _) :: _, _) :: _ when ilMethRef.Name.StartsWithOrdinal("get_") ->
+ UnitTypeExpectedWithPossiblePropertySetter (denv, ty, vf.DisplayName, PrettyNaming.ChopPropertyName(ilMethRef.Name), m)
+ | Expr.Val (vf, _, _) :: _ ->
+ UnitTypeExpectedWithPossibleAssignment (denv, ty, vf.IsMutable, vf.DisplayName, m)
+ | _ -> UnitTypeExpectedWithEquality (denv, ty, m)
+ | _ -> UnitTypeExpected (denv, ty, m)
+
+ match expr with
+ | Expr.Let (_, Expr.Sequential (_, inner, _, _, _), _, _)
+ | Expr.Sequential (_, inner, _, _, _) ->
+ let rec extractNext expr =
+ match expr with
+ | Expr.Sequential (_, inner, _, _, _) -> extractNext inner
+ | _ -> checkExpr expr.Range expr
+ extractNext inner
+ | expr -> checkExpr m expr
+
+let UnifyUnitType cenv (env: TcEnv) m ty expr =
+ let denv = env.DisplayEnv
+ if AddCxTypeEqualsTypeUndoIfFailed denv cenv.css m ty cenv.g.unit_ty then
+ true
+ else
+ let domainTy = NewInferenceType ()
+ let resultTy = NewInferenceType ()
+ if AddCxTypeEqualsTypeUndoIfFailed denv cenv.css m ty (domainTy --> resultTy) then
+ warning (FunctionValueUnexpected(denv, ty, m))
+ else
+ let reportImplicitlyDiscardError() =
+ if typeEquiv cenv.g cenv.g.bool_ty ty then
+ warning (ReportImplicitlyIgnoredBoolExpression denv m ty expr)
+ else
+ warning (UnitTypeExpected (denv, ty, m))
+
+ match env.eContextInfo with
+ | ContextInfo.SequenceExpression seqTy ->
+ let lifted = mkSeqTy cenv.g ty
+ if typeEquiv cenv.g seqTy lifted then
+ warning (Error (FSComp.SR.implicitlyDiscardedInSequenceExpression(NicePrint.prettyStringOfTy denv ty), m))
+ else
+ if isListTy cenv.g ty || isArrayTy cenv.g ty || typeEquiv cenv.g seqTy ty then
+ warning (Error (FSComp.SR.implicitlyDiscardedSequenceInSequenceExpression(NicePrint.prettyStringOfTy denv ty), m))
+ else
+ reportImplicitlyDiscardError()
+ | _ ->
+ reportImplicitlyDiscardError()
+
+ false
+
+let TryUnifyUnitTypeWithoutWarning cenv (env:TcEnv) m ty =
+ let denv = env.DisplayEnv
+ AddCxTypeEqualsTypeUndoIfFailedOrWarnings denv cenv.css m ty cenv.g.unit_ty
+
+// Logically extends System.AttributeTargets
+module AttributeTargets =
+ let FieldDecl = AttributeTargets.Field ||| AttributeTargets.Property
+ let FieldDeclRestricted = AttributeTargets.Field
+ let UnionCaseDecl = AttributeTargets.Method ||| AttributeTargets.Property
+ let TyconDecl = AttributeTargets.Class ||| AttributeTargets.Interface ||| AttributeTargets.Delegate ||| AttributeTargets.Struct ||| AttributeTargets.Enum
+ let ExnDecl = AttributeTargets.Class
+ let ModuleDecl = AttributeTargets.Class
+ let Top = AttributeTargets.Assembly ||| AttributeTargets.Module ||| AttributeTargets.Method
+
+let ForNewConstructors tcSink (env: TcEnv) mObjTy methodName meths =
+ let origItem = Item.CtorGroup(methodName, meths)
+ let callSink (item, minst) = CallMethodGroupNameResolutionSink tcSink (mObjTy, env.NameEnv, item, origItem, minst, ItemOccurence.Use, env.AccessRights)
+ let sendToSink minst refinedMeths = callSink (Item.CtorGroup(methodName, refinedMeths), minst)
+ match meths with
+ | [] ->
+ AfterResolution.DoNothing
+ | [_] ->
+ sendToSink emptyTyparInst meths
+ AfterResolution.DoNothing
+ | _ ->
+ AfterResolution.RecordResolution (None, (fun tpinst -> callSink (origItem, tpinst)), (fun (minfo, _, minst) -> sendToSink minst [minfo]), (fun () -> callSink (origItem, emptyTyparInst)))
+
+
+/// Typecheck rational constant terms in units-of-measure exponents
+let rec TcSynRationalConst c =
+ match c with
+ | SynRationalConst.Integer i -> intToRational i
+ | SynRationalConst.Negate c' -> NegRational (TcSynRationalConst c')
+ | SynRationalConst.Rational(p, q, _) -> DivRational (intToRational p) (intToRational q)
+
+/// Typecheck constant terms in expressions and patterns
+let TcConst cenv ty m env c =
+ let rec tcMeasure ms =
+ match ms with
+ | SynMeasure.One -> Measure.One
+ | SynMeasure.Named(tc, m) ->
+ let ad = env.eAccessRights
+ let _, tcref = ForceRaise(ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.Use OpenQualified env.eNameResEnv ad tc TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.No)
+ match tcref.TypeOrMeasureKind with
+ | TyparKind.Type -> error(Error(FSComp.SR.tcExpectedUnitOfMeasureNotType(), m))
+ | TyparKind.Measure -> Measure.Con tcref
+
+ | SynMeasure.Power(ms, exponent, _) -> Measure.RationalPower (tcMeasure ms, TcSynRationalConst exponent)
+ | SynMeasure.Product(ms1, ms2, _) -> Measure.Prod(tcMeasure ms1, tcMeasure ms2)
+ | SynMeasure.Divide(ms1, ((SynMeasure.Seq (_ :: (_ :: _), _)) as ms2), m) ->
+ warning(Error(FSComp.SR.tcImplicitMeasureFollowingSlash(), m))
+ Measure.Prod(tcMeasure ms1, Measure.Inv (tcMeasure ms2))
+ | SynMeasure.Divide(ms1, ms2, _) ->
+ Measure.Prod(tcMeasure ms1, Measure.Inv (tcMeasure ms2))
+ | SynMeasure.Seq(mss, _) -> ProdMeasures (List.map tcMeasure mss)
+ | SynMeasure.Anon _ -> error(Error(FSComp.SR.tcUnexpectedMeasureAnon(), m))
+ | SynMeasure.Var(_, m) -> error(Error(FSComp.SR.tcNonZeroConstantCannotHaveGenericUnit(), m))
+
+ let unif expected = UnifyTypes cenv env m ty expected
+
+ let unifyMeasureArg iszero tcr c =
+ let measureTy =
+ match c with
+ | SynConst.Measure(_, SynMeasure.Anon _) ->
+ (mkAppTy tcr [TType_measure (Measure.Var (NewAnonTypar (TyparKind.Measure, m, TyparRigidity.Anon, (if iszero then NoStaticReq else HeadTypeStaticReq), TyparDynamicReq.No)))])
+
+ | SynConst.Measure(_, ms) -> mkAppTy tcr [TType_measure (tcMeasure ms)]
+ | _ -> mkAppTy tcr [TType_measure Measure.One]
+ unif measureTy
+
+ let expandedMeasurablesEnabled =
+ cenv.g.langVersion.SupportsFeature LanguageFeature.ExpandedMeasurables
+
+ match c with
+ | SynConst.Unit -> unif cenv.g.unit_ty; Const.Unit
+ | SynConst.Bool i -> unif cenv.g.bool_ty; Const.Bool i
+ | SynConst.Single f -> unif cenv.g.float32_ty; Const.Single f
+ | SynConst.Double f -> unif cenv.g.float_ty; Const.Double f
+ | SynConst.Decimal f -> unif (mkAppTy cenv.g.decimal_tcr []); Const.Decimal f
+ | SynConst.SByte i -> unif cenv.g.sbyte_ty; Const.SByte i
+ | SynConst.Int16 i -> unif cenv.g.int16_ty; Const.Int16 i
+ | SynConst.Int32 i -> unif cenv.g.int_ty; Const.Int32 i
+ | SynConst.Int64 i -> unif cenv.g.int64_ty; Const.Int64 i
+ | SynConst.IntPtr i -> unif cenv.g.nativeint_ty; Const.IntPtr i
+ | SynConst.Byte i -> unif cenv.g.byte_ty; Const.Byte i
+ | SynConst.UInt16 i -> unif cenv.g.uint16_ty; Const.UInt16 i
+ | SynConst.UInt32 i -> unif cenv.g.uint32_ty; Const.UInt32 i
+ | SynConst.UInt64 i -> unif cenv.g.uint64_ty; Const.UInt64 i
+ | SynConst.UIntPtr i -> unif cenv.g.unativeint_ty; Const.UIntPtr i
+ | SynConst.Measure(SynConst.Single f, _) -> unifyMeasureArg (f=0.0f) cenv.g.pfloat32_tcr c; Const.Single f
+ | SynConst.Measure(SynConst.Double f, _) -> unifyMeasureArg (f=0.0) cenv.g.pfloat_tcr c; Const.Double f
+ | SynConst.Measure(SynConst.Decimal f, _) -> unifyMeasureArg false cenv.g.pdecimal_tcr c; Const.Decimal f
+ | SynConst.Measure(SynConst.SByte i, _) -> unifyMeasureArg (i=0y) cenv.g.pint8_tcr c; Const.SByte i
+ | SynConst.Measure(SynConst.Int16 i, _) -> unifyMeasureArg (i=0s) cenv.g.pint16_tcr c; Const.Int16 i
+ | SynConst.Measure(SynConst.Int32 i, _) -> unifyMeasureArg (i=0) cenv.g.pint_tcr c; Const.Int32 i
+ | SynConst.Measure(SynConst.Int64 i, _) -> unifyMeasureArg (i=0L) cenv.g.pint64_tcr c; Const.Int64 i
+ | SynConst.Measure(SynConst.IntPtr i, _) when expandedMeasurablesEnabled -> unifyMeasureArg (i=0L) cenv.g.pnativeint_tcr c; Const.IntPtr i
+ | SynConst.Measure(SynConst.Byte i, _) when expandedMeasurablesEnabled -> unifyMeasureArg (i=0uy) cenv.g.puint8_tcr c; Const.Byte i
+ | SynConst.Measure(SynConst.UInt16 i, _) when expandedMeasurablesEnabled -> unifyMeasureArg (i=0us) cenv.g.puint16_tcr c; Const.UInt16 i
+ | SynConst.Measure(SynConst.UInt32 i, _) when expandedMeasurablesEnabled -> unifyMeasureArg (i=0u) cenv.g.puint_tcr c; Const.UInt32 i
+ | SynConst.Measure(SynConst.UInt64 i, _) when expandedMeasurablesEnabled -> unifyMeasureArg (i=0UL) cenv.g.puint64_tcr c; Const.UInt64 i
+ | SynConst.Measure(SynConst.UIntPtr i, _) when expandedMeasurablesEnabled -> unifyMeasureArg (i=0UL) cenv.g.punativeint_tcr c; Const.UIntPtr i
+ | SynConst.Char c -> unif cenv.g.char_ty; Const.Char c
+ | SynConst.String (s, _) -> unif cenv.g.string_ty; Const.String s
+ | SynConst.UserNum _ -> error (InternalError(FSComp.SR.tcUnexpectedBigRationalConstant(), m))
+ | SynConst.Measure _ -> error (Error(FSComp.SR.tcInvalidTypeForUnitsOfMeasure(), m))
+ | SynConst.UInt16s _ -> error (InternalError(FSComp.SR.tcUnexpectedConstUint16Array(), m))
+ | SynConst.Bytes _ -> error (InternalError(FSComp.SR.tcUnexpectedConstByteArray(), m))
+
+/// Convert an Abstract IL ILFieldInit value read from .NET metadata to a TAST constant
+let TcFieldInit (_m: range) lit = PatternMatchCompilation.ilFieldToTastConst lit
+
+//-------------------------------------------------------------------------
+// Arities. These serve two roles in the system:
+// 1. syntactic arities come from the syntactic forms found
+// signature files and the syntactic forms of function and member definitions.
+// 2. compiled arities representing representation choices w.r.t. internal representations of
+// functions and members.
+//-------------------------------------------------------------------------
+
+// Adjust the arities that came from the parsing of the toptyp (arities) to be a valSynData.
+// This means replacing the "[unitArg]" arising from a "unit -> ty" with a "[]".
+let AdjustValSynInfoInSignature g ty (SynValInfo(argsData, retData) as sigMD) =
+ if argsData.Length = 1 && argsData.Head.Length = 1 && isFunTy g ty && typeEquiv g g.unit_ty (domainOfFunTy g ty) then
+ SynValInfo(argsData.Head.Tail :: argsData.Tail, retData)
+ else
+ sigMD
+
+/// The ValReprInfo for a value, except the number of typars is not yet inferred
+type PartialValReprInfo =
+ | PartialValReprInfo of
+ curriedArgInfos: ArgReprInfo list list *
+ returnInfo: ArgReprInfo
+
+let TranslateTopArgSynInfo isArg m tcAttributes (SynArgInfo(Attributes attrs, isOpt, nm)) =
+ // Synthesize an artificial "OptionalArgument" attribute for the parameter
+ let optAttrs =
+ if isOpt then
+ [ ( { TypeName=LongIdentWithDots(pathToSynLid m ["Microsoft";"FSharp";"Core";"OptionalArgument"], [])
+ ArgExpr=mkSynUnit m
+ Target=None
+ AppliesToGetterAndSetter=false
+ Range=m} : SynAttribute) ]
+ else
+ []
+
+ if isArg && not (isNil attrs) && Option.isNone nm then
+ errorR(Error(FSComp.SR.tcParameterRequiresName(), m))
+
+ if not isArg && Option.isSome nm then
+ errorR(Error(FSComp.SR.tcReturnValuesCannotHaveNames(), m))
+
+ // Call the attribute checking function
+ let attribs = tcAttributes (optAttrs@attrs)
+ ({ Attribs = attribs; Name = nm } : ArgReprInfo)
+
+/// Members have an arity inferred from their syntax. This "valSynData" is not quite the same as the arities
+/// used in the middle and backends of the compiler ("topValInfo").
+/// "0" in a valSynData (see arity_of_pat) means a "unit" arg in a topValInfo
+/// Hence remove all "zeros" from arity and replace them with 1 here.
+/// Note we currently use the compiled form for choosing unique names, to distinguish overloads because this must match up
+/// between signature and implementation, and the signature just has "unit".
+let TranslateTopValSynInfo m tcAttributes (SynValInfo(argsData, retData)) =
+ PartialValReprInfo (argsData |> List.mapSquared (TranslateTopArgSynInfo true m (tcAttributes AttributeTargets.Parameter)),
+ retData |> TranslateTopArgSynInfo false m (tcAttributes AttributeTargets.ReturnValue))
+
+let TranslatePartialArity tps (PartialValReprInfo (argsData, retData)) =
+ ValReprInfo(ValReprInfo.InferTyparInfo tps, argsData, retData)
+
+//-------------------------------------------------------------------------
+// Members
+//-------------------------------------------------------------------------
+
+let ComputeLogicalName (id: Ident) memberFlags =
+ match memberFlags.MemberKind with
+ | MemberKind.ClassConstructor -> ".cctor"
+ | MemberKind.Constructor -> ".ctor"
+ | MemberKind.Member ->
+ match id.idText with
+ | (".ctor" | ".cctor") as r -> errorR(Error(FSComp.SR.tcInvalidMemberNameCtor(), id.idRange)); r
+ | r -> r
+ | MemberKind.PropertyGetSet -> error(InternalError(FSComp.SR.tcMemberKindPropertyGetSetNotExpected(), id.idRange))
+ | MemberKind.PropertyGet -> "get_" + id.idText
+ | MemberKind.PropertySet -> "set_" + id.idText
+
+type PreValMemberInfo =
+ | PreValMemberInfo of
+ memberInfo: ValMemberInfo *
+ logicalName: string *
+ compiledName: string
+
+/// Make the unique "name" for a member.
+//
+// optImplSlotTy = None (for classes) or Some ty (when implementing interface type ty)
+let MakeMemberDataAndMangledNameForMemberVal(g, tcref, isExtrinsic, attrs, optImplSlotTys, memberFlags, valSynData, id, isCompGen) =
+ let logicalName = ComputeLogicalName id memberFlags
+ let optIntfSlotTys = if optImplSlotTys |> List.forall (isInterfaceTy g) then optImplSlotTys else []
+ let memberInfo: ValMemberInfo =
+ { ApparentEnclosingEntity=tcref
+ MemberFlags=memberFlags
+ IsImplemented=false
+ // NOTE: This value is initially only set for interface implementations and those overrides
+ // where we manage to pre-infer which abstract is overridden by the method. It is filled in
+ // properly when we check the allImplemented implementation checks at the end of the inference scope.
+ ImplementedSlotSigs=optImplSlotTys |> List.map (fun ity -> TSlotSig(logicalName, ity, [], [], [], None)) }
+ let isInstance = MemberIsCompiledAsInstance g tcref isExtrinsic memberInfo attrs
+ if (memberFlags.IsDispatchSlot || not (isNil optIntfSlotTys)) then
+ if not isInstance then
+ errorR(VirtualAugmentationOnNullValuedType(id.idRange))
+ elif not memberFlags.IsOverrideOrExplicitImpl && memberFlags.IsInstance then
+ if not isExtrinsic && not isInstance then
+ warning(NonVirtualAugmentationOnNullValuedType(id.idRange))
+
+ let compiledName =
+ if isExtrinsic then
+ let tname = tcref.LogicalName
+ let text = tname + "." + logicalName
+ let text = if memberFlags.MemberKind <> MemberKind.Constructor && memberFlags.MemberKind <> MemberKind.ClassConstructor && not memberFlags.IsInstance then text + ".Static" else text
+ let text = if memberFlags.IsOverrideOrExplicitImpl then text + ".Override" else text
+ text
+ else if not optIntfSlotTys.IsEmpty then
+ // interface implementation
+ if optIntfSlotTys.Length > 1 then
+ failwithf "unexpected: optIntfSlotTys.Length > 1 (== %i) in MakeMemberDataAndMangledNameForMemberVal for '%s'" optIntfSlotTys.Length logicalName
+ qualifiedInterfaceImplementationName g optIntfSlotTys.Head logicalName
+ else
+ List.foldBack (fun x -> qualifiedMangledNameOfTyconRef (tcrefOfAppTy g x)) optIntfSlotTys logicalName
+
+ if not isCompGen && IsMangledOpName id.idText && IsInfixOperator id.idText then
+ let m = id.idRange
+ let name = DecompileOpName id.idText
+ // Check symbolic members. Expect valSynData implied arity to be [[2]].
+ match SynInfo.AritiesOfArgs valSynData with
+ | [] | [0] -> warning(Error(FSComp.SR.memberOperatorDefinitionWithNoArguments name, m))
+ | n :: otherArgs ->
+ let opTakesThreeArgs = PrettyNaming.IsTernaryOperator name
+ if n<>2 && not opTakesThreeArgs then warning(Error(FSComp.SR.memberOperatorDefinitionWithNonPairArgument(name, n), m))
+ if n<>3 && opTakesThreeArgs then warning(Error(FSComp.SR.memberOperatorDefinitionWithNonTripleArgument(name, n), m))
+ if not (isNil otherArgs) then warning(Error(FSComp.SR.memberOperatorDefinitionWithCurriedArguments name, m))
+
+ if isExtrinsic && IsMangledOpName id.idText then
+ warning(Error(FSComp.SR.tcMemberOperatorDefinitionInExtrinsic(), id.idRange))
+
+ PreValMemberInfo(memberInfo, logicalName, compiledName)
+
+type OverridesOK =
+ | OverridesOK
+ | WarnOnOverrides
+ | ErrorOnOverrides
+
+/// A type to represent information associated with values to indicate what explicit (declared) type parameters
+/// are given and what additional type parameters can be inferred, if any.
+///
+/// The declared type parameters, e.g. let f<'a> (x:'a) = x, plus an indication
+/// of whether additional polymorphism may be inferred, e.g. let f<'a, ..> (x:'a) y = x
+type ExplicitTyparInfo =
+ | ExplicitTyparInfo of
+ rigidCopyOfDeclaredTypars: Typars *
+ declaredTypars: Typars *
+ infer: bool
+
+let permitInferTypars = ExplicitTyparInfo ([], [], true)
+let dontInferTypars = ExplicitTyparInfo ([], [], false)
+
+type ArgAndRetAttribs = ArgAndRetAttribs of Attribs list list * Attribs
+let noArgOrRetAttribs = ArgAndRetAttribs ([], [])
+
+/// A flag to represent the sort of bindings are we processing.
+/// Processing "declaration" and "class" bindings that make up a module (such as "let x = 1 let y = 2")
+/// shares the same code paths (e.g. TcLetBinding and TcLetrec) as processing expression bindings (such as "let x = 1 in ...")
+/// Member bindings also use this path.
+//
+/// However there are differences in how different bindings get processed,
+/// i.e. module bindings get published to the implicitly accumulated module type, but expression 'let' bindings don't.
+type DeclKind =
+ | ModuleOrMemberBinding
+
+ /// Extensions to a type within the same assembly
+ | IntrinsicExtensionBinding
+
+ /// Extensions to a type in a different assembly
+ | ExtrinsicExtensionBinding
+
+ | ClassLetBinding of isStatic: bool
+
+ | ObjectExpressionOverrideBinding
+
+ | ExpressionBinding
+
+ static member IsModuleOrMemberOrExtensionBinding x =
+ match x with
+ | ModuleOrMemberBinding -> true
+ | IntrinsicExtensionBinding -> true
+ | ExtrinsicExtensionBinding -> true
+ | ClassLetBinding _ -> false
+ | ObjectExpressionOverrideBinding -> false
+ | ExpressionBinding -> false
+
+ static member MustHaveArity x = DeclKind.IsModuleOrMemberOrExtensionBinding x
+
+ member x.CanBeDllImport =
+ match x with
+ | ModuleOrMemberBinding -> true
+ | IntrinsicExtensionBinding -> true
+ | ExtrinsicExtensionBinding -> true
+ | ClassLetBinding _ -> true
+ | ObjectExpressionOverrideBinding -> false
+ | ExpressionBinding -> false
+
+ static member IsAccessModifierPermitted x = DeclKind.IsModuleOrMemberOrExtensionBinding x
+
+ static member ImplicitlyStatic x = DeclKind.IsModuleOrMemberOrExtensionBinding x
+
+ static member AllowedAttribTargets memberFlagsOpt x =
+ match x with
+ | ModuleOrMemberBinding | ObjectExpressionOverrideBinding ->
+ match memberFlagsOpt with
+ | Some flags when flags.MemberKind = MemberKind.Constructor -> AttributeTargets.Constructor
+ | Some flags when flags.MemberKind = MemberKind.PropertyGetSet -> AttributeTargets.Event ||| AttributeTargets.Property
+ | Some flags when flags.MemberKind = MemberKind.PropertyGet -> AttributeTargets.Event ||| AttributeTargets.Property
+ | Some flags when flags.MemberKind = MemberKind.PropertySet -> AttributeTargets.Property
+ | Some _ -> AttributeTargets.Method
+ | None -> AttributeTargets.Field ||| AttributeTargets.Method ||| AttributeTargets.Property
+ | IntrinsicExtensionBinding -> AttributeTargets.Method ||| AttributeTargets.Property
+ | ExtrinsicExtensionBinding -> AttributeTargets.Method ||| AttributeTargets.Property
+ | ClassLetBinding _ -> AttributeTargets.Field ||| AttributeTargets.Method
+ | ExpressionBinding -> enum 0 // indicates attributes not allowed on expression 'let' bindings
+
+ // Note: now always true
+ static member CanGeneralizeConstrainedTypars x =
+ match x with
+ | ModuleOrMemberBinding -> true
+ | IntrinsicExtensionBinding -> true
+ | ExtrinsicExtensionBinding -> true
+ | ClassLetBinding _ -> true
+ | ObjectExpressionOverrideBinding -> true
+ | ExpressionBinding -> true
+
+ static member ConvertToLinearBindings x =
+ match x with
+ | ModuleOrMemberBinding -> true
+ | IntrinsicExtensionBinding -> true
+ | ExtrinsicExtensionBinding -> true
+ | ClassLetBinding _ -> true
+ | ObjectExpressionOverrideBinding -> true
+ | ExpressionBinding -> false
+
+ static member CanOverrideOrImplement x =
+ match x with
+ | ModuleOrMemberBinding -> OverridesOK
+ | IntrinsicExtensionBinding -> WarnOnOverrides
+ | ExtrinsicExtensionBinding -> ErrorOnOverrides
+ | ClassLetBinding _ -> ErrorOnOverrides
+ | ObjectExpressionOverrideBinding -> OverridesOK
+ | ExpressionBinding -> ErrorOnOverrides
+
+//-------------------------------------------------------------------------
+// Data structures that track the gradual accumulation of information
+// about values and members during inference.
+//-------------------------------------------------------------------------
+
+/// The results of preliminary pass over patterns to extract variables being declared.
+// We should make this a record for cleaner code
+type PrelimValScheme1 =
+ | PrelimValScheme1 of
+ id: Ident *
+ explicitTyparInfo: ExplicitTyparInfo *
+ TType *
+ PartialValReprInfo option *
+ PreValMemberInfo option *
+ bool *
+ ValInline *
+ ValBaseOrThisInfo *
+ ArgAndRetAttribs *
+ SynAccess option *
+ bool
+
+ member x.Type = let (PrelimValScheme1(_, _, ty, _, _, _, _, _, _, _, _)) = x in ty
+
+ member x.Ident = let (PrelimValScheme1(id, _, _, _, _, _, _, _, _, _, _)) = x in id
+
+/// The results of applying let-style generalization after type checking.
+// We should make this a record for cleaner code
+type PrelimValScheme2 =
+ PrelimValScheme2 of
+ Ident *
+ TypeScheme *
+ PartialValReprInfo option *
+ PreValMemberInfo option *
+ bool *
+ ValInline *
+ ValBaseOrThisInfo *
+ ArgAndRetAttribs *
+ SynAccess option *
+ bool *
+ bool (* hasDeclaredTypars *)
+
+
+/// The results of applying arity inference to PrelimValScheme2
+type ValScheme =
+ | ValScheme of
+ id: Ident *
+ typeScheme: TypeScheme *
+ topValInfo: ValReprInfo option *
+ memberInfo: PreValMemberInfo option *
+ isMutable: bool *
+ inlineInfo: ValInline *
+ baseOrThisInfo: ValBaseOrThisInfo *
+ visibility: SynAccess option *
+ compgen: bool *
+ isIncrClass: bool *
+ isTyFunc: bool *
+ hasDeclaredTypars: bool
+
+ member x.GeneralizedTypars = let (ValScheme(_, TypeScheme(gtps, _), _, _, _, _, _, _, _, _, _, _)) = x in gtps
+
+ member x.TypeScheme = let (ValScheme(_, ts, _, _, _, _, _, _, _, _, _, _)) = x in ts
+
+ member x.ValReprInfo = let (ValScheme(_, _, topValInfo, _, _, _, _, _, _, _, _, _)) = x in topValInfo
+
+/// Translation of patterns is split into three phases. The first collects names.
+/// The second is run after val_specs have been created for those names and inference
+/// has been resolved. The second phase is run by applying a function returned by the
+/// first phase. The input to the second phase is a List.map that gives the Val and type scheme
+/// for each value bound by the pattern.
+type TcPatPhase2Input =
+ | TcPatPhase2Input of (Val * TypeScheme) NameMap * bool
+ // Get an input indicating we are no longer on the left-most path through a disjunctive "or" pattern
+ member x.RightPath = (let (TcPatPhase2Input(a, _)) = x in TcPatPhase2Input(a, false))
+
+/// The first phase of checking and elaborating a binding leaves a goop of information.
+/// This is a bit of a mess: much of this information is also carried on a per-value basis by the
+/// "NameMap".
+type CheckedBindingInfo =
+ | CheckedBindingInfo of
+ inlineFlag: ValInline *
+ valAttribs: Attribs *
+ xmlDoc: XmlDoc *
+ tcPatPhase2: (TcPatPhase2Input -> PatternMatchCompilation.Pattern) *
+ exlicitTyparInfo: ExplicitTyparInfo *
+ nameToPrelimValSchemeMap: NameMap *
+ rhsExprChecked: Expr *
+ argAndRetAttribs: ArgAndRetAttribs *
+ overallPatTy: TType *
+ mBinding: range *
+ spBind: DebugPointForBinding *
+ isCompilerGenerated: bool *
+ literalValue: Const option *
+ isFixed: bool
+ member x.Expr = let (CheckedBindingInfo(_, _, _, _, _, _, expr, _, _, _, _, _, _, _)) = x in expr
+ member x.SeqPoint = let (CheckedBindingInfo(_, _, _, _, _, _, _, _, _, _, spBind, _, _, _)) = x in spBind
+
+/// Return the generalized type for a type scheme
+let GeneralizedTypeForTypeScheme typeScheme =
+ let (TypeScheme(generalizedTypars, tau)) = typeScheme
+ mkForallTyIfNeeded generalizedTypars tau
+
+/// Create a type scheme for something that is not generic
+let NonGenericTypeScheme ty = TypeScheme([], ty)
+
+//-------------------------------------------------------------------------
+// Helpers related to publishing values, types and members into the
+// elaborated representation.
+//-------------------------------------------------------------------------
+
+let UpdateAccModuleOrNamespaceType cenv env f =
+ // When compiling FSharp.Core, modify the fslib CCU to ensure forward stable references used by
+ // the compiler can be resolved ASAP. Not at all pretty but it's hard to
+ // find good ways to do references from the compiler into a term graph.
+ if cenv.compilingCanonicalFslibModuleType then
+ let nleref = mkNonLocalEntityRef cenv.topCcu (arrPathOfLid env.ePath)
+ let modul = nleref.Deref
+ modul.entity_modul_contents <- MaybeLazy.Strict (f true modul.ModuleOrNamespaceType)
+ SetCurrAccumulatedModuleOrNamespaceType env (f false (GetCurrAccumulatedModuleOrNamespaceType env))
+
+let PublishModuleDefn cenv env mspec =
+ UpdateAccModuleOrNamespaceType cenv env (fun intoFslibCcu mty ->
+ if intoFslibCcu then mty
+ else mty.AddEntity mspec)
+ let item = Item.ModuleOrNamespaces([mkLocalModRef mspec])
+ CallNameResolutionSink cenv.tcSink (mspec.Range, env.NameEnv, item, emptyTyparInst, ItemOccurence.Binding, env.AccessRights)
+
+let PublishTypeDefn cenv env mspec =
+ UpdateAccModuleOrNamespaceType cenv env (fun _ mty ->
+ mty.AddEntity mspec)
+
+let PublishValueDefnPrim cenv env (vspec: Val) =
+ UpdateAccModuleOrNamespaceType cenv env (fun _ mty ->
+ mty.AddVal vspec)
+
+let PublishValueDefn cenv env declKind (vspec: Val) =
+ if (declKind = ModuleOrMemberBinding) &&
+ ((GetCurrAccumulatedModuleOrNamespaceType env).ModuleOrNamespaceKind = Namespace) &&
+ (Option.isNone vspec.MemberInfo) then
+ errorR(NumberedError(FSComp.SR.tcNamespaceCannotContainValues(), vspec.Range))
+
+ if (declKind = ExtrinsicExtensionBinding) &&
+ ((GetCurrAccumulatedModuleOrNamespaceType env).ModuleOrNamespaceKind = Namespace) then
+ errorR(Error(FSComp.SR.tcNamespaceCannotContainExtensionMembers(), vspec.Range))
+
+ // Publish the value to the module type being generated.
+ match declKind with
+ | ModuleOrMemberBinding
+ | ExtrinsicExtensionBinding
+ | IntrinsicExtensionBinding -> PublishValueDefnPrim cenv env vspec
+ | _ -> ()
+
+ match vspec.MemberInfo with
+ | Some _ when
+ (not vspec.IsCompilerGenerated &&
+ // Extrinsic extensions don't get added to the tcaug
+ not (declKind = ExtrinsicExtensionBinding)) ->
+ // // Static initializers don't get published to the tcaug
+ // not (memberInfo.MemberFlags.MemberKind = MemberKind.ClassConstructor)) ->
+
+ let tcaug = vspec.MemberApparentEntity.TypeContents
+ let vref = mkLocalValRef vspec
+ tcaug.tcaug_adhoc <- NameMultiMap.add vspec.LogicalName vref tcaug.tcaug_adhoc
+ tcaug.tcaug_adhoc_list.Add (ValRefIsExplicitImpl cenv.g vref, vref)
+ | _ -> ()
+
+let CombineVisibilityAttribs vis1 vis2 m =
+ match vis1 with
+ | Some _ ->
+ if Option.isSome vis2 then
+ errorR(Error(FSComp.SR.tcMultipleVisibilityAttributes(), m))
+ vis1
+ | _ -> vis2
+
+let ComputeAccessAndCompPath env declKindOpt m vis overrideVis actualParent =
+ let accessPath = env.eAccessPath
+ let accessModPermitted =
+ match declKindOpt with
+ | None -> true
+ | Some declKind -> DeclKind.IsAccessModifierPermitted declKind
+
+ if Option.isSome vis && not accessModPermitted then
+ errorR(Error(FSComp.SR.tcMultipleVisibilityAttributesWithLet(), m))
+
+ let vis =
+ match overrideVis, vis with
+ | Some v, _ -> v
+ | _, None -> taccessPublic (* a module or member binding defaults to "public" *)
+ | _, Some SynAccess.Public -> taccessPublic
+ | _, Some SynAccess.Private -> taccessPrivate accessPath
+ | _, Some SynAccess.Internal -> taccessInternal
+
+ let vis =
+ match actualParent with
+ | ParentNone -> vis
+ | Parent tcref -> combineAccess vis tcref.Accessibility
+
+ let cpath = if accessModPermitted then Some env.eCompPath else None
+ vis, cpath
+
+let CheckForAbnormalOperatorNames cenv (idRange: range) coreDisplayName (memberInfoOpt: ValMemberInfo option) =
+ if (idRange.EndColumn - idRange.StartColumn <= 5) &&
+ not cenv.g.compilingFslib
+ then
+ let opName = DecompileOpName coreDisplayName
+ let isMember = memberInfoOpt.IsSome
+ match opName with
+ | PrettyNaming.Relational ->
+ if isMember then
+ warning(StandardOperatorRedefinitionWarning(FSComp.SR.tcInvalidMethodNameForRelationalOperator(opName, coreDisplayName), idRange))
+ else
+ warning(StandardOperatorRedefinitionWarning(FSComp.SR.tcInvalidOperatorDefinitionRelational opName, idRange))
+ | PrettyNaming.Equality ->
+ if isMember then
+ warning(StandardOperatorRedefinitionWarning(FSComp.SR.tcInvalidMethodNameForEquality(opName, coreDisplayName), idRange))
+ else
+ warning(StandardOperatorRedefinitionWarning(FSComp.SR.tcInvalidOperatorDefinitionEquality opName, idRange))
+ | PrettyNaming.Control ->
+ if isMember then
+ warning(StandardOperatorRedefinitionWarning(FSComp.SR.tcInvalidMemberName(opName, coreDisplayName), idRange))
+ else
+ warning(StandardOperatorRedefinitionWarning(FSComp.SR.tcInvalidOperatorDefinition opName, idRange))
+ | PrettyNaming.Indexer ->
+ if not isMember then
+ error(StandardOperatorRedefinitionWarning(FSComp.SR.tcInvalidIndexOperatorDefinition opName, idRange))
+ | PrettyNaming.FixedTypes ->
+ if isMember then
+ warning(StandardOperatorRedefinitionWarning(FSComp.SR.tcInvalidMemberNameFixedTypes opName, idRange))
+ | PrettyNaming.Other -> ()
+
+let MakeAndPublishVal cenv env (altActualParent, inSig, declKind, vrec, vscheme, attrs, doc, konst, isGeneratedEventVal) =
+
+ let (ValScheme(id, typeScheme, topValData, memberInfoOpt, isMutable, inlineFlag, baseOrThis, vis, compgen, isIncrClass, isTyFunc, hasDeclaredTypars)) = vscheme
+
+ let ty = GeneralizedTypeForTypeScheme typeScheme
+
+ let m = id.idRange
+
+ let isTopBinding =
+ match declKind with
+ | ModuleOrMemberBinding -> true
+ | ExtrinsicExtensionBinding -> true
+ | IntrinsicExtensionBinding -> true
+ | _ -> false
+
+ let isExtrinsic = (declKind = ExtrinsicExtensionBinding)
+
+ let actualParent, overrideVis =
+ // Use the parent of the member if it's available
+ // If it's an extrinsic extension member or not a member then use the containing module.
+ match memberInfoOpt with
+ | Some (PreValMemberInfo(memberInfo, _, _)) when not isExtrinsic ->
+ if memberInfo.ApparentEnclosingEntity.IsModuleOrNamespace then
+ errorR(InternalError(FSComp.SR.tcExpectModuleOrNamespaceParent(id.idText), m))
+
+ // Members of interface implementations have the accessibility of the interface
+ // they are implementing.
+ let vis =
+ if MemberIsExplicitImpl cenv.g memberInfo then
+ let slotSig = List.head memberInfo.ImplementedSlotSigs
+ match slotSig.ImplementedType with
+ | TType_app (tyconref, _) -> Some tyconref.Accessibility
+ | _ -> None
+ else
+ None
+ Parent(memberInfo.ApparentEnclosingEntity), vis
+ | _ -> altActualParent, None
+
+ let vis, _ = ComputeAccessAndCompPath env (Some declKind) id.idRange vis overrideVis actualParent
+
+ let inlineFlag =
+ if HasFSharpAttributeOpt cenv.g cenv.g.attrib_DllImportAttribute attrs then
+ if inlineFlag = ValInline.PseudoVal || inlineFlag = ValInline.Always then
+ errorR(Error(FSComp.SR.tcDllImportStubsCannotBeInlined(), m))
+ ValInline.Never
+ else
+ let implflags =
+ match TryFindFSharpAttribute cenv.g cenv.g.attrib_MethodImplAttribute attrs with
+ | Some (Attrib(_, _, [ AttribInt32Arg flags ], _, _, _, _)) -> flags
+ | _ -> 0x0
+ // MethodImplOptions.NoInlining = 0x8
+ let NO_INLINING = 0x8
+ if (implflags &&& NO_INLINING) <> 0x0 then
+ ValInline.Never
+ else
+ inlineFlag
+
+ // CompiledName not allowed on virtual/abstract/override members
+ let compiledNameAttrib = TryFindFSharpStringAttribute cenv.g cenv.g.attrib_CompiledNameAttribute attrs
+ if Option.isSome compiledNameAttrib then
+ match memberInfoOpt with
+ | Some (PreValMemberInfo(memberInfo, _, _)) ->
+ if memberInfo.MemberFlags.IsDispatchSlot || memberInfo.MemberFlags.IsOverrideOrExplicitImpl then
+ errorR(Error(FSComp.SR.tcCompiledNameAttributeMisused(), m))
+ | None ->
+ match altActualParent with
+ | ParentNone -> errorR(Error(FSComp.SR.tcCompiledNameAttributeMisused(), m))
+ | _ -> ()
+
+ let compiledNameIsOnProp =
+ match memberInfoOpt with
+ | Some (PreValMemberInfo(memberInfo, _, _)) ->
+ memberInfo.MemberFlags.MemberKind = MemberKind.PropertyGet ||
+ memberInfo.MemberFlags.MemberKind = MemberKind.PropertySet ||
+ memberInfo.MemberFlags.MemberKind = MemberKind.PropertyGetSet
+ | _ -> false
+
+ let compiledName =
+ match compiledNameAttrib with
+ // We fix up CompiledName on properties during codegen
+ | Some _ when not compiledNameIsOnProp -> compiledNameAttrib
+ | _ ->
+ match memberInfoOpt with
+ | Some (PreValMemberInfo(_, _, compiledName)) ->
+ Some compiledName
+ | None ->
+ None
+
+ let logicalName =
+ match memberInfoOpt with
+ | Some (PreValMemberInfo(_, logicalName, _)) ->
+ logicalName
+ | None ->
+ id.idText
+
+ let memberInfoOpt =
+ match memberInfoOpt with
+ | Some (PreValMemberInfo(memberInfo, _, _)) ->
+ Some memberInfo
+ | None ->
+ None
+
+ let mut = if isMutable then Mutable else Immutable
+ let vspec =
+ Construct.NewVal
+ (logicalName, id.idRange, compiledName, ty, mut,
+ compgen, topValData, vis, vrec, memberInfoOpt, baseOrThis, attrs, inlineFlag,
+ doc, isTopBinding, isExtrinsic, isIncrClass, isTyFunc,
+ (hasDeclaredTypars || inSig), isGeneratedEventVal, konst, actualParent)
+
+
+ CheckForAbnormalOperatorNames cenv id.idRange vspec.CoreDisplayName memberInfoOpt
+
+ PublishValueDefn cenv env declKind vspec
+
+ let shouldNotifySink (vspec: Val) =
+ match vspec.MemberInfo with
+ // `this` reference named `__`. It's either:
+ // * generated by compiler for auto properties or
+ // * provided by source code (i.e. `member _.Method = ...`)
+ // We don't notify sink about it to prevent generating `FSharpSymbol` for it and appearing in completion list.
+ | None when
+ let baseOrThisInfo = vspec.BaseOrThisInfo
+ baseOrThisInfo = ValBaseOrThisInfo.BaseVal || // visualfsharp#3699
+ baseOrThisInfo = ValBaseOrThisInfo.MemberThisVal && vspec.LogicalName = "__" -> false
+ | _ -> true
+
+ match cenv.tcSink.CurrentSink with
+ | Some _ when not vspec.IsCompilerGenerated && shouldNotifySink vspec ->
+ let nenv = AddFakeNamedValRefToNameEnv vspec.DisplayName env.NameEnv (mkLocalValRef vspec)
+ CallEnvSink cenv.tcSink (vspec.Range, nenv, env.eAccessRights)
+ let item = Item.Value(mkLocalValRef vspec)
+ CallNameResolutionSink cenv.tcSink (vspec.Range, nenv, item, emptyTyparInst, ItemOccurence.Binding, env.eAccessRights)
+ | _ -> ()
+
+ vspec
+
+let MakeAndPublishVals cenv env (altActualParent, inSig, declKind, vrec, valSchemes, attrs, doc, literalValue) =
+ Map.foldBack
+ (fun name (valscheme: ValScheme) values ->
+ Map.add name (MakeAndPublishVal cenv env (altActualParent, inSig, declKind, vrec, valscheme, attrs, doc, literalValue, false), valscheme.TypeScheme) values)
+ valSchemes
+ Map.empty
+
+let MakeAndPublishBaseVal cenv env baseIdOpt ty =
+ baseIdOpt
+ |> Option.map (fun (id: Ident) ->
+ let valscheme = ValScheme(id, NonGenericTypeScheme ty, None, None, false, ValInline.Never, BaseVal, None, false, false, false, false)
+ MakeAndPublishVal cenv env (ParentNone, false, ExpressionBinding, ValNotInRecScope, valscheme, [], XmlDoc.Empty, None, false))
+
+// Make the "delayed reference" value where the this pointer will reside after calling the base class constructor
+// Make the value for the 'this' pointer for use within a constructor
+let MakeAndPublishSafeThisVal cenv env (thisIdOpt: Ident option) thisTy =
+ match thisIdOpt with
+ | Some thisId ->
+ // for structs, thisTy is a byref
+ if not (isFSharpObjModelTy cenv.g thisTy) then
+ errorR(Error(FSComp.SR.tcStructsCanOnlyBindThisAtMemberDeclaration(), thisId.idRange))
+
+ let valScheme = ValScheme(thisId, NonGenericTypeScheme(mkRefCellTy cenv.g thisTy), None, None, false, ValInline.Never, CtorThisVal, None, false, false, false, false)
+ Some(MakeAndPublishVal cenv env (ParentNone, false, ExpressionBinding, ValNotInRecScope, valScheme, [], XmlDoc.Empty, None, false))
+
+ | None ->
+ None
+
+
+//-------------------------------------------------------------------------
+// Helpers for type inference for recursive bindings
+//-------------------------------------------------------------------------
+
+/// Fixup the type instantiation at recursive references. Used after the bindings have been
+/// checked. The fixups are applied by using mutation.
+let AdjustAndForgetUsesOfRecValue cenv (vrefTgt: ValRef) (valScheme: ValScheme) =
+ let (TypeScheme(generalizedTypars, _)) = valScheme.TypeScheme
+ let fty = GeneralizedTypeForTypeScheme valScheme.TypeScheme
+ let lvrefTgt = vrefTgt.Deref
+ if not (isNil generalizedTypars) then
+ // Find all the uses of this recursive binding and use mutation to adjust the expressions
+ // at those points in order to record the inferred type parameters.
+ let recUses = cenv.recUses.Find lvrefTgt
+ recUses
+ |> List.iter (fun (fixupPoint, m, isComplete) ->
+ if not isComplete then
+ // Keep any values for explicit type arguments
+ let fixedUpExpr =
+ let vrefFlags, tyargs0 =
+ match fixupPoint.Value with
+ | Expr.App (Expr.Val (_, vrefFlags, _), _, tyargs0, [], _) -> vrefFlags, tyargs0
+ | Expr.Val (_, vrefFlags, _) -> vrefFlags, []
+ | _ ->
+ errorR(Error(FSComp.SR.tcUnexpectedExprAtRecInfPoint(), m))
+ NormalValUse, []
+
+ let ityargs = generalizeTypars (List.skip (List.length tyargs0) generalizedTypars)
+ primMkApp (Expr.Val (vrefTgt, vrefFlags, m), fty) (tyargs0 @ ityargs) [] m
+ fixupPoint.Value <- fixedUpExpr)
+
+ vrefTgt.Deref.SetValRec ValNotInRecScope
+ cenv.recUses <- cenv.recUses.Remove vrefTgt.Deref
+
+
+/// Set the properties of recursive values that are only fully known after inference is complete
+let AdjustRecType (vspec: Val) (ValScheme(_, typeScheme, topValData, _, _, _, _, _, _, _, _, _)) =
+ let fty = GeneralizedTypeForTypeScheme typeScheme
+ vspec.SetType fty
+ vspec.SetValReprInfo topValData
+ vspec.SetValRec (ValInRecScope true)
+
+/// Record the generated value expression as a place where we will have to
+/// adjust using AdjustAndForgetUsesOfRecValue at a letrec point. Every use of a value
+/// under a letrec gets used at the _same_ type instantiation.
+let RecordUseOfRecValue cenv vrec (vrefTgt: ValRef) vexp m =
+ match vrec with
+ | ValInRecScope isComplete ->
+ let fixupPoint = ref vexp
+ cenv.recUses <- cenv.recUses.Add (vrefTgt.Deref, (fixupPoint, m, isComplete))
+ Expr.Link fixupPoint
+ | ValNotInRecScope ->
+ vexp
+
+type RecursiveUseFixupPoints = RecursiveUseFixupPoints of (Expr ref * range) list
+
+/// Get all recursive references, for fixing up delayed recursion using laziness
+let GetAllUsesOfRecValue cenv vrefTgt =
+ RecursiveUseFixupPoints (cenv.recUses.Find vrefTgt |> List.map (fun (fixupPoint, m, _) -> (fixupPoint, m)))
+
+
+//-------------------------------------------------------------------------
+// Helpers for Generalization
+//-------------------------------------------------------------------------
+
+let ChooseCanonicalDeclaredTyparsAfterInference g denv declaredTypars m =
+ declaredTypars |> List.iter (fun tp ->
+ let ty = mkTyparTy tp
+ if not (isAnyParTy g ty) then
+ error(Error(FSComp.SR.tcLessGenericBecauseOfAnnotation(tp.Name, NicePrint.prettyStringOfTy denv ty), tp.Range)))
+
+ let declaredTypars = NormalizeDeclaredTyparsForEquiRecursiveInference g declaredTypars
+
+ if ListSet.hasDuplicates typarEq declaredTypars then
+ errorR(Error(FSComp.SR.tcConstrainedTypeVariableCannotBeGeneralized(), m))
+
+ declaredTypars
+
+let ChooseCanonicalValSchemeAfterInference g denv vscheme m =
+ let (ValScheme(id, typeScheme, arityInfo, memberInfoOpt, isMutable, inlineFlag, baseOrThis, vis, compgen, isIncrClass, isTyFunc, hasDeclaredTypars)) = vscheme
+ let (TypeScheme(generalizedTypars, ty)) = typeScheme
+ let generalizedTypars = ChooseCanonicalDeclaredTyparsAfterInference g denv generalizedTypars m
+ let typeScheme = TypeScheme(generalizedTypars, ty)
+ let valscheme = ValScheme(id, typeScheme, arityInfo, memberInfoOpt, isMutable, inlineFlag, baseOrThis, vis, compgen, isIncrClass, isTyFunc, hasDeclaredTypars)
+ valscheme
+
+let PlaceTyparsInDeclarationOrder declaredTypars generalizedTypars =
+ declaredTypars @ (generalizedTypars |> List.filter (fun tp -> not (ListSet.contains typarEq tp declaredTypars)))
+
+let SetTyparRigid denv m (tp: Typar) =
+ match tp.Solution with
+ | None -> ()
+ | Some ty ->
+ if tp.IsCompilerGenerated then
+ errorR(Error(FSComp.SR.tcGenericParameterHasBeenConstrained(NicePrint.prettyStringOfTy denv ty), m))
+ else
+ errorR(Error(FSComp.SR.tcTypeParameterHasBeenConstrained(NicePrint.prettyStringOfTy denv ty), tp.Range))
+ tp.SetRigidity TyparRigidity.Rigid
+
+let GeneralizeVal cenv denv enclosingDeclaredTypars generalizedTyparsForThisBinding
+ (PrelimValScheme1(id, explicitTyparInfo, ty, partialValReprInfo, memberInfoOpt, isMutable, inlineFlag, baseOrThis, argAttribs, vis, compgen)) =
+
+ let (ExplicitTyparInfo(_rigidCopyOfDeclaredTypars, declaredTypars, _)) = explicitTyparInfo
+
+ let m = id.idRange
+
+ let allDeclaredTypars = enclosingDeclaredTypars@declaredTypars
+ let allDeclaredTypars = ChooseCanonicalDeclaredTyparsAfterInference cenv.g denv allDeclaredTypars m
+
+ // Trim out anything not in type of the value (as opposed to the type of the r.h.s)
+ // This is important when a single declaration binds
+ // multiple generic items, where each item does not use all the polymorphism
+ // of the r.h.s., e.g. let x, y = None, []
+ let computeRelevantTypars thruFlag =
+ let ftps = freeInTypeLeftToRight cenv.g thruFlag ty
+ let generalizedTypars = generalizedTyparsForThisBinding |> List.filter (fun tp -> ListSet.contains typarEq tp ftps)
+ // Put declared typars first
+ let generalizedTypars = PlaceTyparsInDeclarationOrder allDeclaredTypars generalizedTypars
+ generalizedTypars
+
+ let generalizedTypars = computeRelevantTypars false
+
+ // Check stability of existence and ordering of type parameters under erasure of type abbreviations
+ let generalizedTyparsLookingThroughTypeAbbreviations = computeRelevantTypars true
+ if not (generalizedTypars.Length = generalizedTyparsLookingThroughTypeAbbreviations.Length &&
+ List.forall2 typarEq generalizedTypars generalizedTyparsLookingThroughTypeAbbreviations)
+ then
+ warning(Error(FSComp.SR.tcTypeParametersInferredAreNotStable(), m))
+
+ let hasDeclaredTypars = not (isNil declaredTypars)
+ // This is just about the only place we form a TypeScheme
+ let tyScheme = TypeScheme(generalizedTypars, ty)
+ PrelimValScheme2(id, tyScheme, partialValReprInfo, memberInfoOpt, isMutable, inlineFlag, baseOrThis, argAttribs, vis, compgen, hasDeclaredTypars)
+
+let GeneralizeVals cenv denv enclosingDeclaredTypars generalizedTypars types =
+ NameMap.map (GeneralizeVal cenv denv enclosingDeclaredTypars generalizedTypars) types
+
+let DontGeneralizeVals types =
+ let dontGeneralizeVal (PrelimValScheme1(id, _, ty, partialValReprInfoOpt, memberInfoOpt, isMutable, inlineFlag, baseOrThis, argAttribs, vis, compgen)) =
+ PrelimValScheme2(id, NonGenericTypeScheme ty, partialValReprInfoOpt, memberInfoOpt, isMutable, inlineFlag, baseOrThis, argAttribs, vis, compgen, false)
+ NameMap.map dontGeneralizeVal types
+
+let InferGenericArityFromTyScheme (TypeScheme(generalizedTypars, _)) partialValReprInfo =
+ TranslatePartialArity generalizedTypars partialValReprInfo
+
+let ComputeIsTyFunc(id: Ident, hasDeclaredTypars, arityInfo: ValReprInfo option) =
+ hasDeclaredTypars &&
+ (match arityInfo with
+ | None -> error(Error(FSComp.SR.tcExplicitTypeParameterInvalid(), id.idRange))
+ | Some info -> info.NumCurriedArgs = 0)
+
+let UseSyntacticArity declKind typeScheme partialValReprInfo =
+ if DeclKind.MustHaveArity declKind then
+ Some(InferGenericArityFromTyScheme typeScheme partialValReprInfo)
+ else
+ None
+
+/// Combine the results of InferSynValData and InferArityOfExpr.
+//
+// The F# spec says that we infer arities from declaration forms and types.
+//
+// For example
+// let f (a, b) c = 1 // gets arity [2;1]
+// let f (a: int*int) = 1 // gets arity [2], based on type
+// let f () = 1 // gets arity [0]
+// let f = (fun (x: int) (y: int) -> 1) // gets arity [1;1]
+// let f = (fun (x: int*int) y -> 1) // gets arity [2;1]
+//
+// Some of this arity inference is purely syntax directed and done in InferSynValData in ast.fs
+// Some is done by InferArityOfExpr.
+//
+// However, there are some corner cases in this specification. In particular, consider
+// let f () () = 1 // [0;1] or [0;0]? Answer: [0;1]
+// let f (a: unit) = 1 // [0] or [1]? Answer: [1]
+// let f = (fun () -> 1) // [0] or [1]? Answer: [0]
+// let f = (fun (a: unit) -> 1) // [0] or [1]? Answer: [1]
+//
+// The particular choice of [1] for
+// let f (a: unit) = 1
+// is intended to give a disambiguating form for members that override methods taking a single argument
+// instantiated to type "unit", e.g.
+// type Base<'a> =
+// abstract M: 'a -> unit
+//
+// { new Base with
+// member x.M(v: int) = () }
+//
+// { new Base with
+// member x.M(v: unit) = () }
+//
+let CombineSyntacticAndInferredArities g declKind rhsExpr prelimScheme =
+ let (PrelimValScheme2(_, typeScheme, partialValReprInfoOpt, memberInfoOpt, isMutable, _, _, ArgAndRetAttribs(argAttribs, retAttribs), _, _, _)) = prelimScheme
+ match partialValReprInfoOpt, DeclKind.MustHaveArity declKind with
+ | _, false -> None
+ | None, true -> Some(PartialValReprInfo([], ValReprInfo.unnamedRetVal))
+ // Don't use any expression information for members, where syntax dictates the arity completely
+ | _ when memberInfoOpt.IsSome ->
+ partialValReprInfoOpt
+ | Some partialValReprInfoFromSyntax, true ->
+ let (PartialValReprInfo(curriedArgInfosFromSyntax, retInfoFromSyntax)) = partialValReprInfoFromSyntax
+ let partialArityInfo =
+ if isMutable then
+ PartialValReprInfo ([], retInfoFromSyntax)
+ else
+
+ let (ValReprInfo (_, curriedArgInfosFromExpression, _)) =
+ InferArityOfExpr g AllowTypeDirectedDetupling.Yes (GeneralizedTypeForTypeScheme typeScheme) argAttribs retAttribs rhsExpr
+
+ // Choose between the syntactic arity and the expression-inferred arity
+ // If the syntax specifies an eliminated unit arg, then use that
+ let choose ai1 ai2 =
+ match ai1, ai2 with
+ | [], _ -> []
+ // Dont infer eliminated unit args from the expression if they don't occur syntactically.
+ | ai, [] -> ai
+ // If we infer a tupled argument from the expression and/or type then use that
+ | _ when ai1.Length < ai2.Length -> ai2
+ | _ -> ai1
+ let rec loop ais1 ais2 =
+ match ais1, ais2 with
+ // If the expression infers additional arguments then use those (this shouldn't happen, since the
+ // arity inference done on the syntactic form should give identical results)
+ | [], ais | ais, [] -> ais
+ | (h1 :: t1), (h2 :: t2) -> choose h1 h2 :: loop t1 t2
+ let curriedArgInfos = loop curriedArgInfosFromSyntax curriedArgInfosFromExpression
+ PartialValReprInfo (curriedArgInfos, retInfoFromSyntax)
+
+ Some partialArityInfo
+
+let BuildValScheme declKind partialArityInfoOpt prelimScheme =
+ let (PrelimValScheme2(id, typeScheme, _, memberInfoOpt, isMutable, inlineFlag, baseOrThis, _, vis, compgen, hasDeclaredTypars)) = prelimScheme
+ let topValInfo =
+ if DeclKind.MustHaveArity declKind then
+ Option.map (InferGenericArityFromTyScheme typeScheme) partialArityInfoOpt
+ else
+ None
+ let isTyFunc = ComputeIsTyFunc(id, hasDeclaredTypars, topValInfo)
+ ValScheme(id, typeScheme, topValInfo, memberInfoOpt, isMutable, inlineFlag, baseOrThis, vis, compgen, false, isTyFunc, hasDeclaredTypars)
+
+let UseCombinedArity g declKind rhsExpr prelimScheme =
+ let partialArityInfoOpt = CombineSyntacticAndInferredArities g declKind rhsExpr prelimScheme
+ BuildValScheme declKind partialArityInfoOpt prelimScheme
+
+let UseNoArity prelimScheme =
+ BuildValScheme ExpressionBinding None prelimScheme
+
+/// Make and publish the Val nodes for a collection of simple (non-generic) value specifications
+let MakeAndPublishSimpleVals cenv env names =
+ let tyschemes = DontGeneralizeVals names
+ let valSchemes = NameMap.map UseNoArity tyschemes
+ let values = MakeAndPublishVals cenv env (ParentNone, false, ExpressionBinding, ValNotInRecScope, valSchemes, [], XmlDoc.Empty, None)
+ let vspecMap = NameMap.map fst values
+ values, vspecMap
+
+/// Make and publish the Val nodes for a collection of value specifications at Lambda and Match positions
+///
+/// We merge the additions to the name resolution environment into one using a merged range so all values are brought
+/// into scope simultaneously. The technique used to do this is a disturbing and unfortunate hack that
+/// intercepts `NotifyNameResolution` calls being emitted by `MakeAndPublishSimpleVals`
+
+let MakeAndPublishSimpleValsForMergedScope cenv env m (names: NameMap<_>) =
+ let values, vspecMap =
+ if names.Count <= 1 then
+ MakeAndPublishSimpleVals cenv env names
+ else
+ let nameResolutions = ResizeArray()
+
+ let notifyNameResolution (pos, item, itemGroup, itemTyparInst, occurence, nenv, ad, (m: range), replacing) =
+ if not m.IsSynthetic then
+ nameResolutions.Add(pos, item, itemGroup, itemTyparInst, occurence, nenv, ad, m, replacing)
+
+ let values, vspecMap =
+ let sink =
+ { new ITypecheckResultsSink with
+ member this.NotifyEnvWithScope(_, _, _) = () // ignore EnvWithScope reports
+
+ member this.NotifyNameResolution(pos, item, itemTyparInst, occurence, nenv, ad, m, replacing) =
+ notifyNameResolution (pos, item, item, itemTyparInst, occurence, nenv, ad, m, replacing)
+
+ member this.NotifyMethodGroupNameResolution(pos, item, itemGroup, itemTyparInst, occurence, nenv, ad, m, replacing) =
+ notifyNameResolution (pos, item, itemGroup, itemTyparInst, occurence, nenv, ad, m, replacing)
+
+ member this.NotifyExprHasType(_, _, _, _) = assert false // no expr typings in MakeAndPublishSimpleVals
+ member this.NotifyFormatSpecifierLocation(_, _) = ()
+ member this.NotifyOpenDeclaration(_) = ()
+ member this.CurrentSourceText = None
+ member this.FormatStringCheckContext = None }
+
+ use _h = WithNewTypecheckResultsSink(sink, cenv.tcSink)
+ MakeAndPublishSimpleVals cenv env names
+
+ if nameResolutions.Count <> 0 then
+ let (_, _, _, _, _, _, ad, m1, _replacing) = nameResolutions.[0]
+ // mergedNameEnv - name resolution env that contains all names
+ // mergedRange - union of ranges of names
+ let mergedNameEnv, mergedRange =
+ ((env.NameEnv, m1), nameResolutions) ||> Seq.fold (fun (nenv, merged) (_, item, _, _, _, _, _, m, _) ->
+ // MakeAndPublishVal creates only Item.Value
+ let item = match item with Item.Value item -> item | _ -> failwith "impossible"
+ (AddFakeNamedValRefToNameEnv item.DisplayName nenv item), (unionRanges m merged)
+ )
+ // send notification about mergedNameEnv
+ CallEnvSink cenv.tcSink (mergedRange, mergedNameEnv, ad)
+ // call CallNameResolutionSink for all captured name resolutions using mergedNameEnv
+ for (_, item, itemGroup, itemTyparInst, occurence, _nenv, ad, m, _replacing) in nameResolutions do
+ CallMethodGroupNameResolutionSink cenv.tcSink (m, mergedNameEnv, item, itemGroup, itemTyparInst, occurence, ad)
+
+ values, vspecMap
+
+ let envinner = AddLocalValMap cenv.tcSink m vspecMap env
+ envinner, values, vspecMap
+
+//-------------------------------------------------------------------------
+// Helpers to freshen existing types and values, i.e. when a reference
+// to C<_> occurs then generate C for a fresh type inference variable ?ty.
+//-------------------------------------------------------------------------
+
+let FreshenTyconRef m rigid (tcref: TyconRef) declaredTyconTypars =
+ let tpsorig = declaredTyconTypars
+ let tps = copyTypars tpsorig
+ if rigid <> TyparRigidity.Rigid then
+ tps |> List.iter (fun tp -> tp.SetRigidity rigid)
+
+ let renaming, tinst = FixupNewTypars m [] [] tpsorig tps
+ (TType_app(tcref, List.map mkTyparTy tpsorig), tps, renaming, TType_app(tcref, tinst))
+
+let FreshenPossibleForallTy g m rigid ty =
+ let tpsorig, tau = tryDestForallTy g ty
+ if isNil tpsorig then
+ [], [], [], tau
+ else
+ // tps may be have been equated to other tps in equi-recursive type inference and units-of-measure type inference. Normalize them here
+ let tpsorig = NormalizeDeclaredTyparsForEquiRecursiveInference g tpsorig
+ let tps, renaming, tinst = CopyAndFixupTypars m rigid tpsorig
+ tpsorig, tps, tinst, instType renaming tau
+
+let FreshenTyconRef2 m (tcref: TyconRef) =
+ let tps, renaming, tinst = FreshenTypeInst m (tcref.Typars m)
+ tps, renaming, tinst, TType_app (tcref, tinst)
+
+
+/// Given a abstract method, which may be a generic method, freshen the type in preparation
+/// to apply it as a constraint to the method that implements the abstract slot
+let FreshenAbstractSlot g amap m synTyparDecls absMethInfo =
+
+ // Work out if an explicit instantiation has been given. If so then the explicit type
+ // parameters will be made rigid and checked for generalization. If not then auto-generalize
+ // by making the copy of the type parameters on the virtual being overridden rigid.
+
+ let typarsFromAbsSlotAreRigid =
+
+ match synTyparDecls with
+ | SynValTyparDecls(synTypars, infer, _) ->
+ if infer && not (isNil synTypars) then
+ errorR(Error(FSComp.SR.tcOverridingMethodRequiresAllOrNoTypeParameters(), m))
+
+ isNil synTypars
+
+ let (CompiledSig (argTys, retTy, fmtps, _)) = CompiledSigOfMeth g amap m absMethInfo
+
+ // If the virtual method is a generic method then copy its type parameters
+ let typarsFromAbsSlot, typarInstFromAbsSlot, _ =
+ let ttps = absMethInfo.GetFormalTyparsOfDeclaringType m
+ let ttinst = argsOfAppTy g absMethInfo.ApparentEnclosingType
+ let rigid = if typarsFromAbsSlotAreRigid then TyparRigidity.Rigid else TyparRigidity.Flexible
+ ConstraintSolver.FreshenAndFixupTypars m rigid ttps ttinst fmtps
+
+ // Work out the required type of the member
+ let argTysFromAbsSlot = argTys |> List.mapSquared (instType typarInstFromAbsSlot)
+ let retTyFromAbsSlot = retTy |> GetFSharpViewOfReturnType g |> instType typarInstFromAbsSlot
+ typarsFromAbsSlotAreRigid, typarsFromAbsSlot, argTysFromAbsSlot, retTyFromAbsSlot
+
+
+//-------------------------------------------------------------------------
+// Helpers to typecheck expressions and patterns
+//-------------------------------------------------------------------------
+
+let BuildFieldMap cenv env isPartial ty flds m =
+ let ad = env.eAccessRights
+ if isNil flds then invalidArg "flds" "BuildFieldMap"
+ let fldCount = flds.Length
+
+ let frefSets =
+ let allFields = flds |> List.map (fun ((_, ident), _) -> ident)
+ flds
+ |> List.map (fun (fld, fldExpr) ->
+ let frefSet = ResolveField cenv.tcSink cenv.nameResolver env.eNameResEnv ad ty fld allFields
+ fld, frefSet, fldExpr)
+
+ let relevantTypeSets =
+ frefSets |> List.map (fun (_, frefSet, _) -> frefSet |> List.map (fun (FieldResolution(rfinfo, _)) -> rfinfo.TypeInst, rfinfo.TyconRef))
+
+ let tinst, tcref =
+ match List.fold (ListSet.intersect (fun (_, tcref1) (_, tcref2) -> tyconRefEq cenv.g tcref1 tcref2)) (List.head relevantTypeSets) (List.tail relevantTypeSets) with
+ | [tinst, tcref] -> tinst, tcref
+ | tcrefs ->
+ if isPartial then
+ warning (Error(FSComp.SR.tcFieldsDoNotDetermineUniqueRecordType(), m))
+
+ // try finding a record type with the same number of fields as the ones that are given.
+ match tcrefs |> List.tryFind (fun (_, tc) -> tc.TrueFieldsAsList.Length = fldCount) with
+ | Some (tinst, tcref) -> tinst, tcref
+ | _ ->
+ // OK, there isn't a unique, good type dictated by the intersection for the field refs.
+ // We're going to get an error of some kind below.
+ // Just choose one field ref and let the error come later
+ let (_, frefSet1, _) = List.head frefSets
+ let (FieldResolution(rfinfo1, _)) = List.head frefSet1
+ rfinfo1.TypeInst, rfinfo1.TyconRef
+
+ let fldsmap, rfldsList =
+ ((Map.empty, []), frefSets) ||> List.fold (fun (fs, rfldsList) (fld, frefs, fldExpr) ->
+ match frefs |> List.filter (fun (FieldResolution(rfinfo2, _)) -> tyconRefEq cenv.g tcref rfinfo2.TyconRef) with
+ | [FieldResolution(rfinfo2, showDeprecated)] ->
+
+ // Record the precise resolution of the field for intellisense
+ let item = Item.RecdField(rfinfo2)
+ CallNameResolutionSink cenv.tcSink ((snd fld).idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, ad)
+
+ let fref2 = rfinfo2.RecdFieldRef
+ CheckRecdFieldAccessible cenv.amap m env.eAccessRights fref2 |> ignore
+ CheckFSharpAttributes cenv.g fref2.PropertyAttribs m |> CommitOperationResult
+ if Map.containsKey fref2.FieldName fs then
+ errorR (Error(FSComp.SR.tcFieldAppearsTwiceInRecord(fref2.FieldName), m))
+ if showDeprecated then
+ warning(Deprecated(FSComp.SR.nrRecordTypeNeedsQualifiedAccess(fref2.FieldName, fref2.Tycon.DisplayName) |> snd, m))
+
+ if not (tyconRefEq cenv.g tcref fref2.TyconRef) then
+ let (_, frefSet1, _) = List.head frefSets
+ let (FieldResolution(rfinfo1, _)) = List.head frefSet1
+ errorR (FieldsFromDifferentTypes(env.DisplayEnv, rfinfo1.RecdFieldRef, fref2, m))
+ fs, rfldsList
+ else
+ Map.add fref2.FieldName fldExpr fs, (fref2.FieldName, fldExpr) :: rfldsList
+
+ | _ -> error(Error(FSComp.SR.tcRecordFieldInconsistentTypes(), m)))
+ tinst, tcref, fldsmap, List.rev rfldsList
+
+let rec ApplyUnionCaseOrExn (makerForUnionCase, makerForExnTag) m cenv env overallTy item =
+ let ad = env.eAccessRights
+ match item with
+ | Item.ExnCase ecref ->
+ CheckEntityAttributes cenv.g ecref m |> CommitOperationResult
+ UnifyTypes cenv env m overallTy cenv.g.exn_ty
+ CheckTyconAccessible cenv.amap m ad ecref |> ignore
+ let mkf = makerForExnTag ecref
+ mkf, recdFieldTysOfExnDefRef ecref, [ for f in (recdFieldsOfExnDefRef ecref) -> f.Id ]
+
+ | Item.UnionCase(ucinfo, showDeprecated) ->
+ if showDeprecated then
+ warning(Deprecated(FSComp.SR.nrUnionTypeNeedsQualifiedAccess(ucinfo.Name, ucinfo.Tycon.DisplayName) |> snd, m))
+
+ let ucref = ucinfo.UnionCaseRef
+ CheckUnionCaseAttributes cenv.g ucref m |> CommitOperationResult
+ CheckUnionCaseAccessible cenv.amap m ad ucref |> ignore
+ let gtyp2 = actualResultTyOfUnionCase ucinfo.TypeInst ucref
+ let inst = mkTyparInst ucref.TyconRef.TyparsNoRange ucinfo.TypeInst
+ UnifyTypes cenv env m overallTy gtyp2
+ let mkf = makerForUnionCase(ucref, ucinfo.TypeInst)
+ mkf, actualTysOfUnionCaseFields inst ucref, [ for f in ucref.AllFieldsAsList -> f.Id ]
+ | _ -> invalidArg "item" "not a union case or exception reference"
+
+let ApplyUnionCaseOrExnTypes m cenv env overallTy c =
+ ApplyUnionCaseOrExn ((fun (a, b) mArgs args -> mkUnionCaseExpr(a, b, args, unionRanges m mArgs)),
+ (fun a mArgs args -> mkExnExpr (a, args, unionRanges m mArgs))) m cenv env overallTy c
+
+let ApplyUnionCaseOrExnTypesForPat m cenv env overallTy c =
+ ApplyUnionCaseOrExn ((fun (a, b) mArgs args -> TPat_unioncase(a, b, args, unionRanges m mArgs)),
+ (fun a mArgs args -> TPat_exnconstr(a, args, unionRanges m mArgs))) m cenv env overallTy c
+
+let UnionCaseOrExnCheck (env: TcEnv) numArgTys numArgs m =
+ if numArgs <> numArgTys then error (UnionCaseWrongArguments(env.DisplayEnv, numArgTys, numArgs, m))
+
+let TcUnionCaseOrExnField cenv (env: TcEnv) ty1 m c n funcs =
+ let ad = env.eAccessRights
+ let mkf, argTys, _argNames =
+ match ResolvePatternLongIdent cenv.tcSink cenv.nameResolver AllIdsOK false m ad env.eNameResEnv TypeNameResolutionInfo.Default c with
+ | (Item.UnionCase _ | Item.ExnCase _) as item ->
+ ApplyUnionCaseOrExn funcs m cenv env ty1 item
+ | _ -> error(Error(FSComp.SR.tcUnknownUnion(), m))
+ let argstysLength = List.length argTys
+ if n >= argstysLength then
+ error (UnionCaseWrongNumberOfArgs(env.DisplayEnv, argstysLength, n, m))
+ let ty2 = List.item n argTys
+ mkf, ty2
+
+//-------------------------------------------------------------------------
+// Helpers for generalizing type variables
+//-------------------------------------------------------------------------
+
+type GeneralizeConstrainedTyparOptions =
+ | CanGeneralizeConstrainedTypars
+ | DoNotGeneralizeConstrainedTypars
+
+
+module GeneralizationHelpers =
+ let ComputeUngeneralizableTypars env =
+
+ let acc = Collections.Generic.List()
+ for item in env.eUngeneralizableItems do
+ if not item.WillNeverHaveFreeTypars then
+ let ftps = item.GetFreeTyvars().FreeTypars
+ if not ftps.IsEmpty then
+ for ftp in ftps do
+ acc.Add ftp
+
+ Zset.Create(typarOrder, acc)
+
+
+ let ComputeUnabstractableTycons env =
+ let accInFreeItem acc (item: UngeneralizableItem) =
+ let ftycs =
+ if item.WillNeverHaveFreeTypars then item.CachedFreeLocalTycons else
+ let ftyvs = item.GetFreeTyvars()
+ ftyvs.FreeTycons
+ if ftycs.IsEmpty then acc else unionFreeTycons ftycs acc
+
+ List.fold accInFreeItem emptyFreeTycons env.eUngeneralizableItems
+
+ let ComputeUnabstractableTraitSolutions env =
+ let accInFreeItem acc (item: UngeneralizableItem) =
+ let ftycs =
+ if item.WillNeverHaveFreeTypars then item.CachedFreeTraitSolutions else
+ let ftyvs = item.GetFreeTyvars()
+ ftyvs.FreeTraitSolutions
+ if ftycs.IsEmpty then acc else unionFreeLocals ftycs acc
+
+ List.fold accInFreeItem emptyFreeLocals env.eUngeneralizableItems
+
+ let rec IsGeneralizableValue g t =
+ match t with
+ | Expr.Lambda _ | Expr.TyLambda _ | Expr.Const _ -> true
+
+ // let f(x: byref) = let v = &x in ... shouldn't generalize "v"
+ | Expr.Val (vref, _, m) -> not (isByrefLikeTy g m vref.Type)
+
+ // Look through coercion nodes corresponding to introduction of subsumption
+ | Expr.Op (TOp.Coerce, [inputTy;actualTy], [e1], _) when isFunTy g actualTy && isFunTy g inputTy ->
+ IsGeneralizableValue g e1
+
+ | Expr.Op (op, _, args, _) ->
+
+ let canGeneralizeOp =
+ match op with
+ | TOp.Tuple _ -> true
+ | TOp.UnionCase uc -> not (isUnionCaseRefDefinitelyMutable uc)
+ | TOp.Recd (ctorInfo, tcref) ->
+ match ctorInfo with
+ | RecdExpr -> not (isRecdOrUnionOrStructTyconRefDefinitelyMutable tcref)
+ | RecdExprIsObjInit -> false
+ | TOp.Array -> isNil args
+ | TOp.ExnConstr ec -> not (isExnDefinitelyMutable ec)
+ | TOp.ILAsm ([], _) -> true
+ | _ -> false
+
+ canGeneralizeOp && List.forall (IsGeneralizableValue g) args
+
+ | Expr.LetRec (binds, body, _, _) ->
+ binds |> List.forall (fun b -> not b.Var.IsMutable) &&
+ binds |> List.forall (fun b -> IsGeneralizableValue g b.Expr) &&
+ IsGeneralizableValue g body
+
+ | Expr.Let (bind, body, _, _) ->
+ not bind.Var.IsMutable &&
+ IsGeneralizableValue g bind.Expr &&
+ IsGeneralizableValue g body
+
+ // Applications of type functions are _not_ normally generalizable unless explicitly marked so
+ | Expr.App (Expr.Val (vref, _, _), _, _, [], _) when vref.IsTypeFunction ->
+ HasFSharpAttribute g g.attrib_GeneralizableValueAttribute vref.Attribs
+
+ | Expr.App (e1, _, _, [], _) -> IsGeneralizableValue g e1
+ | Expr.TyChoose (_, b, _) -> IsGeneralizableValue g b
+ | Expr.Obj (_, ty, _, _, _, _, _) -> isInterfaceTy g ty || isDelegateTy g ty
+ | Expr.Link eref -> IsGeneralizableValue g !eref
+
+ | _ -> false
+
+ let CanGeneralizeConstrainedTyparsForDecl declKind =
+ if DeclKind.CanGeneralizeConstrainedTypars declKind
+ then CanGeneralizeConstrainedTypars
+ else DoNotGeneralizeConstrainedTypars
+
+ /// Recursively knock out typars we can't generalize.
+ /// For non-generalized type variables be careful to iteratively knock out
+ /// both the typars and any typars free in the constraints of the typars
+ /// into the set that are considered free in the environment.
+ let rec TrimUngeneralizableTypars genConstrainedTyparFlag inlineFlag (generalizedTypars: Typar list) freeInEnv =
+ // Do not generalize type variables with a static requirement unless function is marked 'inline'
+ let generalizedTypars, ungeneralizableTypars1 =
+ if inlineFlag = ValInline.PseudoVal then generalizedTypars, []
+ else generalizedTypars |> List.partition (fun tp -> tp.StaticReq = NoStaticReq)
+
+ // Do not generalize type variables which would escape their scope
+ // because they are free in the environment
+ let generalizedTypars, ungeneralizableTypars2 =
+ List.partition (fun x -> not (Zset.contains x freeInEnv)) generalizedTypars
+
+ // Some situations, e.g. implicit class constructions that represent functions as fields,
+ // do not allow generalisation over constrained typars. (since they can not be represented as fields)
+ //
+ // Don't generalize IsCompatFlex type parameters to avoid changing inferred types.
+ let generalizedTypars, ungeneralizableTypars3 =
+ generalizedTypars
+ |> List.partition (fun tp ->
+ (genConstrainedTyparFlag = CanGeneralizeConstrainedTypars || tp.Constraints.IsEmpty) &&
+ not tp.IsCompatFlex)
+
+ if isNil ungeneralizableTypars1 && isNil ungeneralizableTypars2 && isNil ungeneralizableTypars3 then
+ generalizedTypars, freeInEnv
+ else
+ let freeInEnv =
+ unionFreeTypars
+ (accFreeInTypars CollectAllNoCaching ungeneralizableTypars1
+ (accFreeInTypars CollectAllNoCaching ungeneralizableTypars2
+ (accFreeInTypars CollectAllNoCaching ungeneralizableTypars3 emptyFreeTyvars))).FreeTypars
+ freeInEnv
+ TrimUngeneralizableTypars genConstrainedTyparFlag inlineFlag generalizedTypars freeInEnv
+
+ /// Condense type variables in positive position
+ let CondenseTypars (cenv, denv: DisplayEnv, generalizedTypars: Typars, tauTy, m) =
+
+ // The type of the value is ty11 * ... * ty1N -> ... -> tyM1 * ... * tyMM -> retTy
+ // This is computed REGARDLESS of the arity of the expression.
+ let curriedArgTys, retTy = stripFunTy cenv.g tauTy
+ let allUntupledArgTys = curriedArgTys |> List.collect (tryDestRefTupleTy cenv.g)
+
+ // Compute the type variables in 'retTy'
+ let returnTypeFreeTypars = freeInTypeLeftToRight cenv.g false retTy
+ let allUntupledArgTysWithFreeVars = allUntupledArgTys |> List.map (fun ty -> (ty, freeInTypeLeftToRight cenv.g false ty))
+
+ let relevantUniqueSubtypeConstraint (tp: Typar) =
+ // Find a single subtype constraint
+ match tp.Constraints |> List.partition (function (TyparConstraint.CoercesTo _) -> true | _ -> false) with
+ | [TyparConstraint.CoercesTo(cxty, _)], others ->
+ // Throw away null constraints if they are implied
+ if others |> List.exists (function (TyparConstraint.SupportsNull(_)) -> not (TypeSatisfiesNullConstraint cenv.g m cxty) | _ -> true)
+ then None
+ else Some cxty
+ | _ -> None
+
+
+ // Condensation typars can't be used in the constraints of any candidate condensation typars. So compute all the
+ // typars free in the constraints of tyIJ
+
+ let lhsConstraintTypars =
+ allUntupledArgTys |> List.collect (fun ty ->
+ match tryDestTyparTy cenv.g ty with
+ | ValueSome tp ->
+ match relevantUniqueSubtypeConstraint tp with
+ | Some cxty -> freeInTypeLeftToRight cenv.g false cxty
+ | None -> []
+ | _ -> [])
+
+ let IsCondensationTypar (tp: Typar) =
+ // A condensation typar may not a user-generated type variable nor has it been unified with any user type variable
+ (tp.DynamicReq = TyparDynamicReq.No) &&
+ // A condensation typar must have a single constraint "'a :> A"
+ (Option.isSome (relevantUniqueSubtypeConstraint tp)) &&
+ // This is type variable is not used on the r.h.s. of the type
+ not (ListSet.contains typarEq tp returnTypeFreeTypars) &&
+ // A condensation typar can't be used in the constraints of any candidate condensation typars
+ not (ListSet.contains typarEq tp lhsConstraintTypars) &&
+ // A condensation typar must occur precisely once in tyIJ, and must not occur free in any other tyIJ
+ (match allUntupledArgTysWithFreeVars |> List.partition (fun (ty, _) -> match tryDestTyparTy cenv.g ty with ValueSome destTypar -> typarEq destTypar tp | _ -> false) with
+ | [_], rest -> not (rest |> List.exists (fun (_, fvs) -> ListSet.contains typarEq tp fvs))
+ | _ -> false)
+
+ let condensationTypars, generalizedTypars = generalizedTypars |> List.partition IsCondensationTypar
+
+ // Condensation solves type variables eagerly and removes them from the generalization set
+ condensationTypars |> List.iter (fun tp ->
+ ConstraintSolver.ChooseTyparSolutionAndSolve cenv.css denv tp)
+ generalizedTypars
+
+ let ComputeAndGeneralizeGenericTypars (cenv,
+ denv: DisplayEnv,
+ m,
+ freeInEnv: FreeTypars,
+ canInferTypars,
+ genConstrainedTyparFlag,
+ inlineFlag,
+ exprOpt,
+ allDeclaredTypars: Typars,
+ maxInferredTypars: Typars,
+ tauTy,
+ resultFirst) =
+
+ let allDeclaredTypars = NormalizeDeclaredTyparsForEquiRecursiveInference cenv.g allDeclaredTypars
+ let typarsToAttemptToGeneralize =
+ if (match exprOpt with None -> true | Some e -> IsGeneralizableValue cenv.g e)
+ then (ListSet.unionFavourLeft typarEq allDeclaredTypars maxInferredTypars)
+ else allDeclaredTypars
+
+ let generalizedTypars, freeInEnv =
+ TrimUngeneralizableTypars genConstrainedTyparFlag inlineFlag typarsToAttemptToGeneralize freeInEnv
+
+ allDeclaredTypars
+ |> List.iter (fun tp ->
+ if Zset.memberOf freeInEnv tp then
+ let ty = mkTyparTy tp
+ error(Error(FSComp.SR.tcNotSufficientlyGenericBecauseOfScope(NicePrint.prettyStringOfTy denv ty), m)))
+
+ let generalizedTypars = CondenseTypars(cenv, denv, generalizedTypars, tauTy, m)
+
+ let generalizedTypars =
+ if canInferTypars then generalizedTypars
+ else generalizedTypars |> List.filter (fun tp -> ListSet.contains typarEq tp allDeclaredTypars)
+
+ let allConstraints = List.collect (fun (tp: Typar) -> tp.Constraints) generalizedTypars
+ let generalizedTypars = ConstraintSolver.SimplifyMeasuresInTypeScheme cenv.g resultFirst generalizedTypars tauTy allConstraints
+
+ // Generalization turns inference type variables into rigid, quantified type variables,
+ // (they may be rigid already)
+ generalizedTypars |> List.iter (SetTyparRigid denv m)
+
+ // Generalization removes constraints related to generalized type variables
+ EliminateConstraintsForGeneralizedTypars denv cenv.css m NoTrace generalizedTypars
+
+ generalizedTypars
+
+ //-------------------------------------------------------------------------
+ // Helpers to freshen existing types and values, i.e. when a reference
+ // to C<_> occurs then generate C for a fresh type inference variable ?ty.
+ //-------------------------------------------------------------------------
+
+ let CheckDeclaredTyparsPermitted (memFlagsOpt, declaredTypars, m) =
+ match memFlagsOpt with
+ | None -> ()
+ | Some memberFlags ->
+ match memberFlags.MemberKind with
+ // can't infer extra polymorphism for properties
+ | MemberKind.PropertyGet
+ | MemberKind.PropertySet ->
+ if not (isNil declaredTypars) then
+ errorR(Error(FSComp.SR.tcPropertyRequiresExplicitTypeParameters(), m))
+ | MemberKind.Constructor ->
+ if not (isNil declaredTypars) then
+ errorR(Error(FSComp.SR.tcConstructorCannotHaveTypeParameters(), m))
+ | _ -> ()
+
+ /// Properties and Constructors may only generalize the variables associated with the containing class (retrieved from the 'this' pointer)
+ /// Also check they don't declare explicit typars.
+ let ComputeCanInferExtraGeneralizableTypars (parentRef, canInferTypars, memFlagsOpt) =
+ canInferTypars &&
+ (match memFlagsOpt with
+ | None -> true
+ | Some memberFlags ->
+ match memberFlags.MemberKind with
+ // can't infer extra polymorphism for properties
+ | MemberKind.PropertyGet | MemberKind.PropertySet -> false
+ // can't infer extra polymorphism for class constructors
+ | MemberKind.ClassConstructor -> false
+ // can't infer extra polymorphism for constructors
+ | MemberKind.Constructor -> false
+ // feasible to infer extra polymorphism
+ | _ -> true) &&
+ (match parentRef with
+ | Parent tcref -> not tcref.IsFSharpDelegateTycon
+ | _ -> true) // no generic parameters inferred for 'Invoke' method
+
+
+
+//-------------------------------------------------------------------------
+// ComputeInlineFlag
+//-------------------------------------------------------------------------
+
+let ComputeInlineFlag memFlagsOption isInline isMutable m =
+ let inlineFlag =
+ // Mutable values may never be inlined
+ // Constructors may never be inlined
+ // Calls to virtual/abstract slots may never be inlined
+ if isMutable ||
+ (match memFlagsOption with
+ | None -> false
+ | Some x -> (x.MemberKind = MemberKind.Constructor) || x.IsDispatchSlot || x.IsOverrideOrExplicitImpl)
+ then ValInline.Never
+ elif isInline then ValInline.PseudoVal
+ else ValInline.Optional
+ if isInline && (inlineFlag <> ValInline.PseudoVal) then
+ errorR(Error(FSComp.SR.tcThisValueMayNotBeInlined(), m))
+ inlineFlag
+
+
+//-------------------------------------------------------------------------
+// Binding normalization.
+//
+// Determine what sort of value is being bound (normal value, instance
+// member, normal function, static member etc.) and make some
+// name-resolution-sensitive adjustments to the syntax tree.
+//
+// One part of this "normalization" ensures:
+// "let SynPat.LongIdent(f) = e" when f not a datatype constructor --> let Pat_var(f) = e"
+// "let SynPat.LongIdent(f) pat = e" when f not a datatype constructor --> let Pat_var(f) = \pat. e"
+// "let (SynPat.LongIdent(f) : ty) = e" when f not a datatype constructor --> let (Pat_var(f) : ty) = e"
+// "let (SynPat.LongIdent(f) : ty) pat = e" when f not a datatype constructor --> let (Pat_var(f) : ty) = \pat. e"
+//
+// This is because the first lambda in a function definition "let F x = e"
+// now looks like a constructor application, i.e. let (F x) = e ...
+// also let A.F x = e ...
+// also let f x = e ...
+//
+// The other parts turn property definitions into method definitions.
+//-------------------------------------------------------------------------
+
+
+// NormalizedBindingRhs records the r.h.s. of a binding after some munging just before type checking.
+// NOTE: This is a bit of a mess. In the early implementation of F# we decided
+// to have the parser convert "let f x = e" into
+// "let f = fun x -> e". This is called "pushing" a pattern across to the right hand side. Complex
+// patterns (e.g. non-tuple patterns) result in a computation on the right.
+// However, this approach really isn't that great - especially since
+// the language is now considerably more complex, e.g. we use
+// type information from the first (but not the second) form in
+// type inference for recursive bindings, and the first form
+// may specify .NET attributes for arguments. There are still many
+// relics of this approach around, e.g. the expression in BindingRhs
+// below is of the second form. However, to extract relevant information
+// we keep a record of the pats and optional explicit return type already pushed
+// into expression so we can use any user-given type information from these
+type NormalizedBindingRhs =
+ | NormalizedBindingRhs of
+ simplePats: SynSimplePats list *
+ returnTyOpt: SynBindingReturnInfo option *
+ rhsExpr: SynExpr
+
+let PushOnePatternToRhs (cenv: cenv) isMember p (NormalizedBindingRhs(spatsL, rtyOpt, rhsExpr)) =
+ let spats, rhsExpr = PushPatternToExpr cenv.synArgNameGenerator isMember p rhsExpr
+ NormalizedBindingRhs(spats :: spatsL, rtyOpt, rhsExpr)
+
+type NormalizedBindingPatternInfo =
+ NormalizedBindingPat of SynPat * NormalizedBindingRhs * SynValData * SynValTyparDecls
+
+/// Represents a syntactic, unchecked binding after the resolution of the name resolution status of pattern
+/// constructors and after "pushing" all complex patterns to the right hand side.
+type NormalizedBinding =
+ | NormalizedBinding of
+ visibility: SynAccess option *
+ kind: SynBindingKind *
+ mustInline: bool *
+ isMutable: bool *
+ attribs: SynAttribute list *
+ xmlDoc: XmlDoc *
+ typars: SynValTyparDecls *
+ valSynData: SynValData *
+ pat: SynPat *
+ rhsExpr: NormalizedBindingRhs *
+ mBinding: range *
+ spBinding: DebugPointForBinding
+
+type IsObjExprBinding =
+ | ObjExprBinding
+ | ValOrMemberBinding
+
+module BindingNormalization =
+ /// Push a bunch of pats at once. They may contain patterns, e.g. let f (A x) (B y) = ...
+ /// In this case the semantics is let f a b = let A x = a in let B y = b
+ let private PushMultiplePatternsToRhs (cenv: cenv) isMember ps (NormalizedBindingRhs(spatsL, rtyOpt, rhsExpr)) =
+ let spatsL2, rhsExpr = PushCurriedPatternsToExpr cenv.synArgNameGenerator rhsExpr.Range isMember ps rhsExpr
+ NormalizedBindingRhs(spatsL2@spatsL, rtyOpt, rhsExpr)
+
+
+ let private MakeNormalizedStaticOrValBinding cenv isObjExprBinding id vis typars args rhsExpr valSynData =
+ let (SynValData(memberFlagsOpt, _, _)) = valSynData
+ NormalizedBindingPat(mkSynPatVar vis id, PushMultiplePatternsToRhs cenv ((isObjExprBinding = ObjExprBinding) || Option.isSome memberFlagsOpt) args rhsExpr, valSynData, typars)
+
+ let private MakeNormalizedInstanceMemberBinding cenv thisId memberId toolId vis m typars args rhsExpr valSynData =
+ NormalizedBindingPat(SynPat.InstanceMember(thisId, memberId, toolId, vis, m), PushMultiplePatternsToRhs cenv true args rhsExpr, valSynData, typars)
+
+ let private NormalizeStaticMemberBinding cenv memberFlags valSynData id vis typars args m rhsExpr =
+ let (SynValData(_, valSynInfo, thisIdOpt)) = valSynData
+ if memberFlags.IsInstance then
+ // instance method without adhoc "this" argument
+ error(Error(FSComp.SR.tcInstanceMemberRequiresTarget(), m))
+ match args, memberFlags.MemberKind with
+ | _, MemberKind.PropertyGetSet -> error(Error(FSComp.SR.tcUnexpectedPropertyInSyntaxTree(), m))
+ | [], MemberKind.ClassConstructor -> error(Error(FSComp.SR.tcStaticInitializerRequiresArgument(), m))
+ | [], MemberKind.Constructor -> error(Error(FSComp.SR.tcObjectConstructorRequiresArgument(), m))
+ | [_], MemberKind.ClassConstructor
+ | [_], MemberKind.Constructor -> MakeNormalizedStaticOrValBinding cenv ValOrMemberBinding id vis typars args rhsExpr valSynData
+ // Static property declared using 'static member P = expr': transformed to a method taking a "unit" argument
+ // static property: these transformed into methods taking one "unit" argument
+ | [], MemberKind.Member ->
+ let memberFlags = {memberFlags with MemberKind = MemberKind.PropertyGet}
+ let valSynData = SynValData(Some memberFlags, valSynInfo, thisIdOpt)
+ NormalizedBindingPat(mkSynPatVar vis id,
+ PushOnePatternToRhs cenv true (SynPat.Const(SynConst.Unit, m)) rhsExpr,
+ valSynData,
+ typars)
+ | _ -> MakeNormalizedStaticOrValBinding cenv ValOrMemberBinding id vis typars args rhsExpr valSynData
+
+ let private NormalizeInstanceMemberBinding cenv memberFlags valSynData thisId memberId (toolId: Ident option) vis typars args m rhsExpr =
+ let (SynValData(_, valSynInfo, thisIdOpt)) = valSynData
+ if not memberFlags.IsInstance then
+ // static method with adhoc "this" argument
+ error(Error(FSComp.SR.tcStaticMemberShouldNotHaveThis(), m))
+ match args, memberFlags.MemberKind with
+ | _, MemberKind.ClassConstructor -> error(Error(FSComp.SR.tcExplicitStaticInitializerSyntax(), m))
+ | _, MemberKind.Constructor -> error(Error(FSComp.SR.tcExplicitObjectConstructorSyntax(), m))
+ | _, MemberKind.PropertyGetSet -> error(Error(FSComp.SR.tcUnexpectedPropertySpec(), m))
+ // Instance property declared using 'x.Member': transformed to methods taking a "this" and a "unit" argument
+ // We push across the 'this' arg in mk_rec_binds
+ | [], MemberKind.Member ->
+ let memberFlags = {memberFlags with MemberKind = MemberKind.PropertyGet}
+ NormalizedBindingPat
+ (SynPat.InstanceMember(thisId, memberId, toolId, vis, m),
+ PushOnePatternToRhs cenv true (SynPat.Const(SynConst.Unit, m)) rhsExpr,
+ // Update the member info to record that this is a MemberKind.PropertyGet
+ SynValData(Some memberFlags, valSynInfo, thisIdOpt),
+ typars)
+
+ | _ -> MakeNormalizedInstanceMemberBinding cenv thisId memberId toolId vis m typars args rhsExpr valSynData
+
+ let private NormalizeBindingPattern cenv nameResolver isObjExprBinding (env: TcEnv) valSynData pat rhsExpr =
+ let ad = env.AccessRights
+ let (SynValData(memberFlagsOpt, _, _)) = valSynData
+ let rec normPattern pat =
+ // One major problem with versions of F# prior to 1.9.x was that data constructors easily 'pollute' the namespace
+ // of available items, to the point that you can't even define a function with the same name as an existing union case.
+ match pat with
+ | SynPat.FromParseError(p, _) -> normPattern p
+ | SynPat.LongIdent (LongIdentWithDots(longId, _), toolId, tyargs, SynArgPats.Pats args, vis, m) ->
+ let typars = match tyargs with None -> inferredTyparDecls | Some typars -> typars
+ match memberFlagsOpt with
+ | None ->
+ match ResolvePatternLongIdent cenv.tcSink nameResolver AllIdsOK true m ad env.NameEnv TypeNameResolutionInfo.Default longId with
+ | Item.NewDef id ->
+ if id.idText = opNameCons then
+ NormalizedBindingPat(pat, rhsExpr, valSynData, typars)
+ else
+ if isObjExprBinding = ObjExprBinding then
+ errorR(Deprecated(FSComp.SR.tcObjectExpressionFormDeprecated(), m))
+ MakeNormalizedStaticOrValBinding cenv isObjExprBinding id vis typars args rhsExpr valSynData
+ | _ ->
+ error(Error(FSComp.SR.tcInvalidDeclaration(), m))
+
+ | Some memberFlags ->
+ match longId with
+ // x.Member in member binding patterns.
+ | [thisId;memberId] -> NormalizeInstanceMemberBinding cenv memberFlags valSynData thisId memberId toolId vis typars args m rhsExpr
+ | [memberId] -> NormalizeStaticMemberBinding cenv memberFlags valSynData memberId vis typars args m rhsExpr
+ | _ -> NormalizedBindingPat(pat, rhsExpr, valSynData, typars)
+
+ // Object constructors are normalized in TcLetrec
+ // Here we are normalizing member definitions with simple (not long) ids,
+ // e.g. "static member x = 3" and "member x = 3" (instance with missing "this." comes through here. It is trapped and generates a warning)
+ | SynPat.Named (SynPat.Wild _, id, false, vis, m)
+ when
+ (match memberFlagsOpt with
+ | None -> false
+ | Some memberFlags ->
+ memberFlags.MemberKind <> MemberKind.Constructor &&
+ memberFlags.MemberKind <> MemberKind.ClassConstructor) ->
+ NormalizeStaticMemberBinding cenv (Option.get memberFlagsOpt) valSynData id vis inferredTyparDecls [] m rhsExpr
+
+ | SynPat.Typed(pat', x, y) ->
+ let (NormalizedBindingPat(pat'', e'', valSynData, typars)) = normPattern pat'
+ NormalizedBindingPat(SynPat.Typed(pat'', x, y), e'', valSynData, typars)
+
+ | SynPat.Attrib(_, _, m) ->
+ error(Error(FSComp.SR.tcAttributesInvalidInPatterns(), m))
+
+ | _ ->
+ NormalizedBindingPat(pat, rhsExpr, valSynData, inferredTyparDecls)
+ normPattern pat
+
+ let NormalizeBinding isObjExprBinding cenv (env: TcEnv) binding =
+ match binding with
+ | Binding (vis, bkind, isInline, isMutable, Attributes attrs, doc, valSynData, p, retInfo, rhsExpr, mBinding, spBind) ->
+ let (NormalizedBindingPat(pat, rhsExpr, valSynData, typars)) =
+ NormalizeBindingPattern cenv cenv.nameResolver isObjExprBinding env valSynData p (NormalizedBindingRhs ([], retInfo, rhsExpr))
+ let paramNames = Some valSynData.SynValInfo.ArgNames
+ let doc = doc.ToXmlDoc(true, paramNames)
+ NormalizedBinding(vis, bkind, isInline, isMutable, attrs, doc, typars, valSynData, pat, rhsExpr, mBinding, spBind)
+
+//-------------------------------------------------------------------------
+// input is:
+// []
+// member x.P with get = fun () -> e
+// -->
+// member x.add_P< >(argName) = (e).AddHandler(argName)
+// member x.remove_P< >(argName) = (e).RemoveHandler(argName)
+
+module EventDeclarationNormalization =
+ let ConvertSynInfo m (SynValInfo(argInfos, retInfo)) =
+ // reconstitute valSynInfo by adding the argument
+ let argInfos =
+ match argInfos with
+ | [[thisArgInfo];[]] -> [[thisArgInfo];SynInfo.unnamedTopArg] // instance property getter
+ | [[]] -> [SynInfo.unnamedTopArg] // static property getter
+ | _ -> error(BadEventTransformation m)
+
+ // reconstitute valSynInfo
+ SynValInfo(argInfos, retInfo)
+
+ // The property x.P becomes methods x.add_P and x.remove_P
+ let ConvertMemberFlags memberFlags = { memberFlags with MemberKind = MemberKind.Member }
+
+ let private ConvertMemberFlagsOpt m memberFlagsOpt =
+ match memberFlagsOpt with
+ | Some memberFlags -> Some (ConvertMemberFlags memberFlags)
+ | _ -> error(BadEventTransformation m)
+
+ let private ConvertSynData m valSynData =
+ let (SynValData(memberFlagsOpt, valSynInfo, thisIdOpt)) = valSynData
+ let memberFlagsOpt = ConvertMemberFlagsOpt m memberFlagsOpt
+ let valSynInfo = ConvertSynInfo m valSynInfo
+ SynValData(memberFlagsOpt, valSynInfo, thisIdOpt)
+
+ let rec private RenameBindingPattern f declPattern =
+ match declPattern with
+ | SynPat.FromParseError(p, _) -> RenameBindingPattern f p
+ | SynPat.Typed(pat', _, _) -> RenameBindingPattern f pat'
+ | SynPat.Named (SynPat.Wild m1, id, x2, vis2, m) -> SynPat.Named (SynPat.Wild m1, ident(f id.idText, id.idRange), x2, vis2, m)
+ | SynPat.InstanceMember(thisId, id, toolId, vis2, m) -> SynPat.InstanceMember(thisId, ident(f id.idText, id.idRange), toolId, vis2, m)
+ | _ -> error(Error(FSComp.SR.tcOnlySimplePatternsInLetRec(), declPattern.Range))
+
+ /// Some F# bindings syntactically imply additional bindings, notably properties
+ /// annotated with []
+ let GenerateExtraBindings cenv (bindingAttribs, binding) =
+ let (NormalizedBinding(vis1, bindingKind, isInline, isMutable, _, bindingXmlDoc, _synTyparDecls, valSynData, declPattern, bindingRhs, mBinding, spBind)) = binding
+ if CompileAsEvent cenv.g bindingAttribs then
+
+ let MakeOne (prefix, target) =
+ let declPattern = RenameBindingPattern (fun s -> prefix + s) declPattern
+ let argName = "handler"
+ // modify the rhs and argument data
+ let bindingRhs, valSynData =
+ let (NormalizedBindingRhs(_, _, rhsExpr)) = bindingRhs
+ let m = rhsExpr.Range
+ // reconstitute valSynInfo by adding the argument
+ let valSynData = ConvertSynData m valSynData
+
+ match rhsExpr with
+ // Detect 'fun () -> e' which results from the compilation of a property getter
+ | SynExpr.Lambda (_, _, SynSimplePats.SimplePats([], _), trueRhsExpr, _, m) ->
+ let rhsExpr = mkSynApp1 (SynExpr.DotGet (SynExpr.Paren (trueRhsExpr, range0, None, m), range0, LongIdentWithDots([ident(target, m)], []), m)) (SynExpr.Ident (ident(argName, m))) m
+
+ // reconstitute rhsExpr
+ let bindingRhs = NormalizedBindingRhs([], None, rhsExpr)
+
+ // add the argument to the expression
+ let bindingRhs = PushOnePatternToRhs cenv true (mkSynPatVar None (ident (argName, mBinding))) bindingRhs
+
+ bindingRhs, valSynData
+ | _ ->
+ error(BadEventTransformation m)
+
+ // reconstitute the binding
+ NormalizedBinding(vis1, bindingKind, isInline, isMutable, [], bindingXmlDoc, noInferredTypars, valSynData, declPattern, bindingRhs, mBinding, spBind)
+
+ [ MakeOne ("add_", "AddHandler"); MakeOne ("remove_", "RemoveHandler") ]
+ else
+ []
+
+
+
+/// Make a copy of the "this" type for a generic object type, e.g. List<'T> --> List<'?> for a fresh inference variable.
+/// Also adjust the "this" type to take into account whether the type is a struct.
+let FreshenObjectArgType cenv m rigid tcref isExtrinsic declaredTyconTypars =
+#if EXTENDED_EXTENSION_MEMBERS // indicates if extension members can add additional constraints to type parameters
+ let tcrefObjTy, enclosingDeclaredTypars, renaming, objTy = FreshenTyconRef m (if isExtrinsic then TyparRigidity.Flexible else rigid) tcref declaredTyconTypars
+#else
+ let tcrefObjTy, enclosingDeclaredTypars, renaming, objTy = FreshenTyconRef m rigid tcref declaredTyconTypars
+#endif
+ // Struct members have a byref 'this' type (unless they are extrinsic extension members)
+ let thisTy =
+ if not isExtrinsic && tcref.IsStructOrEnumTycon then
+ if isRecdOrStructTyReadOnly cenv.g m objTy then
+ mkInByrefTy cenv.g objTy
+ else
+ mkByrefTy cenv.g objTy
+ else
+ objTy
+ tcrefObjTy, enclosingDeclaredTypars, renaming, objTy, thisTy
+
+
+// The early generalization rule of F# 2.0 can be unsound for members in generic types (Bug DevDiv2 10649).
+// It gives rise to types like "Forall T. ?X -> ?Y" where ?X and ?Y are later discovered to involve T.
+//
+// For example:
+// type C<'T>() =
+// let mutable x = Unchecked.defaultof<_> // unknown inference variable ?X
+// static member A() = x
+// // At this point A is generalized early to "Forall T. unit -> ?X"
+// static member B1() = C.A()
+// // At this point during type inference, the return type of C.A() is '?X'
+// // After type inference, the return type of C.A() is 'string'
+// static member B2() = C.A()
+// // At this point during type inference, the return type of C.A() is '?X'
+// // After type inference, the return type of C.A() is 'int'
+// member this.C() = (x: 'T)
+// // At this point during type inference the type of 'x' is inferred to be 'T'
+//
+// Here "A" is generalized too early.
+//
+// Ideally we would simply generalize "A" later, when it is known to be
+// sound. However, that can lead to other problems (e.g. some programs that typecheck today would no longer
+// be accepted). As a result, we deal with this unsoundness by an adhoc post-type-checking
+// consistency check for recursive uses of "A" with explicit instantiations within the recursive
+// scope of "A".
+let TcValEarlyGeneralizationConsistencyCheck cenv (env: TcEnv) (v: Val, vrec, tinst, vty, tau, m) =
+ match vrec with
+ | ValInRecScope isComplete when isComplete && not (isNil tinst) ->
+ //printfn "pushing post-inference check for '%s', vty = '%s'" v.DisplayName (DebugPrint.showType vty)
+ cenv.postInferenceChecks.Add (fun () ->
+ //printfn "running post-inference check for '%s'" v.DisplayName
+ //printfn "tau = '%s'" (DebugPrint.showType tau)
+ //printfn "vty = '%s'" (DebugPrint.showType vty)
+ let tpsorig, tau2 = tryDestForallTy cenv.g vty
+ //printfn "tau2 = '%s'" (DebugPrint.showType tau2)
+ if not (isNil tpsorig) then
+ let tpsorig = NormalizeDeclaredTyparsForEquiRecursiveInference cenv.g tpsorig
+ let tau3 = instType (mkTyparInst tpsorig tinst) tau2
+ //printfn "tau3 = '%s'" (DebugPrint.showType tau3)
+ if not (AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m tau tau3) then
+ let txt = bufs (fun buf -> NicePrint.outputQualifiedValSpec env.DisplayEnv buf v)
+ error(Error(FSComp.SR.tcInferredGenericTypeGivesRiseToInconsistency(v.DisplayName, txt), m)))
+ | _ -> ()
+
+
+/// TcVal. "Use" a value, normally at a fresh type instance (unless optInst is
+/// given). optInst is set when an explicit type instantiation is given, e.g.
+/// Seq.empty
+/// In this case the vrefFlags inside optInst are just NormalValUse.
+///
+/// optInst is is also set when building the final call for a reference to an
+/// F# object model member, in which case the optInst is the type instantiation
+/// inferred by member overload resolution, and vrefFlags indicate if the
+/// member is being used in a special way, i.e. may be one of:
+/// | CtorValUsedAsSuperInit "inherit Panel()"
+/// | CtorValUsedAsSelfInit "new() = new OwnType(3)"
+/// | VSlotDirectCall "base.OnClick(eventArgs)"
+let TcVal checkAttributes cenv env tpenv (vref: ValRef) optInst optAfterResolution m =
+ let (tpsorig, _, _, _, tinst, _) as res =
+ let v = vref.Deref
+ let vrec = v.RecursiveValInfo
+ v.SetHasBeenReferenced()
+ CheckValAccessible m env.eAccessRights vref
+ if checkAttributes then
+ CheckValAttributes cenv.g vref m |> CommitOperationResult
+ let vty = vref.Type
+ // byref-typed values get dereferenced
+ if isByrefTy cenv.g vty then
+ let isSpecial = true
+ [], mkAddrGet m vref, isSpecial, destByrefTy cenv.g vty, [], tpenv
+ else
+ match v.LiteralValue with
+ | Some c ->
+ // Literal values go to constants
+ let isSpecial = true
+ // The value may still be generic, e.g.
+ // []
+ // let Null = null
+ let tpsorig, _, tinst, tau = FreshenPossibleForallTy cenv.g m TyparRigidity.Flexible vty
+ tpsorig, Expr.Const (c, m, tau), isSpecial, tau, tinst, tpenv
+
+ | None ->
+ // References to 'this' in classes get dereferenced from their implicit reference cell and poked
+ if v.BaseOrThisInfo = CtorThisVal && isRefCellTy cenv.g vty then
+ let exprForVal = exprForValRef m vref
+ //if AreWithinCtorPreConstruct env then
+ // warning(SelfRefObjCtor(AreWithinImplicitCtor env, m))
+
+ let ty = destRefCellTy cenv.g vty
+ let isSpecial = true
+ [], mkCallCheckThis cenv.g m ty (mkRefCellGet cenv.g m ty exprForVal), isSpecial, ty, [], tpenv
+ else
+ // Instantiate the value
+ let tpsorig, vrefFlags, tinst, tau, tpenv =
+ // Have we got an explicit instantiation?
+ match optInst with
+ // No explicit instantiation (the normal case)
+ | None ->
+ if HasFSharpAttribute cenv.g cenv.g.attrib_RequiresExplicitTypeArgumentsAttribute v.Attribs then
+ errorR(Error(FSComp.SR.tcFunctionRequiresExplicitTypeArguments(v.DisplayName), m))
+
+ match vrec with
+ | ValInRecScope false ->
+ let tpsorig, tau = vref.TypeScheme
+ let tinst = tpsorig |> List.map mkTyparTy
+ tpsorig, NormalValUse, tinst, tau, tpenv
+ | ValInRecScope true
+ | ValNotInRecScope ->
+ let tpsorig, _, tinst, tau = FreshenPossibleForallTy cenv.g m TyparRigidity.Flexible vty
+ tpsorig, NormalValUse, tinst, tau, tpenv
+
+ // If we have got an explicit instantiation then use that
+ | Some(vrefFlags, checkTys) ->
+ let checkInst (tinst: TypeInst) =
+ if not v.IsMember && not v.PermitsExplicitTypeInstantiation && not (List.isEmpty tinst) && not (List.isEmpty v.Typars) then
+ warning(Error(FSComp.SR.tcDoesNotAllowExplicitTypeArguments(v.DisplayName), m))
+ match vrec with
+ | ValInRecScope false ->
+ let tpsorig, tau = vref.TypeScheme
+ let (tinst: TypeInst), tpenv = checkTys tpenv (tpsorig |> List.map (fun tp -> tp.Kind))
+ checkInst tinst
+ if tpsorig.Length <> tinst.Length then error(Error(FSComp.SR.tcTypeParameterArityMismatch(tpsorig.Length, tinst.Length), m))
+ let tau2 = instType (mkTyparInst tpsorig tinst) tau
+ (tpsorig, tinst) ||> List.iter2 (fun tp ty ->
+ try UnifyTypes cenv env m (mkTyparTy tp) ty
+ with _ -> error (Recursion(env.DisplayEnv, v.Id, tau2, tau, m)))
+ tpsorig, vrefFlags, tinst, tau2, tpenv
+ | ValInRecScope true
+ | ValNotInRecScope ->
+ let tpsorig, tps, tptys, tau = FreshenPossibleForallTy cenv.g m TyparRigidity.Flexible vty
+ //dprintfn "After Freshen: tau = %s" (LayoutRender.showL (typeL tau))
+ let (tinst: TypeInst), tpenv = checkTys tpenv (tps |> List.map (fun tp -> tp.Kind))
+ checkInst tinst
+ //dprintfn "After Check: tau = %s" (LayoutRender.showL (typeL tau))
+ if tptys.Length <> tinst.Length then error(Error(FSComp.SR.tcTypeParameterArityMismatch(tps.Length, tinst.Length), m))
+ List.iter2 (UnifyTypes cenv env m) tptys tinst
+ TcValEarlyGeneralizationConsistencyCheck cenv env (v, vrec, tinst, vty, tau, m)
+
+ //dprintfn "After Unify: tau = %s" (LayoutRender.showL (typeL tau))
+ tpsorig, vrefFlags, tinst, tau, tpenv
+
+ let exprForVal = Expr.Val (vref, vrefFlags, m)
+ let exprForVal = mkTyAppExpr m (exprForVal, vty) tinst
+ let isSpecial =
+ (match vrefFlags with NormalValUse | PossibleConstrainedCall _ -> false | _ -> true) ||
+ valRefEq cenv.g vref cenv.g.splice_expr_vref ||
+ valRefEq cenv.g vref cenv.g.splice_raw_expr_vref
+
+ let exprForVal = RecordUseOfRecValue cenv vrec vref exprForVal m
+
+ tpsorig, exprForVal, isSpecial, tau, tinst, tpenv
+
+ match optAfterResolution with
+ | Some (AfterResolution.RecordResolution(_, callSink, _, _)) -> callSink (mkTyparInst tpsorig tinst)
+ | Some AfterResolution.DoNothing | None -> ()
+ res
+
+/// simplified version of TcVal used in calls to BuildMethodCall (typrelns.fs)
+/// this function is used on typechecking step for making calls to provided methods and on optimization step (for the same purpose).
+let LightweightTcValForUsingInBuildMethodCall g (vref: ValRef) vrefFlags (vrefTypeInst: TTypes) m =
+ let v = vref.Deref
+ let vty = vref.Type
+ // byref-typed values get dereferenced
+ if isByrefTy g vty then
+ mkAddrGet m vref, destByrefTy g vty
+ else
+ match v.LiteralValue with
+ | Some c ->
+ let _, _, _, tau = FreshenPossibleForallTy g m TyparRigidity.Flexible vty
+ Expr.Const (c, m, tau), tau
+ | None ->
+ // Instantiate the value
+ let tau =
+ // If we have got an explicit instantiation then use that
+ let _, tps, tptys, tau = FreshenPossibleForallTy g m TyparRigidity.Flexible vty
+ if tptys.Length <> vrefTypeInst.Length then error(Error(FSComp.SR.tcTypeParameterArityMismatch(tps.Length, vrefTypeInst.Length), m))
+ instType (mkTyparInst tps vrefTypeInst) tau
+
+ let exprForVal = Expr.Val (vref, vrefFlags, m)
+ let exprForVal = mkTyAppExpr m (exprForVal, vty) vrefTypeInst
+ exprForVal, tau
+
+/// Mark points where we decide whether an expression will support automatic
+/// decondensation or not. This is somewhat a relic of a previous implementation of decondensation and could
+/// be removed
+
+type ApplicableExpr =
+ | ApplicableExpr of
+ // context
+ cenv *
+ // the function-valued expression
+ Expr *
+ // is this the first in an application series
+ bool
+
+ member x.Range =
+ match x with
+ | ApplicableExpr (_, e, _) -> e.Range
+
+ member x.Type =
+ match x with
+ | ApplicableExpr (cenv, e, _) -> tyOfExpr cenv.g e
+
+ member x.SupplyArgument(e2, m) =
+ let (ApplicableExpr (cenv, fe, first)) = x
+ let combinedExpr =
+ match fe with
+ | Expr.App (e1, e1ty, tyargs1, args1, e1m) when
+ (not first || isNil args1) &&
+ (not (isForallTy cenv.g e1ty) || isFunTy cenv.g (applyTys cenv.g e1ty (tyargs1, args1))) ->
+ Expr.App (e1, e1ty, tyargs1, args1@[e2], unionRanges e1m m)
+ | _ ->
+ Expr.App (fe, tyOfExpr cenv.g fe, [], [e2], m)
+ ApplicableExpr(cenv, combinedExpr, false)
+
+ member x.Expr =
+ match x with
+ | ApplicableExpr(_, e, _) -> e
+
+let MakeApplicableExprNoFlex cenv expr =
+ ApplicableExpr (cenv, expr, true)
+
+/// This function reverses the effect of condensation for a named function value (indeed it can
+/// work for any expression, though we only invoke it immediately after a call to TcVal).
+///
+/// De-condensation is determined BEFORE any arguments are checked. Thus
+/// let f (x:'a) (y:'a) = ()
+///
+/// f (new obj()) "string"
+///
+/// does not type check (the argument instantiates 'a to "obj" but there is no flexibility on the
+/// second argument position.
+///
+/// De-condensation is applied AFTER taking into account an explicit type instantiation. This
+/// let f<'a> (x:'a) = ()
+///
+/// f("string)"
+///
+/// will type check but
+///
+/// Sealed types and 'obj' do not introduce generic flexibility when functions are used as first class
+/// values.
+///
+/// For 'obj' this is because introducing this flexibility would NOT be the reverse of condensation,
+/// since we don't condense
+/// f: 'a -> unit
+/// to
+/// f: obj -> unit
+///
+/// We represent the flexibility in the TAST by leaving a function-to-function coercion node in the tree
+/// This "special" node is immediately eliminated by the use of IteratedFlexibleAdjustArityOfLambdaBody as soon as we
+/// first transform the tree (currently in optimization)
+
+let MakeApplicableExprWithFlex cenv (env: TcEnv) expr =
+ let g = cenv.g
+ let exprTy = tyOfExpr g expr
+ let m = expr.Range
+
+ let isNonFlexibleType ty = isSealedTy g ty
+
+ let argTys, retTy = stripFunTy g exprTy
+ let curriedActualTypes = argTys |> List.map (tryDestRefTupleTy g)
+ if (curriedActualTypes.IsEmpty ||
+ curriedActualTypes |> List.exists (List.exists (isByrefTy g)) ||
+ curriedActualTypes |> List.forall (List.forall isNonFlexibleType)) then
+
+ ApplicableExpr (cenv, expr, true)
+ else
+ let curriedFlexibleTypes =
+ curriedActualTypes |> List.mapSquared (fun actualType ->
+ if isNonFlexibleType actualType
+ then actualType
+ else
+ let flexibleType = NewInferenceType ()
+ AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace actualType flexibleType
+ flexibleType)
+
+ // Create a coercion to represent the expansion of the application
+ let expr = mkCoerceExpr (expr, mkIteratedFunTy (List.map (mkRefTupledTy g) curriedFlexibleTypes) retTy, m, exprTy)
+ ApplicableExpr (cenv, expr, true)
+
+
+/// Checks, warnings and constraint assertions for downcasts
+let TcRuntimeTypeTest isCast isOperator cenv denv m tgtTy srcTy =
+ let g = cenv.g
+ if TypeDefinitelySubsumesTypeNoCoercion 0 g cenv.amap m tgtTy srcTy then
+ warning(TypeTestUnnecessary m)
+
+ if isTyparTy g srcTy && not (destTyparTy g srcTy).IsCompatFlex then
+ error(IndeterminateRuntimeCoercion(denv, srcTy, tgtTy, m))
+
+ if isSealedTy g srcTy then
+ error(RuntimeCoercionSourceSealed(denv, srcTy, m))
+
+ if isSealedTy g tgtTy || isTyparTy g tgtTy || not (isInterfaceTy g srcTy) then
+ if isCast then
+ AddCxTypeMustSubsumeType (ContextInfo.RuntimeTypeTest isOperator) denv cenv.css m NoTrace srcTy tgtTy
+ else
+ AddCxTypeMustSubsumeType ContextInfo.NoContext denv cenv.css m NoTrace srcTy tgtTy
+
+ if isErasedType g tgtTy then
+ if isCast then
+ warning(Error(FSComp.SR.tcTypeCastErased(NicePrint.minimalStringOfType denv tgtTy, NicePrint.minimalStringOfType denv (stripTyEqnsWrtErasure EraseAll g tgtTy)), m))
+ else
+ error(Error(FSComp.SR.tcTypeTestErased(NicePrint.minimalStringOfType denv tgtTy, NicePrint.minimalStringOfType denv (stripTyEqnsWrtErasure EraseAll g tgtTy)), m))
+ else
+ getErasedTypes g tgtTy |>
+ List.iter (fun ety -> if isMeasureTy g ety
+ then warning(Error(FSComp.SR.tcTypeTestLosesMeasures(NicePrint.minimalStringOfType denv ety), m))
+ else warning(Error(FSComp.SR.tcTypeTestLossy(NicePrint.minimalStringOfType denv ety, NicePrint.minimalStringOfType denv (stripTyEqnsWrtErasure EraseAll g ety)), m)))
+
+/// Checks, warnings and constraint assertions for upcasts
+let TcStaticUpcast cenv denv m tgtTy srcTy =
+ if isTyparTy cenv.g tgtTy then
+ if not (destTyparTy cenv.g tgtTy).IsCompatFlex then
+ error(IndeterminateStaticCoercion(denv, srcTy, tgtTy, m))
+ //else warning(UpcastUnnecessary m)
+
+ if isSealedTy cenv.g tgtTy && not (isTyparTy cenv.g tgtTy) then
+ warning(CoercionTargetSealed(denv, tgtTy, m))
+
+ if typeEquiv cenv.g srcTy tgtTy then
+ warning(UpcastUnnecessary m)
+
+ AddCxTypeMustSubsumeType ContextInfo.NoContext denv cenv.css m NoTrace tgtTy srcTy
+
+let BuildPossiblyConditionalMethodCall cenv env isMutable m isProp minfo valUseFlags minst objArgs args =
+
+ let conditionalCallDefineOpt = TryFindMethInfoStringAttribute cenv.g m cenv.g.attrib_ConditionalAttribute minfo
+
+ match conditionalCallDefineOpt, cenv.conditionalDefines with
+ | Some d, Some defines when not (List.contains d defines) ->
+
+ // Methods marked with 'Conditional' must return 'unit'
+ UnifyTypes cenv env m cenv.g.unit_ty (minfo.GetFSharpReturnTy(cenv.amap, m, minst))
+ mkUnit cenv.g m, cenv.g.unit_ty
+
+ | _ ->
+#if !NO_EXTENSIONTYPING
+ match minfo with
+ | ProvidedMeth(_, mi, _, _) ->
+ // BuildInvokerExpressionForProvidedMethodCall converts references to F# intrinsics back to values
+ // and uses TcVal to do this. However we don't want to check attributes again for provided references to values,
+ // so we pass 'false' for 'checkAttributes'.
+ let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g
+ let _, retExpt, retTy = ProvidedMethodCalls.BuildInvokerExpressionForProvidedMethodCall tcVal (cenv.g, cenv.amap, mi, objArgs, isMutable, isProp, valUseFlags, args, m)
+ retExpt, retTy
+
+ | _ ->
+#endif
+ let tcVal valref valUse ttypes m =
+ let _, a, _, b, _, _ = TcVal true cenv env emptyUnscopedTyparEnv valref (Some (valUse, (fun x _ -> ttypes, x))) None m
+ a, b
+ BuildMethodCall tcVal cenv.g cenv.amap isMutable m isProp minfo valUseFlags minst objArgs args
+
+
+let TryFindIntrinsicOrExtensionMethInfo collectionSettings (cenv: cenv) (env: TcEnv) m ad nm ty =
+ AllMethInfosOfTypeInScope collectionSettings cenv.infoReader env.NameEnv (Some nm) ad IgnoreOverrides m ty
+
+let TryFindFSharpSignatureInstanceGetterProperty (cenv: cenv) (env: TcEnv) m nm ty (sigTys: TType list) =
+ TryFindPropInfo cenv.infoReader m env.AccessRights nm ty
+ |> List.tryFind (fun propInfo ->
+ not propInfo.IsStatic && propInfo.HasGetter &&
+ (
+ match propInfo.GetterMethod.GetParamTypes(cenv.amap, m, []) with
+ | [] -> false
+ | argTysList ->
+
+ let argTys = (argTysList |> List.reduce (@)) @ [ propInfo.GetterMethod.GetFSharpReturnTy(cenv.amap, m, []) ] in
+ if argTys.Length <> sigTys.Length then
+ false
+ else
+ (argTys, sigTys)
+ ||> List.forall2 (typeEquiv cenv.g)
+ )
+ )
+
+/// Build the 'test and dispose' part of a 'use' statement
+let BuildDisposableCleanup cenv env m (v: Val) =
+ v.SetHasBeenReferenced()
+ let ad = env.eAccessRights
+ let disposeMethod =
+ match TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AllResults cenv env m ad "Dispose" cenv.g.system_IDisposable_ty with
+ | [x] -> x
+ | _ -> error(InternalError(FSComp.SR.tcCouldNotFindIDisposable(), m))
+
+
+ // For struct types the test is simpler: we can determine if IDisposable is supported, and even when it is, we can avoid doing the type test
+ // Note this affects the elaborated form seen by quotations etc.
+ if isStructTy cenv.g v.Type then
+ if TypeFeasiblySubsumesType 0 cenv.g cenv.amap m cenv.g.system_IDisposable_ty CanCoerce v.Type then
+ // We can use NeverMutates here because the variable is going out of scope, there is no need to take a defensive
+ // copy of it.
+ let disposeExpr, _ = BuildPossiblyConditionalMethodCall cenv env NeverMutates m false disposeMethod NormalValUse [] [exprForVal v.Range v] []
+ disposeExpr
+ else
+ mkUnit cenv.g m
+ else
+ let disposeObjVar, disposeObjExpr = mkCompGenLocal m "objectToDispose" cenv.g.system_IDisposable_ty
+ let disposeExpr, _ = BuildPossiblyConditionalMethodCall cenv env PossiblyMutates m false disposeMethod NormalValUse [] [disposeObjExpr] []
+ let inpe = mkCoerceExpr(exprForVal v.Range v, cenv.g.obj_ty, m, v.Type)
+ mkIsInstConditional cenv.g m cenv.g.system_IDisposable_ty inpe disposeObjVar disposeExpr (mkUnit cenv.g m)
+
+/// Build call to get_OffsetToStringData as part of 'fixed'
+let BuildOffsetToStringData cenv env m =
+ let ad = env.eAccessRights
+ let offsetToStringDataMethod =
+ match TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AllResults cenv env m ad "get_OffsetToStringData" cenv.g.system_RuntimeHelpers_ty with
+ | [x] -> x
+ | _ -> error(Error(FSComp.SR.tcCouldNotFindOffsetToStringData(), m))
+
+ let offsetExpr, _ = BuildPossiblyConditionalMethodCall cenv env NeverMutates m false offsetToStringDataMethod NormalValUse [] [] []
+ offsetExpr
+
+let BuildILFieldGet g amap m objExpr (finfo: ILFieldInfo) =
+ let fref = finfo.ILFieldRef
+ let isValueType = finfo.IsValueType
+ let valu = if isValueType then AsValue else AsObject
+ let tinst = finfo.TypeInst
+ let fieldType = finfo.FieldType (amap, m)
+#if !NO_EXTENSIONTYPING
+ let ty = tyOfExpr g objExpr
+ match finfo with
+ | ProvidedField _ when (isErasedType g ty) ->
+ // we know it's accessible, and there are no attributes to check for now...
+ match finfo.LiteralValue with
+ | None ->
+ error (Error(FSComp.SR.tcTPFieldMustBeLiteral(), m))
+ | Some lit ->
+ Expr.Const (TcFieldInit m lit, m, fieldType)
+ | _ ->
+#endif
+ let wrap, objExpr, _readonly, _writeonly = mkExprAddrOfExpr g isValueType false NeverMutates objExpr None m
+ // The empty instantiation on the AbstractIL fspec is OK, since we make the correct fspec in IlxGen.GenAsm
+ // This ensures we always get the type instantiation right when doing this from
+ // polymorphic code, after inlining etc. *
+ let fspec = mkILFieldSpec(fref, mkILNamedTy valu fref.DeclaringTypeRef [])
+ // Add an I_nop if this is an initonly field to make sure we never recognize it as an lvalue. See mkExprAddrOfExpr.
+ wrap (mkAsmExpr (([ mkNormalLdfld fspec ] @ (if finfo.IsInitOnly then [ AI_nop ] else [])), tinst, [objExpr], [fieldType], m))
+
+/// Checks that setting a field value does not set a literal or initonly field
+let private CheckFieldLiteralArg (finfo: ILFieldInfo) argExpr m =
+ finfo.LiteralValue |> Option.iter (fun _ ->
+ match argExpr with
+ | Expr.Const (v, _, _) ->
+ let literalValue = string v
+ error (Error(FSComp.SR.tcLiteralFieldAssignmentWithArg literalValue, m))
+ | _ ->
+ error (Error(FSComp.SR.tcLiteralFieldAssignmentNoArg(), m))
+ )
+ if finfo.IsInitOnly then error (Error (FSComp.SR.tcFieldIsReadonly(), m))
+
+let BuildILFieldSet g m objExpr (finfo: ILFieldInfo) argExpr =
+ let fref = finfo.ILFieldRef
+ let isValueType = finfo.IsValueType
+ let valu = if isValueType then AsValue else AsObject
+ let tinst = finfo.TypeInst
+ // The empty instantiation on the AbstractIL fspec is OK, since we make the correct fspec in IlxGen.GenAsm
+ // This ensures we always get the type instantiation right when doing this from
+ // polymorphic code, after inlining etc. *
+ let fspec = mkILFieldSpec(fref, mkILNamedTy valu fref.DeclaringTypeRef [])
+ CheckFieldLiteralArg finfo argExpr m
+ let wrap, objExpr, _readonly, _writeonly = mkExprAddrOfExpr g isValueType false DefinitelyMutates objExpr None m
+ wrap (mkAsmExpr ([ mkNormalStfld fspec ], tinst, [objExpr; argExpr], [], m))
+
+let BuildILStaticFieldSet m (finfo: ILFieldInfo) argExpr =
+ let fref = finfo.ILFieldRef
+ let isValueType = finfo.IsValueType
+ let valu = if isValueType then AsValue else AsObject
+ let tinst = finfo.TypeInst
+ // The empty instantiation on the AbstractIL fspec is OK, since we make the correct fspec in IlxGen.GenAsm
+ // This ensures we always get the type instantiation right when doing this from
+ // polymorphic code, after inlining etc.
+ let fspec = mkILFieldSpec(fref, mkILNamedTy valu fref.DeclaringTypeRef [])
+ CheckFieldLiteralArg finfo argExpr m
+ mkAsmExpr ([ mkNormalStsfld fspec ], tinst, [argExpr], [], m)
+
+let BuildRecdFieldSet g m objExpr (rfinfo: RecdFieldInfo) argExpr =
+ let tgtTy = rfinfo.DeclaringType
+ let valu = isStructTy g tgtTy
+ let objExpr = if valu then objExpr else mkCoerceExpr(objExpr, tgtTy, m, tyOfExpr g objExpr)
+ let wrap, objExpr, _readonly, _writeonly = mkExprAddrOfExpr g valu false DefinitelyMutates objExpr None m
+ wrap (mkRecdFieldSetViaExprAddr (objExpr, rfinfo.RecdFieldRef, rfinfo.TypeInst, argExpr, m) )
+
+//-------------------------------------------------------------------------
+// Helpers dealing with named and optional args at callsites
+//-------------------------------------------------------------------------
+
+let (|BinOpExpr|_|) e =
+ match e with
+ | SynExpr.App (_, _, SynExpr.App (_, _, SingleIdent opId, a, _), b, _) -> Some (opId, a, b)
+ | _ -> None
+
+let (|SimpleEqualsExpr|_|) e =
+ match e with
+ | BinOpExpr(opId, a, b) when opId.idText = opNameEquals -> Some (a, b)
+ | _ -> None
+
+/// Detect a named argument at a callsite
+let TryGetNamedArg e =
+ match e with
+ | SimpleEqualsExpr(LongOrSingleIdent(isOpt, LongIdentWithDots([a], _), None, _), b) -> Some(isOpt, a, b)
+ | _ -> None
+
+let inline IsNamedArg e =
+ match e with
+ | SimpleEqualsExpr(LongOrSingleIdent(_, LongIdentWithDots([_], _), None, _), _) -> true
+ | _ -> false
+
+/// Get the method arguments at a callsite, taking into account named and optional arguments
+let GetMethodArgs arg =
+ let args =
+ match arg with
+ | SynExpr.Const (SynConst.Unit, _) -> []
+ | SynExprParen(SynExpr.Tuple (false, args, _, _), _, _, _) | SynExpr.Tuple (false, args, _, _) -> args
+ | SynExprParen(arg, _, _, _) | arg -> [arg]
+ let unnamedCallerArgs, namedCallerArgs =
+ args |> List.takeUntil IsNamedArg
+ let namedCallerArgs =
+ namedCallerArgs
+ |> List.choose (fun e ->
+ match TryGetNamedArg e with
+ | None ->
+ // ignore errors to avoid confusing error messages in cases like foo(a = 1, )
+ // do not abort overload resolution in case if named arguments are mixed with errors
+ match e with
+ | SynExpr.ArbitraryAfterError _ -> None
+ | _ -> error(Error(FSComp.SR.tcNameArgumentsMustAppearLast(), e.Range))
+ | namedArg -> namedArg)
+ unnamedCallerArgs, namedCallerArgs
+
+
+//-------------------------------------------------------------------------
+// Helpers dealing with pattern match compilation
+//-------------------------------------------------------------------------
+
+let CompilePatternForMatch cenv (env: TcEnv) mExpr matchm warnOnUnused actionOnFailure (inputVal, generalizedTypars, inputExprOpt) clauses inputTy resultTy =
+ let dtree, targets = CompilePattern cenv.g env.DisplayEnv cenv.amap (LightweightTcValForUsingInBuildMethodCall cenv.g) cenv.infoReader mExpr matchm warnOnUnused actionOnFailure (inputVal, generalizedTypars, inputExprOpt) clauses inputTy resultTy
+ mkAndSimplifyMatch NoDebugPointAtInvisibleBinding mExpr matchm resultTy dtree targets
+
+/// Compile a pattern
+let CompilePatternForMatchClauses cenv env mExpr matchm warnOnUnused actionOnFailure inputExprOpt inputTy resultTy tclauses =
+ // Avoid creating a dummy in the common cases where we are about to bind a name for the expression
+ // CLEANUP: avoid code duplication with code further below, i.e.all callers should call CompilePatternForMatch
+ match tclauses with
+ | [TClause(TPat_as (pat1, PBind (asVal, TypeScheme(generalizedTypars, _)), _), None, TTarget(vs, e, spTarget), m2)] ->
+ let expr = CompilePatternForMatch cenv env mExpr matchm warnOnUnused actionOnFailure (asVal, generalizedTypars, None) [TClause(pat1, None, TTarget(ListSet.remove valEq asVal vs, e, spTarget), m2)] inputTy resultTy
+ asVal, expr
+ | _ ->
+ let matchValueTmp, _ = mkCompGenLocal mExpr "matchValue" inputTy
+ let expr = CompilePatternForMatch cenv env mExpr matchm warnOnUnused actionOnFailure (matchValueTmp, [], inputExprOpt) tclauses inputTy resultTy
+ matchValueTmp, expr
+
+//-------------------------------------------------------------------------
+// Helpers dealing with sequence expressions
+//-------------------------------------------------------------------------
+
+/// Get the fragmentary expressions resulting from turning
+/// an expression into an enumerable value, e.g. at 'for' loops
+
+// localAlloc is relevant if the enumerator is a mutable struct and indicates
+// if the enumerator can be allocated as a mutable local variable
+let AnalyzeArbitraryExprAsEnumerable cenv (env: TcEnv) localAlloc m exprty expr =
+ let ad = env.AccessRights
+
+ let err k ty =
+ let txt = NicePrint.minimalStringOfType env.DisplayEnv ty
+ let msg = if k then FSComp.SR.tcTypeCannotBeEnumerated txt else FSComp.SR.tcEnumTypeCannotBeEnumerated txt
+ Exception(Error(msg, m))
+
+ let findMethInfo k m nm ty =
+ match TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad nm ty with
+ | [] -> err k ty
+ | res :: _ -> Result res
+
+ // Ensure there are no curried arguments, and indeed no arguments at all
+ let hasArgs (minfo: MethInfo) minst =
+ match minfo.GetParamTypes(cenv.amap, m, minst) with
+ | [[]] -> false
+ | _ -> true
+
+ let tryType (exprToSearchForGetEnumeratorAndItem, tyToSearchForGetEnumeratorAndItem) =
+ match findMethInfo true m "GetEnumerator" tyToSearchForGetEnumeratorAndItem with
+ | Exception e -> Exception e
+ | Result getEnumerator_minfo ->
+
+ let getEnumerator_minst = FreshenMethInfo m getEnumerator_minfo
+ let retTypeOfGetEnumerator = getEnumerator_minfo.GetFSharpReturnTy(cenv.amap, m, getEnumerator_minst)
+ if hasArgs getEnumerator_minfo getEnumerator_minst then err true tyToSearchForGetEnumeratorAndItem else
+
+ match findMethInfo false m "MoveNext" retTypeOfGetEnumerator with
+ | Exception e -> Exception e
+ | Result moveNext_minfo ->
+
+ let moveNext_minst = FreshenMethInfo m moveNext_minfo
+ let retTypeOfMoveNext = moveNext_minfo.GetFSharpReturnTy(cenv.amap, m, moveNext_minst)
+ if not (typeEquiv cenv.g cenv.g.bool_ty retTypeOfMoveNext) then err false retTypeOfGetEnumerator else
+ if hasArgs moveNext_minfo moveNext_minst then err false retTypeOfGetEnumerator else
+
+ match findMethInfo false m "get_Current" retTypeOfGetEnumerator with
+ | Exception e -> Exception e
+ | Result get_Current_minfo ->
+
+ let get_Current_minst = FreshenMethInfo m get_Current_minfo
+ if hasArgs get_Current_minfo get_Current_minst then err false retTypeOfGetEnumerator else
+ let enumElemTy = get_Current_minfo.GetFSharpReturnTy(cenv.amap, m, get_Current_minst)
+
+ // Compute the element type of the strongly typed enumerator
+ //
+ // Like C#, we detect the 'GetEnumerator' pattern for .NET version 1.x abstractions that don't
+ // support the correct generic interface. However unlike C# we also go looking for a 'get_Item' or 'Item' method
+ // with a single integer indexer argument to try to get a strong type for the enumeration should the Enumerator
+ // not provide anything useful. To enable interop with some legacy COM APIs,
+ // the single integer indexer argument is allowed to have type 'object'.
+
+ let enumElemTy =
+
+ if isObjTy cenv.g enumElemTy then
+ // Look for an 'Item' property, or a set of these with consistent return types
+ let allEquivReturnTypes (minfo: MethInfo) (others: MethInfo list) =
+ let returnTy = minfo.GetFSharpReturnTy(cenv.amap, m, [])
+ others |> List.forall (fun other -> typeEquiv cenv.g (other.GetFSharpReturnTy(cenv.amap, m, [])) returnTy)
+
+ let isInt32OrObjectIndexer (minfo: MethInfo) =
+ match minfo.GetParamTypes(cenv.amap, m, []) with
+ | [[ty]] ->
+ // e.g. MatchCollection
+ typeEquiv cenv.g cenv.g.int32_ty ty ||
+ // e.g. EnvDTE.Documents.Item
+ typeEquiv cenv.g cenv.g.obj_ty ty
+ | _ -> false
+
+ match TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AllResults cenv env m ad "get_Item" tyToSearchForGetEnumeratorAndItem with
+ | (minfo :: others) when (allEquivReturnTypes minfo others &&
+ List.exists isInt32OrObjectIndexer (minfo :: others)) ->
+ minfo.GetFSharpReturnTy(cenv.amap, m, [])
+
+ | _ ->
+
+ // Some types such as XmlNodeList have only an Item method
+ match TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AllResults cenv env m ad "Item" tyToSearchForGetEnumeratorAndItem with
+ | (minfo :: others) when (allEquivReturnTypes minfo others &&
+ List.exists isInt32OrObjectIndexer (minfo :: others)) ->
+ minfo.GetFSharpReturnTy(cenv.amap, m, [])
+
+ | _ -> enumElemTy
+ else
+ enumElemTy
+
+ let isEnumeratorTypeStruct = isStructTy cenv.g retTypeOfGetEnumerator
+ let originalRetTypeOfGetEnumerator = retTypeOfGetEnumerator
+
+ let (enumeratorVar, enumeratorExpr), retTypeOfGetEnumerator =
+ if isEnumeratorTypeStruct then
+ if localAlloc then
+ mkMutableCompGenLocal m "enumerator" retTypeOfGetEnumerator, retTypeOfGetEnumerator
+ else
+ let refCellTyForRetTypeOfGetEnumerator = mkRefCellTy cenv.g retTypeOfGetEnumerator
+ let v, e = mkMutableCompGenLocal m "enumerator" refCellTyForRetTypeOfGetEnumerator
+ (v, mkRefCellGet cenv.g m retTypeOfGetEnumerator e), refCellTyForRetTypeOfGetEnumerator
+
+ else
+ mkCompGenLocal m "enumerator" retTypeOfGetEnumerator, retTypeOfGetEnumerator
+
+ let getEnumExpr, getEnumTy =
+ let (getEnumExpr, getEnumTy) as res = BuildPossiblyConditionalMethodCall cenv env PossiblyMutates m false getEnumerator_minfo NormalValUse getEnumerator_minst [exprToSearchForGetEnumeratorAndItem] []
+ if not isEnumeratorTypeStruct || localAlloc then res
+ else
+ // wrap enumerators that are represented as mutable structs into ref cells
+ let getEnumExpr = mkRefCell cenv.g m originalRetTypeOfGetEnumerator getEnumExpr
+ let getEnumTy = mkRefCellTy cenv.g getEnumTy
+ getEnumExpr, getEnumTy
+
+ let guardExpr, guardTy = BuildPossiblyConditionalMethodCall cenv env DefinitelyMutates m false moveNext_minfo NormalValUse moveNext_minst [enumeratorExpr] []
+ let currentExpr, currentTy = BuildPossiblyConditionalMethodCall cenv env DefinitelyMutates m true get_Current_minfo NormalValUse get_Current_minst [enumeratorExpr] []
+ let currentExpr = mkCoerceExpr(currentExpr, enumElemTy, currentExpr.Range, currentTy)
+ let currentExpr, enumElemTy =
+ // Implicitly dereference byref for expr 'for x in ...'
+ if isByrefTy cenv.g enumElemTy then
+ let expr = mkDerefAddrExpr m currentExpr currentExpr.Range enumElemTy
+ expr, destByrefTy cenv.g enumElemTy
+ else
+ currentExpr, enumElemTy
+
+ Result(enumeratorVar, enumeratorExpr, retTypeOfGetEnumerator, enumElemTy, getEnumExpr, getEnumTy, guardExpr, guardTy, currentExpr)
+
+ // First try the original known static type
+ match (if isArray1DTy cenv.g exprty then Exception (Failure "") else tryType (expr, exprty)) with
+ | Result res -> res
+ | Exception e ->
+
+ let probe ty =
+ if (AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m ty exprty) then
+ match tryType (mkCoerceExpr(expr, ty, expr.Range, exprty), ty) with
+ | Result res -> Some res
+ | Exception e ->
+ PreserveStackTrace e
+ raise e
+ else None
+
+ // Next try to typecheck the thing as a sequence
+ let enumElemTy = NewInferenceType ()
+ let exprTyAsSeq = mkSeqTy cenv.g enumElemTy
+
+ match probe exprTyAsSeq with
+ | Some res -> res
+ | None ->
+ let ienumerable = mkAppTy cenv.g.tcref_System_Collections_IEnumerable []
+ match probe ienumerable with
+ | Some res -> res
+ | None ->
+ PreserveStackTrace e
+ raise e
+
+// Used inside sequence expressions
+let ConvertArbitraryExprToEnumerable (cenv: cenv) ty (env: TcEnv) (expr: Expr) =
+ let m = expr.Range
+ let enumElemTy = NewInferenceType ()
+ if AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m ( mkSeqTy cenv.g enumElemTy) ty then
+ expr, enumElemTy
+ else
+ let enumerableVar, enumerableExpr = mkCompGenLocal m "inputSequence" ty
+ let enumeratorVar, _, retTypeOfGetEnumerator, enumElemTy, getEnumExpr, _, guardExpr, guardTy, betterCurrentExpr =
+ AnalyzeArbitraryExprAsEnumerable cenv env false m ty enumerableExpr
+
+ let expr =
+ mkCompGenLet m enumerableVar expr
+ (mkCallSeqOfFunctions cenv.g m retTypeOfGetEnumerator enumElemTy
+ (mkUnitDelayLambda cenv.g m getEnumExpr)
+ (mkLambda m enumeratorVar (guardExpr, guardTy))
+ (mkLambda m enumeratorVar (betterCurrentExpr, enumElemTy)))
+ expr, enumElemTy
+
+//-------------------------------------------------------------------------
+// Post-transform initialization graphs using the 'lazy' interpretation.
+// See ML workshop paper.
+//-------------------------------------------------------------------------
+
+type InitializationGraphAnalysisState =
+ | Top
+ | InnerTop
+ | DefinitelyStrict
+ | MaybeLazy
+ | DefinitelyLazy
+
+type PreInitializationGraphEliminationBinding =
+ { FixupPoints: RecursiveUseFixupPoints
+ Binding: Binding }
+
+/// Check for safety and determine if we need to insert lazy thunks
+let EliminateInitializationGraphs
+ g
+ mustHaveArity
+ denv
+ (bindings: 'Bindings list)
+ (iterBindings: ((PreInitializationGraphEliminationBinding list -> unit) -> 'Bindings list -> unit))
+ (buildLets: Binding list -> 'Result)
+ (mapBindings: (PreInitializationGraphEliminationBinding list -> Binding list) -> 'Bindings list -> 'Result list)
+ bindsm =
+
+ let recursiveVals =
+ let hash = ValHash.Create()
+ let add (pgrbind: PreInitializationGraphEliminationBinding) = let c = pgrbind.Binding.Var in hash.Add(c, c)
+ bindings |> iterBindings (List.iter add)
+ hash
+
+ // The output of the analysis
+ let mutable outOfOrder = false
+ let mutable runtimeChecks = false
+ let mutable directRecursiveData = false
+ let mutable reportedEager = false
+ let mutable definiteDependencies = []
+
+ let rec stripChooseAndExpr e =
+ match stripExpr e with
+ | Expr.TyChoose (_, b, _) -> stripChooseAndExpr b
+ | e -> e
+
+ let availIfInOrder = ValHash<_>.Create()
+ let check boundv expr =
+ let strict = function
+ | MaybeLazy -> MaybeLazy
+ | DefinitelyLazy -> DefinitelyLazy
+ | Top | DefinitelyStrict | InnerTop -> DefinitelyStrict
+ let lzy = function
+ | Top | InnerTop | DefinitelyLazy -> DefinitelyLazy
+ | MaybeLazy | DefinitelyStrict -> MaybeLazy
+ let fixable = function
+ | Top | InnerTop -> InnerTop
+ | DefinitelyStrict -> DefinitelyStrict
+ | MaybeLazy -> MaybeLazy
+ | DefinitelyLazy -> DefinitelyLazy
+
+ let rec CheckExpr st e =
+ match stripChooseAndExpr e with
+ // Expressions with some lazy parts
+ | Expr.Lambda (_, _, _, _, b, _, _) -> checkDelayed st b
+
+ // Type-lambdas are analyzed as if they are strict.
+ //
+ // This is a design decision (See bug 6496), so that generalized recursive bindings such as
+ // let rec x = x
+ // are analyzed. Although we give type "x: 'T" to these, from the users point of view
+ // any use of "x" will result in an infinite recursion. Type instantiation is implicit in F#
+ // because of type inference, which makes it reasonable to check generic bindings strictly.
+ | Expr.TyLambda (_, _, b, _, _) -> CheckExpr st b
+
+ | Expr.Obj (_, ty, _, e, overrides, extraImpls, _) ->
+ // NOTE: we can't fixup recursive references inside delegates since the closure delegee of a delegate is not accessible
+ // from outside. Object expressions implementing interfaces can, on the other hand, be fixed up. See FSharp 1.0 bug 1469
+ if isInterfaceTy g ty then
+ List.iter (fun (TObjExprMethod(_, _, _, _, e, _)) -> checkDelayed st e) overrides
+ List.iter (snd >> List.iter (fun (TObjExprMethod(_, _, _, _, e, _)) -> checkDelayed st e)) extraImpls
+ else
+ CheckExpr (strict st) e
+ List.iter (fun (TObjExprMethod(_, _, _, _, e, _)) -> CheckExpr (lzy (strict st)) e) overrides
+ List.iter (snd >> List.iter (fun (TObjExprMethod(_, _, _, _, e, _)) -> CheckExpr (lzy (strict st)) e)) extraImpls
+
+ // Expressions where fixups may be needed
+ | Expr.Val (v, _, m) -> CheckValRef st v m
+
+ // Expressions where subparts may be fixable
+ | Expr.Op ((TOp.Tuple _ | TOp.UnionCase _ | TOp.Recd _), _, args, _) ->
+ List.iter (CheckExpr (fixable st)) args
+
+ // Composite expressions
+ | Expr.Const _ -> ()
+ | Expr.LetRec (binds, e, _, _) ->
+ binds |> List.iter (CheckBinding (strict st))
+ CheckExpr (strict st) e
+ | Expr.Let (bind, e, _, _) ->
+ CheckBinding (strict st) bind
+ CheckExpr (strict st) e
+ | Expr.Match (_, _, pt, targets, _, _) ->
+ CheckDecisionTree (strict st) pt
+ Array.iter (CheckDecisionTreeTarget (strict st)) targets
+ | Expr.App (e1, _, _, args, _) ->
+ CheckExpr (strict st) e1
+ List.iter (CheckExpr (strict st)) args
+ // Binary expressions
+ | Expr.Sequential (e1, e2, _, _, _)
+ | Expr.StaticOptimization (_, e1, e2, _) ->
+ CheckExpr (strict st) e1; CheckExpr (strict st) e2
+ // n-ary expressions
+ | Expr.Op (op, _, args, m) -> CheckExprOp st op m; List.iter (CheckExpr (strict st)) args
+ // misc
+ | Expr.Link eref -> CheckExpr st !eref
+ | Expr.TyChoose (_, b, _) -> CheckExpr st b
+ | Expr.Quote _ -> ()
+ | Expr.WitnessArg (_witnessInfo, _m) -> ()
+
+ and CheckBinding st (TBind(_, e, _)) = CheckExpr st e
+ and CheckDecisionTree st = function
+ | TDSwitch(e1, csl, dflt, _) -> CheckExpr st e1; List.iter (fun (TCase(_, d)) -> CheckDecisionTree st d) csl; Option.iter (CheckDecisionTree st) dflt
+ | TDSuccess (es, _) -> es |> List.iter (CheckExpr st)
+ | TDBind(bind, e) -> CheckBinding st bind; CheckDecisionTree st e
+ and CheckDecisionTreeTarget st (TTarget(_, e, _)) = CheckExpr st e
+
+ and CheckExprOp st op m =
+ match op with
+ | TOp.LValueOp (_, lvr) -> CheckValRef (strict st) lvr m
+ | _ -> ()
+
+ and CheckValRef st (v: ValRef) m =
+ match st with
+ | MaybeLazy ->
+ if recursiveVals.TryFind v.Deref |> Option.isSome then
+ warning (RecursiveUseCheckedAtRuntime (denv, v, m))
+ if not reportedEager then
+ (warning (LetRecCheckedAtRuntime m); reportedEager <- true)
+ runtimeChecks <- true
+
+ | Top | DefinitelyStrict ->
+ if recursiveVals.TryFind v.Deref |> Option.isSome then
+ if availIfInOrder.TryFind v.Deref |> Option.isNone then
+ warning (LetRecEvaluatedOutOfOrder (denv, boundv, v, m))
+ outOfOrder <- true
+ if not reportedEager then
+ (warning (LetRecCheckedAtRuntime m); reportedEager <- true)
+ definiteDependencies <- (boundv, v) :: definiteDependencies
+ | InnerTop ->
+ if recursiveVals.TryFind v.Deref |> Option.isSome then
+ directRecursiveData <- true
+ | DefinitelyLazy -> ()
+ and checkDelayed st b =
+ match st with
+ | MaybeLazy | DefinitelyStrict -> CheckExpr MaybeLazy b
+ | DefinitelyLazy | Top | InnerTop -> ()
+
+
+ CheckExpr Top expr
+
+
+ // Check the bindings one by one, each w.r.t. the previously available set of binding
+ begin
+ let checkBind (pgrbind: PreInitializationGraphEliminationBinding) =
+ let (TBind(v, e, _)) = pgrbind.Binding
+ check (mkLocalValRef v) e
+ availIfInOrder.Add(v, 1)
+ bindings |> iterBindings (List.iter checkBind)
+ end
+
+ // ddg = definiteDependencyGraph
+ let ddgNodes = recursiveVals.Values |> Seq.toList |> List.map mkLocalValRef
+ let ddg = Graph((fun v -> v.Stamp), ddgNodes, definiteDependencies )
+ ddg.IterateCycles (fun path -> error (LetRecUnsound (denv, path, path.Head.Range)))
+
+ let requiresLazyBindings = runtimeChecks || outOfOrder
+ if directRecursiveData && requiresLazyBindings then
+ error(Error(FSComp.SR.tcInvalidMixtureOfRecursiveForms(), bindsm))
+
+ if requiresLazyBindings then
+ let morphBinding (pgrbind: PreInitializationGraphEliminationBinding) =
+ let (RecursiveUseFixupPoints fixupPoints) = pgrbind.FixupPoints
+ let (TBind(v, e, seqPtOpt)) = pgrbind.Binding
+ match stripChooseAndExpr e with
+ | Expr.Lambda _ | Expr.TyLambda _ ->
+ [], [mkInvisibleBind v e]
+ | _ ->
+ let ty = v.Type
+ let m = v.Range
+ let vty = (mkLazyTy g ty)
+
+ let fty = (g.unit_ty --> ty)
+ let flazy, felazy = mkCompGenLocal m v.LogicalName fty
+ let frhs = mkUnitDelayLambda g m e
+ if mustHaveArity then flazy.SetValReprInfo (Some(InferArityOfExpr g AllowTypeDirectedDetupling.Yes fty [] [] frhs))
+
+ let vlazy, velazy = mkCompGenLocal m v.LogicalName vty
+ let vrhs = (mkLazyDelayed g m ty felazy)
+
+ if mustHaveArity then vlazy.SetValReprInfo (Some(InferArityOfExpr g AllowTypeDirectedDetupling.Yes vty [] [] vrhs))
+ fixupPoints |> List.iter (fun (fp, _) -> fp := mkLazyForce g (!fp).Range ty velazy)
+
+ [mkInvisibleBind flazy frhs; mkInvisibleBind vlazy vrhs],
+ [mkBind seqPtOpt v (mkLazyForce g m ty velazy)]
+
+ let newTopBinds = ResizeArray<_>()
+ let morphBindings pgrbinds = pgrbinds |> List.map morphBinding |> List.unzip |> (fun (a, b) -> newTopBinds.Add (List.concat a); List.concat b)
+
+ let res = bindings |> mapBindings morphBindings
+ if newTopBinds.Count = 0 then res
+ else buildLets (List.concat newTopBinds) :: res
+ else
+ let noMorph (pgrbinds: PreInitializationGraphEliminationBinding list) = pgrbinds |> List.map (fun pgrbind -> pgrbind.Binding)
+ bindings |> mapBindings noMorph
+
+//-------------------------------------------------------------------------
+// Check the shape of an object constructor and rewrite calls
+//-------------------------------------------------------------------------
+
+let CheckAndRewriteObjectCtor g env (ctorLambdaExpr: Expr) =
+
+ let m = ctorLambdaExpr.Range
+ let tps, vsl, body, returnTy = stripTopLambda (ctorLambdaExpr, tyOfExpr g ctorLambdaExpr)
+
+ // Rewrite legitimate self-construction calls to CtorValUsedAsSelfInit
+ let error (expr: Expr) =
+ errorR(Error(FSComp.SR.tcInvalidObjectConstructionExpression(), expr.Range))
+ expr
+
+ // Build an assignment into the safeThisValOpt mutable reference cell that holds recursive references to 'this'
+ // Build an assignment into the safeInitInfo mutable field that indicates that partial initialization is successful
+ let rewriteConstruction recdExpr =
+ match env.eCtorInfo with
+ | None -> recdExpr
+ | Some ctorInfo ->
+ let recdExpr =
+ match ctorInfo.safeThisValOpt with
+ | None -> recdExpr
+ | Some safeInitVal ->
+ let ty = tyOfExpr g recdExpr
+ let thisExpr = mkGetArg0 m ty
+ let setExpr = mkRefCellSet g m ty (exprForValRef m (mkLocalValRef safeInitVal)) thisExpr
+ Expr.Sequential (recdExpr, setExpr, ThenDoSeq, DebugPointAtSequential.StmtOnly, m)
+ let recdExpr =
+ match ctorInfo.safeInitInfo with
+ | NoSafeInitInfo -> recdExpr
+ | SafeInitField (rfref, _) ->
+ let thisTy = tyOfExpr g recdExpr
+ let thisExpr = mkGetArg0 m thisTy
+ let thisTyInst = argsOfAppTy g thisTy
+ let setExpr = mkRecdFieldSetViaExprAddr (thisExpr, rfref, thisTyInst, mkOne g m, m)
+ Expr.Sequential (recdExpr, setExpr, ThenDoSeq, DebugPointAtSequential.StmtOnly, m)
+ recdExpr
+
+
+ let rec checkAndRewrite (expr: Expr) =
+ match expr with
+ // = { fields }
+ // The constructor ends in an object initialization expression - good
+ | Expr.Op (TOp.Recd (RecdExprIsObjInit, _), _, _, _) -> rewriteConstruction expr
+
+ // = "a; "
+ | Expr.Sequential (a, body, NormalSeq, spSeq, b) -> Expr.Sequential (a, checkAndRewrite body, NormalSeq, spSeq, b)
+
+ // = " then "
+ | Expr.Sequential (body, a, ThenDoSeq, spSeq, b) -> Expr.Sequential (checkAndRewrite body, a, ThenDoSeq, spSeq, b)
+
+ // = "let pat = expr in "
+ | Expr.Let (bind, body, m, _) -> mkLetBind m bind (checkAndRewrite body)
+
+ // The constructor is a sequence "let pat = expr in "
+ | Expr.Match (spBind, a, b, targets, c, d) -> Expr.Match (spBind, a, b, (targets |> Array.map (fun (TTarget(vs, body, spTarget)) -> TTarget(vs, checkAndRewrite body, spTarget))), c, d)
+
+ // = "let rec binds in "
+ | Expr.LetRec (a, body, _, _) -> Expr.LetRec (a, checkAndRewrite body, m, Construct.NewFreeVarsCache())
+
+ // = "new C(...)"
+ | Expr.App (f, b, c, d, m) ->
+ // The application had better be an application of a ctor
+ let f = checkAndRewriteCtorUsage f
+ let expr = Expr.App (f, b, c, d, m)
+ rewriteConstruction expr
+
+ | _ ->
+ error expr
+
+ and checkAndRewriteCtorUsage expr =
+ match expr with
+ | Expr.Link eref ->
+ let e = checkAndRewriteCtorUsage !eref
+ eref := e
+ expr
+
+ // Type applications are ok, e.g.
+ // type C<'a>(x: int) =
+ // new() = C<'a>(3)
+ | Expr.App (f, fty, tyargs, [], m) ->
+ let f = checkAndRewriteCtorUsage f
+ Expr.App (f, fty, tyargs, [], m)
+
+ // Self-calls are OK and get rewritten.
+ | Expr.Val (vref, NormalValUse, a) ->
+ let isCtor =
+ match vref.MemberInfo with
+ | None -> false
+ | Some memberInfo -> memberInfo.MemberFlags.MemberKind = MemberKind.Constructor
+
+ if not isCtor then
+ error expr
+ else
+ Expr.Val (vref, CtorValUsedAsSelfInit, a)
+ | _ ->
+ error expr
+
+ let body = checkAndRewrite body
+ mkMultiLambdas m tps vsl (body, returnTy)
+
+
+
+/// Post-typechecking normalizations to enforce semantic constraints
+/// lazy and, lazy or, rethrow, address-of
+let buildApp cenv expr resultTy arg m =
+ let g = cenv.g
+ match expr, arg with
+
+ // Special rule for building applications of the 'x && y' operator
+ | ApplicableExpr(_, Expr.App (Expr.Val (vf, _, _), _, _, [x0], _), _), _
+ when valRefEq g vf g.and_vref
+ || valRefEq g vf g.and2_vref ->
+ MakeApplicableExprNoFlex cenv (mkLazyAnd g m x0 arg), resultTy
+
+ // Special rule for building applications of the 'x || y' operator
+ | ApplicableExpr(_, Expr.App (Expr.Val (vf, _, _), _, _, [x0], _), _), _
+ when valRefEq g vf g.or_vref
+ || valRefEq g vf g.or2_vref ->
+ MakeApplicableExprNoFlex cenv (mkLazyOr g m x0 arg ), resultTy
+
+ // Special rule for building applications of the 'reraise' operator
+ | ApplicableExpr(_, Expr.App (Expr.Val (vf, _, _), _, _, [], _), _), _
+ when valRefEq g vf g.reraise_vref ->
+
+ // exprty is of type: "unit -> 'a". Break it and store the 'a type here, used later as return type.
+ MakeApplicableExprNoFlex cenv (mkCompGenSequential m arg (mkReraise m resultTy)), resultTy
+
+ // Special rules for NativePtr.ofByRef to generalize result.
+ // See RFC FS-1053.md
+ | ApplicableExpr(_, Expr.App (Expr.Val (vf, _, _), _, _, [], _), _), _
+ when (valRefEq g vf g.nativeptr_tobyref_vref) ->
+
+ let argty = NewInferenceType()
+ let resultTy = mkByrefTyWithInference g argty (NewByRefKindInferenceType g m)
+ expr.SupplyArgument (arg, m), resultTy
+
+ // Special rules for building applications of the '&expr' operator, which gets the
+ // address of an expression.
+ //
+ // See also RFC FS-1053.md
+ | ApplicableExpr(_, Expr.App (Expr.Val (vf, _, _), _, _, [], _), _), _
+ when valRefEq g vf g.addrof_vref ->
+
+ let wrap, e1a', readonly, _writeonly = mkExprAddrOfExpr g true false AddressOfOp arg (Some vf) m
+ // Assert the result type to be readonly if we couldn't take the address
+ let resultTy =
+ let argTy = tyOfExpr g arg
+ if readonly then
+ mkInByrefTy g argTy
+
+ // "`outref<'T>` types are never introduced implicitly by F#.", see rationale in RFC FS-1053
+ //
+ // We do _not_ introduce outref here, e.g. '&x' where 'x' is outref<_> is _not_ outref.
+ // This effectively makes 'outref<_>' documentation-only. There is frequently a need to pass outref
+ // pointers to .NET library functions whose signatures are not tagged with []
+ //elif writeonly then
+ // mkOutByrefTy g argTy
+
+ else
+ mkByrefTyWithInference g argTy (NewByRefKindInferenceType g m)
+
+ MakeApplicableExprNoFlex cenv (wrap(e1a')), resultTy
+
+ // Special rules for building applications of the &&expr' operators, which gets the
+ // address of an expression.
+ | ApplicableExpr(_, Expr.App (Expr.Val (vf, _, _), _, _, [], _), _), _
+ when valRefEq g vf g.addrof2_vref ->
+
+ warning(UseOfAddressOfOperator m)
+ let wrap, e1a', _readonly, _writeonly = mkExprAddrOfExpr g true false AddressOfOp arg (Some vf) m
+ MakeApplicableExprNoFlex cenv (wrap(e1a')), resultTy
+
+ | _ when isByrefTy g resultTy ->
+ // Handle byref returns, byref-typed returns get implicitly dereferenced
+ let expr = expr.SupplyArgument (arg, m)
+ let expr = mkDerefAddrExpr m expr.Expr m resultTy
+ let resultTy = destByrefTy g resultTy
+ MakeApplicableExprNoFlex cenv expr, resultTy
+
+ | _ ->
+ expr.SupplyArgument (arg, m), resultTy
+
+//-------------------------------------------------------------------------
+// Additional data structures used by type checking
+//-------------------------------------------------------------------------
+
+type DelayedItem =
+ /// DelayedTypeApp (typeArgs, mTypeArgs, mExprAndTypeArgs)
+ ///
+ /// Represents the in "item"
+ | DelayedTypeApp of SynType list * range * range
+
+ /// DelayedApp (isAtomic, argExpr, mFuncAndArg)
+ ///
+ /// Represents the args in "item args", or "item.[args]".
+ | DelayedApp of ExprAtomicFlag * SynExpr * range
+
+ /// Represents the long identifiers in "item.Ident1", or "item.Ident1.Ident2" etc.
+ | DelayedDotLookup of Ident list * range
+
+ /// Represents an incomplete "item."
+ | DelayedDot
+
+ /// Represents the valueExpr in "item <- valueExpr", also "item.[indexerArgs] <- valueExpr" etc.
+ | DelayedSet of SynExpr * range
+
+let MakeDelayedSet(e: SynExpr, m) =
+ // We have longId <- e. Wrap 'e' in another pair of parentheses to ensure it's never interpreted as
+ // a named argument, e.g. for "el.Checked <- (el = el2)"
+ DelayedSet (SynExpr.Paren (e, range0, None, e.Range), m)
+
+/// Indicates if member declarations are allowed to be abstract members.
+type NewSlotsOK =
+ | NewSlotsOK
+ | NoNewSlots
+
+/// Indicates whether a syntactic type is allowed to include new type variables
+/// not declared anywhere, e.g. `let f (x: 'T option) = x.Value`
+type ImplicitlyBoundTyparsAllowed =
+ | NewTyparsOKButWarnIfNotRigid
+ | NewTyparsOK
+ | NoNewTypars
+
+/// Indicates whether constraints should be checked when checking syntactic types
+type CheckConstraints =
+ | CheckCxs
+ | NoCheckCxs
+
+/// Represents information about the module or type in which a member or value is declared.
+type MemberOrValContainerInfo =
+ | MemberOrValContainerInfo of
+ tcref: TyconRef *
+ optIntfSlotTy: (TType * SlotImplSet) option *
+ baseValOpt: Val option *
+ safeInitInfo: SafeInitData *
+ declaredTyconTypars: Typars
+
+/// Provides information about the context for a value or member definition
+type ContainerInfo =
+ | ContainerInfo of
+ // The nearest containing module. Used as the 'actual' parent for extension members and values
+ ParentRef *
+ // For members:
+ MemberOrValContainerInfo option
+ member x.ParentRef =
+ let (ContainerInfo(v, _)) = x
+ v
+
+/// Indicates a declaration is contained in an expression
+let ExprContainerInfo = ContainerInfo(ParentNone, None)
+
+type NormalizedRecBindingDefn =
+ | NormalizedRecBindingDefn of
+ containerInfo: ContainerInfo *
+ newslotsOk: NewSlotsOK *
+ declKind: DeclKind *
+ binding: NormalizedBinding
+
+type ValSpecResult =
+ | ValSpecResult of
+ altActualParent: ParentRef *
+ memberInfoOpt: PreValMemberInfo option *
+ id: Ident *
+ enclosingDeclaredTypars: Typars *
+ declaredTypars: Typars *
+ ty: TType *
+ partialValReprInfo: PartialValReprInfo *
+ declKind: DeclKind
+
+//-------------------------------------------------------------------------
+// Additional data structures used by checking recursive bindings
+//-------------------------------------------------------------------------
+
+type RecDefnBindingInfo =
+ | RecDefnBindingInfo of
+ containerInfo: ContainerInfo *
+ newslotsOk: NewSlotsOK *
+ declKind: DeclKind *
+ synBinding: SynBinding
+
+/// RecursiveBindingInfo - flows through initial steps of TcLetrec
+type RecursiveBindingInfo =
+ | RecursiveBindingInfo of
+ recBindIndex: int * // index of the binding in the recursive group
+ containerInfo: ContainerInfo *
+ enclosingDeclaredTypars: Typars *
+ inlineFlag: ValInline *
+ vspec: Val *
+ explicitTyparInfo: ExplicitTyparInfo *
+ partialValReprInfo: PartialValReprInfo *
+ memberInfoOpt: PreValMemberInfo option *
+ baseValOpt: Val option *
+ safeThisValOpt: Val option *
+ safeInitInfo: SafeInitData *
+ visibility: SynAccess option *
+ ty: TType *
+ declKind: DeclKind
+
+ member x.EnclosingDeclaredTypars = let (RecursiveBindingInfo(_, _, enclosingDeclaredTypars, _, _, _, _, _, _, _, _, _, _, _)) = x in enclosingDeclaredTypars
+ member x.Val = let (RecursiveBindingInfo(_, _, _, _, vspec, _, _, _, _, _, _, _, _, _)) = x in vspec
+ member x.ExplicitTyparInfo = let (RecursiveBindingInfo(_, _, _, _, _, explicitTyparInfo, _, _, _, _, _, _, _, _)) = x in explicitTyparInfo
+ member x.DeclaredTypars = let (ExplicitTyparInfo(_, declaredTypars, _)) = x.ExplicitTyparInfo in declaredTypars
+ member x.Index = let (RecursiveBindingInfo(i, _, _, _, _, _, _, _, _, _, _, _, _, _)) = x in i
+ member x.ContainerInfo = let (RecursiveBindingInfo(_, c, _, _, _, _, _, _, _, _, _, _, _, _)) = x in c
+ member x.DeclKind = let (RecursiveBindingInfo(_, _, _, _, _, _, _, _, _, _, _, _, _, declKind)) = x in declKind
+
+type PreCheckingRecursiveBinding =
+ { SyntacticBinding: NormalizedBinding
+ RecBindingInfo: RecursiveBindingInfo }
+
+type PreGeneralizationRecursiveBinding =
+ { ExtraGeneralizableTypars: Typars
+ CheckedBinding: CheckedBindingInfo
+ RecBindingInfo: RecursiveBindingInfo }
+
+type PostGeneralizationRecursiveBinding =
+ { ValScheme: ValScheme
+ CheckedBinding: CheckedBindingInfo
+ RecBindingInfo: RecursiveBindingInfo }
+ member x.GeneralizedTypars = x.ValScheme.GeneralizedTypars
+
+type PostSpecialValsRecursiveBinding =
+ { ValScheme: ValScheme
+ Binding: Binding }
+
+let CanInferExtraGeneralizedTyparsForRecBinding (pgrbind: PreGeneralizationRecursiveBinding) =
+ let explicitTyparInfo = pgrbind.RecBindingInfo.ExplicitTyparInfo
+ let (ExplicitTyparInfo(_, _, canInferTypars)) = explicitTyparInfo
+ let memFlagsOpt = pgrbind.RecBindingInfo.Val.MemberInfo |> Option.map (fun memInfo -> memInfo.MemberFlags)
+ let canInferTypars = GeneralizationHelpers.ComputeCanInferExtraGeneralizableTypars (pgrbind.RecBindingInfo.ContainerInfo.ParentRef, canInferTypars, memFlagsOpt)
+ canInferTypars
+
+/// Get the "this" variable from an instance member binding
+let GetInstanceMemberThisVariable (vspec: Val, expr) =
+ // Skip over LAM tps. Choose 'a.
+ if vspec.IsInstanceMember then
+ let rec firstArg e =
+ match e with
+ | Expr.TyLambda (_, _, b, _, _) -> firstArg b
+ | Expr.TyChoose (_, b, _) -> firstArg b
+ | Expr.Lambda (_, _, _, [v], _, _, _) -> Some v
+ | _ -> failwith "GetInstanceMemberThisVariable: instance member did not have expected internal form"
+
+ firstArg expr
+ else
+ None
+
+//-------------------------------------------------------------------------
+// Checking types and type constraints
+//-------------------------------------------------------------------------
+/// Check specifications of constraints on type parameters
+let rec TcTyparConstraint ridx cenv newOk checkCxs occ (env: TcEnv) tpenv c =
+ let checkSimpleConstraint tp m constraintAdder =
+ let tp', tpenv = TcTypar cenv env newOk tpenv tp
+ constraintAdder env.DisplayEnv cenv.css m NoTrace (mkTyparTy tp')
+ tpenv
+
+ match c with
+ | WhereTyparDefaultsToType(tp, ty, m) ->
+ let ty', tpenv = TcTypeAndRecover cenv newOk checkCxs occ env tpenv ty
+ let tp', tpenv = TcTypar cenv env newOk tpenv tp
+ AddCxTyparDefaultsTo env.DisplayEnv cenv.css m env.eContextInfo tp' ridx ty'
+ tpenv
+
+ | WhereTyparSubtypeOfType(tp, ty, m) ->
+ let ty', tpenv = TcTypeAndRecover cenv newOk checkCxs ItemOccurence.UseInType env tpenv ty
+ let tp', tpenv = TcTypar cenv env newOk tpenv tp
+ if newOk = NoNewTypars && isSealedTy cenv.g ty' then
+ errorR(Error(FSComp.SR.tcInvalidConstraintTypeSealed(), m))
+ AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace ty' (mkTyparTy tp')
+ tpenv
+
+ | WhereTyparSupportsNull(tp, m) -> checkSimpleConstraint tp m AddCxTypeMustSupportNull
+
+ | WhereTyparIsComparable(tp, m) -> checkSimpleConstraint tp m AddCxTypeMustSupportComparison
+
+ | WhereTyparIsEquatable(tp, m) -> checkSimpleConstraint tp m AddCxTypeMustSupportEquality
+
+ | WhereTyparIsReferenceType(tp, m) -> checkSimpleConstraint tp m AddCxTypeIsReferenceType
+
+ | WhereTyparIsValueType(tp, m) -> checkSimpleConstraint tp m AddCxTypeIsValueType
+
+ | WhereTyparIsUnmanaged(tp, m) -> checkSimpleConstraint tp m AddCxTypeIsUnmanaged
+
+ | WhereTyparIsEnum(tp, tyargs, m) ->
+ let tp', tpenv = TcTypar cenv env newOk tpenv tp
+ let tpenv =
+ match tyargs with
+ | [underlying] ->
+ let underlying', tpenv = TcTypeAndRecover cenv newOk checkCxs ItemOccurence.UseInType env tpenv underlying
+ AddCxTypeIsEnum env.DisplayEnv cenv.css m NoTrace (mkTyparTy tp') underlying'
+ tpenv
+ | _ ->
+ errorR(Error(FSComp.SR.tcInvalidEnumConstraint(), m))
+ tpenv
+ tpenv
+
+ | WhereTyparIsDelegate(tp, tyargs, m) ->
+ let tp', tpenv = TcTypar cenv env newOk tpenv tp
+ match tyargs with
+ | [a;b] ->
+ let a', tpenv = TcTypeAndRecover cenv newOk checkCxs occ env tpenv a
+ let b', tpenv = TcTypeAndRecover cenv newOk checkCxs occ env tpenv b
+ AddCxTypeIsDelegate env.DisplayEnv cenv.css m NoTrace (mkTyparTy tp') a' b'
+ tpenv
+ | _ ->
+ errorR(Error(FSComp.SR.tcInvalidEnumConstraint(), m))
+ tpenv
+
+ | WhereTyparSupportsMember(tps, memSpfn, m) ->
+ let traitInfo, tpenv = TcPseudoMemberSpec cenv newOk env tps tpenv memSpfn m
+ match traitInfo with
+ | TTrait(objtys, ".ctor", memberFlags, argTys, returnTy, _) when memberFlags.MemberKind = MemberKind.Constructor ->
+ match objtys, argTys with
+ | [ty], [] when typeEquiv cenv.g ty (GetFSharpViewOfReturnType cenv.g returnTy) ->
+ AddCxTypeMustSupportDefaultCtor env.DisplayEnv cenv.css m NoTrace ty
+ tpenv
+ | _ ->
+ errorR(Error(FSComp.SR.tcInvalidNewConstraint(), m))
+ tpenv
+ | _ ->
+ AddCxMethodConstraint env.DisplayEnv cenv.css m NoTrace traitInfo
+ tpenv
+
+and TcPseudoMemberSpec cenv newOk env synTypes tpenv memSpfn m =
+#if ALLOW_MEMBER_CONSTRAINTS_ON_MEASURES
+ let tps, tpenv = List.mapFold (TcTyparOrMeasurePar None cenv env newOk) tpenv synTypars
+#else
+ let tys, tpenv = List.mapFold (TcTypeAndRecover cenv newOk CheckCxs ItemOccurence.UseInType env) tpenv synTypes
+#endif
+ match memSpfn with
+ | SynMemberSig.Member (valSpfn, memberFlags, m) ->
+ // REVIEW: Test pseudo constraints cannot refer to polymorphic methods.
+ // REVIEW: Test pseudo constraints cannot be curried.
+ let members, tpenv = TcValSpec cenv env ModuleOrMemberBinding newOk ExprContainerInfo (Some memberFlags) (Some (List.head tys)) tpenv valSpfn []
+ match members with
+ | [ValSpecResult(_, _, id, _, _, memberConstraintTy, partialValReprInfo, _)] ->
+ let memberConstraintTypars, _ = tryDestForallTy cenv.g memberConstraintTy
+ let topValInfo = TranslatePartialArity memberConstraintTypars partialValReprInfo
+ let _, _, curriedArgInfos, returnTy, _ = GetTopValTypeInCompiledForm cenv.g topValInfo 0 memberConstraintTy m
+ //if curriedArgInfos.Length > 1 then error(Error(FSComp.SR.tcInvalidConstraint(), m))
+ let argTys = List.concat curriedArgInfos
+ let argTys = List.map fst argTys
+ let logicalCompiledName = ComputeLogicalName id memberFlags
+
+ let item = Item.ArgName (id, memberConstraintTy, None)
+ CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.AccessRights)
+
+ TTrait(tys, logicalCompiledName, memberFlags, argTys, returnTy, ref None), tpenv
+ | _ -> error(Error(FSComp.SR.tcInvalidConstraint(), m))
+ | _ -> error(Error(FSComp.SR.tcInvalidConstraint(), m))
+
+
+/// Check a value specification, e.g. in a signature, interface declaration or a constraint
+and TcValSpec cenv env declKind newOk containerInfo memFlagsOpt thisTyOpt tpenv valSpfn attrs =
+ let (ValSpfn(_, id, SynValTyparDecls(synTypars, _, synTyparConstraints), ty, valSynInfo, _, _, _, _, _, m)) = valSpfn
+ let declaredTypars = TcTyparDecls cenv env synTypars
+ let (ContainerInfo(altActualParent, tcrefContainerInfo)) = containerInfo
+ let enclosingDeclaredTypars, memberContainerInfo, thisTyOpt, declKind =
+ match tcrefContainerInfo with
+ | Some(MemberOrValContainerInfo(tcref, _, _, _, declaredTyconTypars)) ->
+ let isExtrinsic = (declKind = ExtrinsicExtensionBinding)
+ let _, enclosingDeclaredTypars, _, _, thisTy = FreshenObjectArgType cenv m TyparRigidity.Rigid tcref isExtrinsic declaredTyconTypars
+ // An implemented interface type is in terms of the type's type parameters.
+ // We need a signature in terms of the values' type parameters.
+ // let optIntfSlotTy = Option.map (instType renaming) optIntfSlotTy in
+ enclosingDeclaredTypars, Some tcref, Some thisTy, declKind
+ | None ->
+ [], None, thisTyOpt, ModuleOrMemberBinding
+ let allDeclaredTypars = enclosingDeclaredTypars @ declaredTypars
+ let envinner = AddDeclaredTypars NoCheckForDuplicateTypars allDeclaredTypars env
+ let checkCxs = CheckCxs
+ let tpenv = TcTyparConstraints cenv newOk checkCxs ItemOccurence.UseInType envinner tpenv synTyparConstraints
+
+ // Treat constraints at the "end" of the type as if they are declared.
+ // This is by far the most convenient place to locate the constraints.
+ // e.g.
+ // val FastGenericComparer<'T>: IComparer<'T> when 'T: comparison
+ let tpenv =
+ match ty with
+ | SynType.WithGlobalConstraints(_, wcs, _) ->
+ TcTyparConstraints cenv newOk checkCxs ItemOccurence.UseInType envinner tpenv wcs
+ | _ ->
+ tpenv
+
+ // Enforce "no undeclared constraints allowed on declared typars"
+ allDeclaredTypars |> List.iter (SetTyparRigid env.DisplayEnv m)
+ // Process the type, including any constraints
+ let declaredTy, tpenv = TcTypeAndRecover cenv newOk checkCxs ItemOccurence.UseInType envinner tpenv ty
+
+ match memFlagsOpt, thisTyOpt with
+ | Some memberFlags, Some thisTy ->
+ let generateOneMember memberFlags =
+
+ // Decode members in the signature
+ let ty', valSynInfo =
+ match memberFlags.MemberKind with
+ | MemberKind.ClassConstructor
+ | MemberKind.Constructor
+ | MemberKind.Member ->
+ declaredTy, valSynInfo
+ | MemberKind.PropertyGet
+ | MemberKind.PropertySet ->
+ let fakeArgReprInfos = [ for n in SynInfo.AritiesOfArgs valSynInfo do yield [ for _ in 1 .. n do yield ValReprInfo.unnamedTopArg1 ] ]
+ let arginfos, returnTy = GetTopTauTypeInFSharpForm cenv.g fakeArgReprInfos declaredTy m
+ if arginfos.Length > 1 then error(Error(FSComp.SR.tcInvalidPropertyType(), m))
+ match memberFlags.MemberKind with
+ | MemberKind.PropertyGet ->
+ if SynInfo.HasNoArgs valSynInfo then
+ (cenv.g.unit_ty --> declaredTy), (SynInfo.IncorporateEmptyTupledArgForPropertyGetter valSynInfo)
+ else
+ declaredTy, valSynInfo
+ | _ ->
+ let setterTy = (mkRefTupledTy cenv.g (List.map fst (List.concat arginfos) @ [returnTy]) --> cenv.g.unit_ty)
+ let synInfo = SynInfo.IncorporateSetterArg valSynInfo
+ setterTy, synInfo
+ | MemberKind.PropertyGetSet ->
+ error(InternalError("Unexpected MemberKind.PropertyGetSet from signature parsing", m))
+
+ // Take "unit" into account in the signature
+ let valSynInfo = AdjustValSynInfoInSignature cenv.g ty' valSynInfo
+
+ let ty', valSynInfo =
+ if memberFlags.IsInstance then
+ (thisTy --> ty'), (SynInfo.IncorporateSelfArg valSynInfo)
+ else
+ ty', valSynInfo
+
+ let reallyGenerateOneMember(id: Ident, valSynInfo, ty', memberFlags) =
+ let (PartialValReprInfo(argsData, _)) as partialValReprInfo =
+ TranslateTopValSynInfo id.idRange (TcAttributes cenv env) valSynInfo
+
+
+ // Fold in the optional argument information
+ // Resort to using the syntactic argument information since that is what tells us
+ // what is optional and what is not.
+ let ty' =
+
+ if SynInfo.HasOptionalArgs valSynInfo then
+ let curriedArgTys, returnTy = GetTopTauTypeInFSharpForm cenv.g argsData ty' m
+ let curriedArgTys =
+ (List.zip (List.mapSquared fst curriedArgTys) valSynInfo.CurriedArgInfos)
+ |> List.map (fun (argTys, argInfos) ->
+ (List.zip argTys argInfos)
+ |> List.map (fun (argty, argInfo) ->
+ if SynInfo.IsOptionalArg argInfo then mkOptionTy cenv.g argty
+ else argty))
+ mkIteratedFunTy (List.map (mkRefTupledTy cenv.g) curriedArgTys) returnTy
+ else ty'
+
+ let memberInfoOpt =
+ match memberContainerInfo with
+ | Some tcref ->
+ let isExtrinsic = (declKind = ExtrinsicExtensionBinding)
+ let memberInfoTransient = MakeMemberDataAndMangledNameForMemberVal(cenv.g, tcref, isExtrinsic, attrs, [], memberFlags, valSynInfo, id, false)
+ Some memberInfoTransient
+ | None ->
+ None
+
+ ValSpecResult(altActualParent, memberInfoOpt, id, enclosingDeclaredTypars, declaredTypars, ty', partialValReprInfo, declKind)
+
+ [ yield reallyGenerateOneMember(id, valSynInfo, ty', memberFlags)
+ if CompileAsEvent cenv.g attrs then
+ let valSynInfo = EventDeclarationNormalization.ConvertSynInfo id.idRange valSynInfo
+ let memberFlags = EventDeclarationNormalization.ConvertMemberFlags memberFlags
+ let delTy = FindDelegateTypeOfPropertyEvent cenv.g cenv.amap id.idText id.idRange declaredTy
+ let ty =
+ if memberFlags.IsInstance then
+ thisTy --> (delTy --> cenv.g.unit_ty)
+ else
+ (delTy --> cenv.g.unit_ty)
+ yield reallyGenerateOneMember(ident("add_" + id.idText, id.idRange), valSynInfo, ty, memberFlags)
+ yield reallyGenerateOneMember(ident("remove_" + id.idText, id.idRange), valSynInfo, ty, memberFlags) ]
+
+
+
+ match memberFlags.MemberKind with
+ | MemberKind.ClassConstructor
+ | MemberKind.Constructor
+ | MemberKind.Member
+ | MemberKind.PropertyGet
+ | MemberKind.PropertySet ->
+ generateOneMember memberFlags, tpenv
+ | MemberKind.PropertyGetSet ->
+ [ yield! generateOneMember({memberFlags with MemberKind=MemberKind.PropertyGet})
+ yield! generateOneMember({memberFlags with MemberKind=MemberKind.PropertySet}) ], tpenv
+ | _ ->
+ let valSynInfo = AdjustValSynInfoInSignature cenv.g declaredTy valSynInfo
+ let partialValReprInfo = TranslateTopValSynInfo id.idRange (TcAttributes cenv env) valSynInfo
+ [ ValSpecResult(altActualParent, None, id, enclosingDeclaredTypars, declaredTypars, declaredTy, partialValReprInfo, declKind) ], tpenv
+
+//-------------------------------------------------------------------------
+// Bind types
+//-------------------------------------------------------------------------
+
+/// Check and elaborate a type or measure parameter occurrence
+/// If optKind=Some kind, then this is the kind we're expecting (we're in *analysis* mode)
+/// If optKind=None, we need to determine the kind (we're in *synthesis* mode)
+///
+and TcTyparOrMeasurePar optKind cenv (env: TcEnv) newOk tpenv (Typar(id, _, _) as tp) =
+ let checkRes (res: Typar) =
+ match optKind, res.Kind with
+ | Some TyparKind.Measure, TyparKind.Type -> error (Error(FSComp.SR.tcExpectedUnitOfMeasureMarkWithAttribute(), id.idRange)); res, tpenv
+ | Some TyparKind.Type, TyparKind.Measure -> error (Error(FSComp.SR.tcExpectedTypeParameter(), id.idRange)); res, tpenv
+ | _, _ ->
+ let item = Item.TypeVar(id.idText, res)
+ CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.UseInType, env.AccessRights)
+ res, tpenv
+ let key = id.idText
+ match env.eNameResEnv.eTypars.TryGetValue key with
+ | true, res -> checkRes res
+ | _ ->
+ match TryFindUnscopedTypar key tpenv with
+ | Some res -> checkRes res
+ | None ->
+ if newOk = NoNewTypars then
+ let suggestTypeParameters (addToBuffer: string -> unit) =
+ for p in env.eNameResEnv.eTypars do
+ addToBuffer ("'" + p.Key)
+
+ match tpenv with
+ | UnscopedTyparEnv elements ->
+ for p in elements do
+ addToBuffer ("'" + p.Key)
+
+ let reportedId = Ident("'" + id.idText, id.idRange)
+ error (UndefinedName(0, FSComp.SR.undefinedNameTypeParameter, reportedId, suggestTypeParameters))
+
+ // OK, this is an implicit declaration of a type parameter
+ // The kind defaults to Type
+ let kind = match optKind with None -> TyparKind.Type | Some kind -> kind
+ let tp' = Construct.NewTypar (kind, TyparRigidity.WarnIfNotRigid, tp, false, TyparDynamicReq.Yes, [], false, false)
+ let item = Item.TypeVar(id.idText, tp')
+ CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.UseInType, env.AccessRights)
+ tp', AddUnscopedTypar key tp' tpenv
+
+and TcTypar cenv env newOk tpenv tp =
+ TcTyparOrMeasurePar (Some TyparKind.Type) cenv env newOk tpenv tp
+
+and TcTyparDecl cenv env (TyparDecl(Attributes synAttrs, (Typar(id, _, _) as stp))) =
+ let attrs = TcAttributes cenv env AttributeTargets.GenericParameter synAttrs
+ let hasMeasureAttr = HasFSharpAttribute cenv.g cenv.g.attrib_MeasureAttribute attrs
+ let hasEqDepAttr = HasFSharpAttribute cenv.g cenv.g.attrib_EqualityConditionalOnAttribute attrs
+ let hasCompDepAttr = HasFSharpAttribute cenv.g cenv.g.attrib_ComparisonConditionalOnAttribute attrs
+ let attrs = attrs |> List.filter (IsMatchingFSharpAttribute cenv.g cenv.g.attrib_MeasureAttribute >> not)
+ let kind = if hasMeasureAttr then TyparKind.Measure else TyparKind.Type
+ let tp = Construct.NewTypar (kind, TyparRigidity.WarnIfNotRigid, stp, false, TyparDynamicReq.Yes, attrs, hasEqDepAttr, hasCompDepAttr)
+ match TryFindFSharpStringAttribute cenv.g cenv.g.attrib_CompiledNameAttribute attrs with
+ | Some compiledName ->
+ tp.SetILName (Some compiledName)
+ | None ->
+ ()
+ let item = Item.TypeVar(id.idText, tp)
+ CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.UseInType, env.eAccessRights)
+ tp
+
+
+and TcTyparDecls cenv env synTypars = List.map (TcTyparDecl cenv env) synTypars
+
+/// Check and elaborate a syntactic type or measure
+/// If optKind=Some kind, then this is the kind we're expecting (we're in *analysis* mode)
+/// If optKind=None, we need to determine the kind (we're in *synthesis* mode)
+///
+and TcTypeOrMeasure optKind cenv newOk checkCxs occ env (tpenv: UnscopedTyparEnv) ty =
+ let g = cenv.g
+
+ match ty with
+ | SynType.LongIdent(LongIdentWithDots([], _)) ->
+ // special case when type name is absent - i.e. empty inherit part in type declaration
+ g.obj_ty, tpenv
+
+ | SynType.LongIdent(LongIdentWithDots(tc, _) as lidwd) ->
+ let m = lidwd.Range
+ let ad = env.eAccessRights
+ let tinstEnclosing, tcref = ForceRaise(ResolveTypeLongIdent cenv.tcSink cenv.nameResolver occ OpenQualified env.NameEnv ad tc TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.No)
+ match optKind, tcref.TypeOrMeasureKind with
+ | Some TyparKind.Type, TyparKind.Measure ->
+ error(Error(FSComp.SR.tcExpectedTypeNotUnitOfMeasure(), m))
+ NewErrorType (), tpenv
+ | Some TyparKind.Measure, TyparKind.Type ->
+ error(Error(FSComp.SR.tcExpectedUnitOfMeasureNotType(), m))
+ TType_measure (NewErrorMeasure ()), tpenv
+ | _, TyparKind.Measure ->
+ TType_measure (Measure.Con tcref), tpenv
+ | _, TyparKind.Type ->
+ TcTypeApp cenv newOk checkCxs occ env tpenv m tcref tinstEnclosing []
+
+ | SynType.App (StripParenTypes (SynType.LongIdent(LongIdentWithDots(tc, _))), _, args, _commas, _, postfix, m) ->
+ let ad = env.eAccessRights
+
+ let tinstEnclosing, tcref =
+ let tyResInfo = TypeNameResolutionStaticArgsInfo.FromTyArgs args.Length
+ ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.UseInType OpenQualified env.eNameResEnv ad tc tyResInfo PermitDirectReferenceToGeneratedType.No
+ |> ForceRaise
+
+ match optKind, tcref.TypeOrMeasureKind with
+ | Some TyparKind.Type, TyparKind.Measure ->
+ error(Error(FSComp.SR.tcExpectedTypeNotUnitOfMeasure(), m))
+ NewErrorType (), tpenv
+
+ | Some TyparKind.Measure, TyparKind.Type ->
+ error(Error(FSComp.SR.tcExpectedUnitOfMeasureNotType(), m))
+ TType_measure (NewErrorMeasure ()), tpenv
+
+ | _, TyparKind.Type ->
+ if postfix && tcref.Typars m |> List.exists (fun tp -> match tp.Kind with TyparKind.Measure -> true | _ -> false)
+ then error(Error(FSComp.SR.tcInvalidUnitsOfMeasurePrefix(), m))
+ TcTypeApp cenv newOk checkCxs occ env tpenv m tcref tinstEnclosing args
+ | _, TyparKind.Measure ->
+ match args, postfix with
+ | [arg], true ->
+ let ms, tpenv = TcMeasure cenv newOk checkCxs occ env tpenv arg m
+ TType_measure (Measure.Prod(Measure.Con tcref, ms)), tpenv
+
+ | _, _ ->
+ errorR(Error(FSComp.SR.tcUnitsOfMeasureInvalidInTypeConstructor(), m))
+ NewErrorType (), tpenv
+
+ | SynType.LongIdentApp (ltyp, LongIdentWithDots(longId, _), _, args, _commas, _, m) ->
+ let ad = env.eAccessRights
+ let ltyp, tpenv = TcType cenv newOk checkCxs occ env tpenv ltyp
+ match ltyp with
+ | AppTy g (tcref, tinst) ->
+ let tcref = ResolveTypeLongIdentInTyconRef cenv.tcSink cenv.nameResolver env.eNameResEnv (TypeNameResolutionInfo.ResolveToTypeRefs (TypeNameResolutionStaticArgsInfo.FromTyArgs args.Length)) ad m tcref longId
+ TcTypeApp cenv newOk checkCxs occ env tpenv m tcref tinst args
+ | _ -> error(Error(FSComp.SR.tcTypeHasNoNestedTypes(), m))
+
+ | SynType.Tuple(isStruct, args, m) ->
+ let tupInfo = mkTupInfo isStruct
+ if isStruct then
+ let args',tpenv = TcTypesAsTuple cenv newOk checkCxs occ env tpenv args m
+ TType_tuple(tupInfo,args'),tpenv
+ else
+ let isMeasure = match optKind with Some TyparKind.Measure -> true | None -> List.exists (fun (isquot,_) -> isquot) args | _ -> false
+ if isMeasure then
+ let ms,tpenv = TcMeasuresAsTuple cenv newOk checkCxs occ env tpenv args m
+ TType_measure ms,tpenv
+ else
+ let args',tpenv = TcTypesAsTuple cenv newOk checkCxs occ env tpenv args m
+ TType_tuple(tupInfo,args'),tpenv
+
+ | SynType.AnonRecd(_, [],m) ->
+ error(Error((FSComp.SR.tcAnonymousTypeInvalidInDeclaration()), m))
+
+ | SynType.AnonRecd(isStruct, args,m) ->
+ let tupInfo = mkTupInfo isStruct
+ let args',tpenv = TcTypesAsTuple cenv newOk checkCxs occ env tpenv (args |> List.map snd |> List.map (fun x -> (false,x))) m
+ let unsortedFieldIds = args |> List.map fst |> List.toArray
+ let anonInfo = AnonRecdTypeInfo.Create(cenv.topCcu, tupInfo, unsortedFieldIds)
+ // Sort into canonical order
+ let sortedFieldTys, sortedCheckedArgTys = List.zip args args' |> List.indexed |> List.sortBy (fun (i,_) -> unsortedFieldIds.[i].idText) |> List.map snd |> List.unzip
+ sortedFieldTys |> List.iteri (fun i (x,_) ->
+ let item = Item.AnonRecdField(anonInfo, sortedCheckedArgTys, i, x.idRange)
+ CallNameResolutionSink cenv.tcSink (x.idRange,env.NameEnv,item,emptyTyparInst,ItemOccurence.UseInType,env.eAccessRights))
+ TType_anon(anonInfo, sortedCheckedArgTys),tpenv
+
+ | SynType.Fun(domainTy, resultTy, _) ->
+ let domainTy', tpenv = TcTypeAndRecover cenv newOk checkCxs occ env tpenv domainTy
+ let resultTy', tpenv = TcTypeAndRecover cenv newOk checkCxs occ env tpenv resultTy
+ (domainTy' --> resultTy'), tpenv
+
+ | SynType.Array (n, elemTy, m) ->
+ let elemTy, tpenv = TcTypeAndRecover cenv newOk checkCxs occ env tpenv elemTy
+ mkArrayTy g n elemTy m, tpenv
+
+ | SynType.Var (tp, _) ->
+ let tp', tpenv = TcTyparOrMeasurePar optKind cenv env newOk tpenv tp
+ match tp'.Kind with
+ | TyparKind.Measure -> TType_measure (Measure.Var tp'), tpenv
+ | TyparKind.Type -> mkTyparTy tp', tpenv
+
+ // _ types
+ | SynType.Anon m ->
+ let tp: Typar = TcAnonTypeOrMeasure optKind cenv TyparRigidity.Anon TyparDynamicReq.No newOk m
+ match tp.Kind with
+ | TyparKind.Measure -> TType_measure (Measure.Var tp), tpenv
+ | TyparKind.Type -> mkTyparTy tp, tpenv
+
+ | SynType.WithGlobalConstraints(ty, wcs, _) ->
+ let cty, tpenv = TcTypeAndRecover cenv newOk checkCxs occ env tpenv ty
+ let tpenv = TcTyparConstraints cenv newOk checkCxs occ env tpenv wcs
+ cty, tpenv
+
+ // #typ
+ | SynType.HashConstraint(ty, m) ->
+ let tp = TcAnonTypeOrMeasure (Some TyparKind.Type) cenv TyparRigidity.WarnIfNotRigid TyparDynamicReq.Yes newOk m
+ let ty', tpenv = TcTypeAndRecover cenv newOk checkCxs occ env tpenv ty
+ AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace ty' (mkTyparTy tp)
+ tp.AsType, tpenv
+
+ | SynType.StaticConstant (c, m) ->
+ match c, optKind with
+ | _, Some TyparKind.Type ->
+ errorR(Error(FSComp.SR.parsInvalidLiteralInType(), m))
+ NewErrorType (), tpenv
+ | SynConst.Int32 1, _ ->
+ TType_measure Measure.One, tpenv
+ | _ ->
+ errorR(Error(FSComp.SR.parsInvalidLiteralInType(), m))
+ NewErrorType (), tpenv
+
+ | SynType.StaticConstantNamed (_, _, m)
+
+ | SynType.StaticConstantExpr (_, m) ->
+ errorR(Error(FSComp.SR.parsInvalidLiteralInType(), m))
+ NewErrorType (), tpenv
+
+ | SynType.MeasurePower(ty, exponent, m) ->
+ match optKind with
+ | Some TyparKind.Type ->
+ errorR(Error(FSComp.SR.tcUnexpectedSymbolInTypeExpression("^"), m))
+ NewErrorType (), tpenv
+ | _ ->
+ let ms, tpenv = TcMeasure cenv newOk checkCxs occ env tpenv ty m
+ TType_measure (Measure.RationalPower (ms, TcSynRationalConst exponent)), tpenv
+
+ | SynType.MeasureDivide(typ1, typ2, m) ->
+ match optKind with
+ | Some TyparKind.Type ->
+ errorR(Error(FSComp.SR.tcUnexpectedSymbolInTypeExpression("/"), m))
+ NewErrorType (), tpenv
+ | _ ->
+ let ms1, tpenv = TcMeasure cenv newOk checkCxs occ env tpenv typ1 m
+ let ms2, tpenv = TcMeasure cenv newOk checkCxs occ env tpenv typ2 m
+ TType_measure (Measure.Prod(ms1, Measure.Inv ms2)), tpenv
+
+ | SynType.App(StripParenTypes (SynType.Var(_, m1) | (SynType.MeasurePower(_, _, m1))) as arg1, _, args, _commas, _, postfix, m) ->
+ match optKind, args, postfix with
+ | (None | Some TyparKind.Measure), [arg2], true ->
+ let ms1, tpenv = TcMeasure cenv newOk checkCxs occ env tpenv arg1 m1
+ let ms2, tpenv = TcMeasure cenv newOk checkCxs occ env tpenv arg2 m
+ TType_measure (Measure.Prod(ms1, ms2)), tpenv
+
+ | _ ->
+ errorR(Error(FSComp.SR.tcTypeParameterInvalidAsTypeConstructor(), m))
+ NewErrorType (), tpenv
+
+ | SynType.App(_, _, _, _, _, _, m) ->
+ errorR(Error(FSComp.SR.tcIllegalSyntaxInTypeExpression(), m))
+ NewErrorType (), tpenv
+
+ | SynType.Paren(innerType, _) ->
+ TcTypeOrMeasure optKind cenv newOk checkCxs occ env (tpenv: UnscopedTyparEnv) innerType
+
+and TcType cenv newOk checkCxs occ env (tpenv: UnscopedTyparEnv) ty =
+ TcTypeOrMeasure (Some TyparKind.Type) cenv newOk checkCxs occ env tpenv ty
+
+and TcMeasure cenv newOk checkCxs occ env (tpenv: UnscopedTyparEnv) (StripParenTypes ty) m =
+ match ty with
+ | SynType.Anon m ->
+ error(Error(FSComp.SR.tcAnonymousUnitsOfMeasureCannotBeNested(), m))
+ NewErrorMeasure (), tpenv
+ | _ ->
+ match TcTypeOrMeasure (Some TyparKind.Measure) cenv newOk checkCxs occ env tpenv ty with
+ | TType_measure ms, tpenv -> ms, tpenv
+ | _ ->
+ error(Error(FSComp.SR.tcExpectedUnitOfMeasureNotType(), m))
+ NewErrorMeasure (), tpenv
+
+and TcAnonTypeOrMeasure optKind _cenv rigid dyn newOk m =
+ if newOk = NoNewTypars then errorR (Error(FSComp.SR.tcAnonymousTypeInvalidInDeclaration(), m))
+ let rigid = (if rigid = TyparRigidity.Anon && newOk = NewTyparsOKButWarnIfNotRigid then TyparRigidity.WarnIfNotRigid else rigid)
+ let kind = match optKind with Some TyparKind.Measure -> TyparKind.Measure | _ -> TyparKind.Type
+ NewAnonTypar (kind, m, rigid, NoStaticReq, dyn)
+
+and TcTypes cenv newOk checkCxs occ env tpenv args =
+ List.mapFold (TcTypeAndRecover cenv newOk checkCxs occ env) tpenv args
+
+and TcTypesAsTuple cenv newOk checkCxs occ env tpenv args m =
+ match args with
+ | [] -> error(InternalError("empty tuple type", m))
+ | [(_, ty)] -> let ty, tpenv = TcTypeAndRecover cenv newOk checkCxs occ env tpenv ty in [ty], tpenv
+ | (isquot, ty) :: args ->
+ let ty, tpenv = TcTypeAndRecover cenv newOk checkCxs occ env tpenv ty
+ let tys, tpenv = TcTypesAsTuple cenv newOk checkCxs occ env tpenv args m
+ if isquot then errorR(Error(FSComp.SR.tcUnexpectedSlashInType(), m))
+ ty :: tys, tpenv
+
+// Type-check a list of measures separated by juxtaposition, * or /
+and TcMeasuresAsTuple cenv newOk checkCxs occ env (tpenv: UnscopedTyparEnv) args m =
+ let rec gather args tpenv isquot acc =
+ match args with
+ | [] -> acc, tpenv
+ | (nextisquot, ty) :: args ->
+ let ms1, tpenv = TcMeasure cenv newOk checkCxs occ env tpenv ty m
+ gather args tpenv nextisquot (if isquot then Measure.Prod(acc, Measure.Inv ms1) else Measure.Prod(acc, ms1))
+ gather args tpenv false Measure.One
+
+and TcTypesOrMeasures optKinds cenv newOk checkCxs occ env tpenv args m =
+ match optKinds with
+ | None ->
+ List.mapFold (TcTypeOrMeasure None cenv newOk checkCxs occ env) tpenv args
+ | Some kinds ->
+ if List.length kinds = List.length args then
+ List.mapFold (fun tpenv (arg, kind) -> TcTypeOrMeasure (Some kind) cenv newOk checkCxs occ env tpenv arg) tpenv (List.zip args kinds)
+ elif isNil kinds then error(Error(FSComp.SR.tcUnexpectedTypeArguments(), m))
+ else error(Error(FSComp.SR.tcTypeParameterArityMismatch((List.length kinds), (List.length args)), m))
+
+and TcTyparConstraints cenv newOk checkCxs occ env tpenv synConstraints =
+ // Mark up default constraints with a priority in reverse order: last gets 0, second
+ // last gets 1 etc. See comment on TyparConstraint.DefaultsTo
+ let _, tpenv = List.fold (fun (ridx, tpenv) tc -> ridx - 1, TcTyparConstraint ridx cenv newOk checkCxs occ env tpenv tc) (List.length synConstraints - 1, tpenv) synConstraints
+ tpenv
+
+#if !NO_EXTENSIONTYPING
+and TcStaticConstantParameter cenv (env: TcEnv) tpenv kind (StripParenTypes v) idOpt container =
+ let g = cenv.g
+ let fail() = error(Error(FSComp.SR.etInvalidStaticArgument(NicePrint.minimalStringOfType env.DisplayEnv kind), v.Range))
+ let record ttype =
+ match idOpt with
+ | Some id ->
+ let item = Item.ArgName (id, ttype, Some container)
+ CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.AccessRights)
+ | _ -> ()
+
+ match v with
+ | SynType.StaticConstant(sc, _) ->
+ let v =
+ match sc with
+ | SynConst.Byte n when typeEquiv g g.byte_ty kind -> record(g.byte_ty); box (n: byte)
+ | SynConst.Int16 n when typeEquiv g g.int16_ty kind -> record(g.int16_ty); box (n: int16)
+ | SynConst.Int32 n when typeEquiv g g.int32_ty kind -> record(g.int32_ty); box (n: int)
+ | SynConst.Int64 n when typeEquiv g g.int64_ty kind -> record(g.int64_ty); box (n: int64)
+ | SynConst.SByte n when typeEquiv g g.sbyte_ty kind -> record(g.sbyte_ty); box (n: sbyte)
+ | SynConst.UInt16 n when typeEquiv g g.uint16_ty kind -> record(g.uint16_ty); box (n: uint16)
+ | SynConst.UInt32 n when typeEquiv g g.uint32_ty kind -> record(g.uint32_ty); box (n: uint32)
+ | SynConst.UInt64 n when typeEquiv g g.uint64_ty kind -> record(g.uint64_ty); box (n: uint64)
+ | SynConst.Decimal n when typeEquiv g g.decimal_ty kind -> record(g.decimal_ty); box (n: decimal)
+ | SynConst.Single n when typeEquiv g g.float32_ty kind -> record(g.float32_ty); box (n: single)
+ | SynConst.Double n when typeEquiv g g.float_ty kind -> record(g.float_ty); box (n: double)
+ | SynConst.Char n when typeEquiv g g.char_ty kind -> record(g.char_ty); box (n: char)
+ | SynConst.String (s, _) when s <> null && typeEquiv g g.string_ty kind -> record(g.string_ty); box (s: string)
+ | SynConst.Bool b when typeEquiv g g.bool_ty kind -> record(g.bool_ty); box (b: bool)
+ | _ -> fail()
+ v, tpenv
+ | SynType.StaticConstantExpr(e, _ ) ->
+
+ // If an error occurs, don't try to recover, since the constant expression will be nothing like what we need
+ let te, tpenv' = TcExprNoRecover cenv kind env tpenv e
+
+ // Evaluate the constant expression using static attribute argument rules
+ let te = EvalLiteralExprOrAttribArg g te
+ let v =
+ match stripExpr te with
+ // Check we have a residue constant. We know the type was correct because we checked the expression with this type.
+ | Expr.Const (c, _, _) ->
+ match c with
+ | Const.Byte n -> record(g.byte_ty); box (n: byte)
+ | Const.Int16 n -> record(g.int16_ty); box (n: int16)
+ | Const.Int32 n -> record(g.int32_ty); box (n: int)
+ | Const.Int64 n -> record(g.int64_ty); box (n: int64)
+ | Const.SByte n -> record(g.sbyte_ty); box (n: sbyte)
+ | Const.UInt16 n -> record(g.uint16_ty); box (n: uint16)
+ | Const.UInt32 n -> record(g.uint32_ty); box (n: uint32)
+ | Const.UInt64 n -> record(g.uint64_ty); box (n: uint64)
+ | Const.Decimal n -> record(g.decimal_ty); box (n: decimal)
+ | Const.Single n -> record(g.float32_ty); box (n: single)
+ | Const.Double n -> record(g.float_ty); box (n: double)
+ | Const.Char n -> record(g.char_ty); box (n: char)
+ | Const.String null -> fail()
+ | Const.String s -> record(g.string_ty); box (s: string)
+ | Const.Bool b -> record(g.bool_ty); box (b: bool)
+ | _ -> fail()
+ | _ -> error(Error(FSComp.SR.tcInvalidConstantExpression(), v.Range))
+ v, tpenv'
+ | SynType.LongIdent lidwd ->
+ let m = lidwd.Range
+ TcStaticConstantParameter cenv env tpenv kind (SynType.StaticConstantExpr(SynExpr.LongIdent (false, lidwd, None, m), m)) idOpt container
+ | _ ->
+ fail()
+
+and CrackStaticConstantArgs cenv env tpenv (staticParameters: Tainted[], args: SynType list, container, containerName, m) =
+ let args =
+ args |> List.map (function
+ | StripParenTypes (SynType.StaticConstantNamed(StripParenTypes (SynType.LongIdent(LongIdentWithDots([id], _))), v, _)) -> Some id, v
+ | v -> None, v)
+
+ let unnamedArgs = args |> Seq.takeWhile (fst >> Option.isNone) |> Seq.toArray |> Array.map snd
+ let otherArgs = args |> List.skipWhile (fst >> Option.isNone)
+ let namedArgs = otherArgs |> List.takeWhile (fst >> Option.isSome) |> List.map (map1Of2 Option.get)
+ let otherArgs = otherArgs |> List.skipWhile (fst >> Option.isSome)
+ if not otherArgs.IsEmpty then
+ error (Error(FSComp.SR.etBadUnnamedStaticArgs(), m))
+
+ let indexedStaticParameters = staticParameters |> Array.toList |> List.indexed
+ for (n, _) in namedArgs do
+ match indexedStaticParameters |> List.filter (fun (j, sp) -> j >= unnamedArgs.Length && n.idText = sp.PUntaint((fun sp -> sp.Name), m)) with
+ | [] ->
+ if staticParameters |> Array.exists (fun sp -> n.idText = sp.PUntaint((fun sp -> sp.Name), n.idRange)) then
+ error (Error(FSComp.SR.etStaticParameterAlreadyHasValue n.idText, n.idRange))
+ else
+ error (Error(FSComp.SR.etNoStaticParameterWithName n.idText, n.idRange))
+ | [_] -> ()
+ | _ -> error (Error(FSComp.SR.etMultipleStaticParameterWithName n.idText, n.idRange))
+
+ if staticParameters.Length < namedArgs.Length + unnamedArgs.Length then
+ error (Error(FSComp.SR.etTooManyStaticParameters(staticParameters.Length, unnamedArgs.Length, namedArgs.Length), m))
+
+ let argsInStaticParameterOrderIncludingDefaults =
+ staticParameters |> Array.mapi (fun i sp ->
+ let spKind = Import.ImportProvidedType cenv.amap m (sp.PApply((fun x -> x.ParameterType), m))
+ let spName = sp.PUntaint((fun sp -> sp.Name), m)
+ if i < unnamedArgs.Length then
+ let v = unnamedArgs.[i]
+ let v, _tpenv = TcStaticConstantParameter cenv env tpenv spKind v None container
+ v
+ else
+ match namedArgs |> List.filter (fun (n, _) -> n.idText = spName) with
+ | [(n, v)] ->
+ let v, _tpenv = TcStaticConstantParameter cenv env tpenv spKind v (Some n) container
+ v
+ | [] ->
+ if sp.PUntaint((fun sp -> sp.IsOptional), m) then
+ match sp.PUntaint((fun sp -> sp.RawDefaultValue), m) with
+ | null -> error (Error(FSComp.SR.etStaticParameterRequiresAValue (spName, containerName, containerName, spName), m))
+ | v -> v
+ else
+ error (Error(FSComp.SR.etStaticParameterRequiresAValue (spName, containerName, containerName, spName), m))
+ | ps ->
+ error (Error(FSComp.SR.etMultipleStaticParameterWithName spName, (fst (List.last ps)).idRange)))
+
+ argsInStaticParameterOrderIncludingDefaults
+
+and TcProvidedTypeAppToStaticConstantArgs cenv env optGeneratedTypePath tpenv (tcref: TyconRef) (args: SynType list) m =
+ let typeBeforeArguments =
+ match tcref.TypeReprInfo with
+ | TProvidedTypeExtensionPoint info -> info.ProvidedType
+ | _ -> failwith "unreachable"
+
+ let staticParameters = typeBeforeArguments.PApplyWithProvider((fun (typeBeforeArguments, provider) -> typeBeforeArguments.GetStaticParameters provider), range=m)
+ let staticParameters = staticParameters.PApplyArray(id, "GetStaticParameters", m)
+
+ let argsInStaticParameterOrderIncludingDefaults = CrackStaticConstantArgs cenv env tpenv (staticParameters, args, ArgumentContainer.Type tcref, tcref.DisplayName, m)
+
+ // Take the static arguments (as SynType's) and convert them to objects of the appropriate type, based on the expected kind.
+ let providedTypeAfterStaticArguments, checkTypeName =
+ match ExtensionTyping.TryApplyProvidedType(typeBeforeArguments, optGeneratedTypePath, argsInStaticParameterOrderIncludingDefaults, m) with
+ | None -> error(Error(FSComp.SR.etErrorApplyingStaticArgumentsToType(), m))
+ | Some (ty, checkTypeName) -> (ty, checkTypeName)
+
+ let hasNoArgs = (argsInStaticParameterOrderIncludingDefaults.Length = 0)
+ hasNoArgs, providedTypeAfterStaticArguments, checkTypeName
+
+and TryTcMethodAppToStaticConstantArgs cenv env tpenv (minfos: MethInfo list, argsOpt, mExprAndArg, mItem) =
+ match minfos, argsOpt with
+ | [minfo], Some (args, _) ->
+ match minfo.ProvidedStaticParameterInfo with
+ | Some (methBeforeArguments, staticParams) ->
+ let providedMethAfterStaticArguments = TcProvidedMethodAppToStaticConstantArgs cenv env tpenv (minfo, methBeforeArguments, staticParams, args, mExprAndArg)
+ let minfoAfterStaticArguments = ProvidedMeth(cenv.amap, providedMethAfterStaticArguments, minfo.ExtensionMemberPriorityOption, mItem)
+ Some minfoAfterStaticArguments
+ | _ -> None
+ | _ -> None
+
+and TcProvidedMethodAppToStaticConstantArgs cenv env tpenv (minfo, methBeforeArguments, staticParams, args, m) =
+
+ let argsInStaticParameterOrderIncludingDefaults = CrackStaticConstantArgs cenv env tpenv (staticParams, args, ArgumentContainer.Method minfo, minfo.DisplayName, m)
+
+ let providedMethAfterStaticArguments =
+ match ExtensionTyping.TryApplyProvidedMethod(methBeforeArguments, argsInStaticParameterOrderIncludingDefaults, m) with
+ | None -> error(Error(FSComp.SR.etErrorApplyingStaticArgumentsToMethod(), m))
+ | Some meth -> meth
+
+ providedMethAfterStaticArguments
+
+and TcProvidedTypeApp cenv env tpenv tcref args m =
+ let hasNoArgs, providedTypeAfterStaticArguments, checkTypeName = TcProvidedTypeAppToStaticConstantArgs cenv env None tpenv tcref args m
+
+ let isGenerated = providedTypeAfterStaticArguments.PUntaint((fun st -> not st.IsErased), m)
+
+ //printfn "adding entity for provided type '%s', isDirectReferenceToGenerated = %b, isGenerated = %b" (st.PUntaint((fun st -> st.Name), m)) isDirectReferenceToGenerated isGenerated
+ let isDirectReferenceToGenerated = isGenerated && ExtensionTyping.IsGeneratedTypeDirectReference (providedTypeAfterStaticArguments, m)
+ if isDirectReferenceToGenerated then
+ error(Error(FSComp.SR.etDirectReferenceToGeneratedTypeNotAllowed(tcref.DisplayName), m))
+
+ // We put the type name check after the 'isDirectReferenceToGenerated' check because we need the 'isDirectReferenceToGenerated' error to be shown for generated types
+ checkTypeName()
+ if hasNoArgs then
+ mkAppTy tcref [], tpenv
+ else
+ let ty = Import.ImportProvidedType cenv.amap m providedTypeAfterStaticArguments
+ ty, tpenv
+#endif
+
+/// Typecheck an application of a generic type to type arguments.
+///
+/// Note that the generic type may be a nested generic type List.ListEnumerator.
+/// In this case, 'args' is only the instantiation of the suffix type arguments, and pathTypeArgs gives
+/// the prefix of type arguments.
+and TcTypeApp cenv newOk checkCxs occ env tpenv m tcref pathTypeArgs (synArgTys: SynType list) =
+ let g = cenv.g
+ CheckTyconAccessible cenv.amap m env.AccessRights tcref |> ignore
+ CheckEntityAttributes g tcref m |> CommitOperationResult
+
+#if !NO_EXTENSIONTYPING
+ // Provided types are (currently) always non-generic. Their names may include mangled
+ // static parameters, which are passed by the provider.
+ if tcref.Deref.IsProvided then TcProvidedTypeApp cenv env tpenv tcref synArgTys m else
+#endif
+
+ let tps, _, tinst, _ = FreshenTyconRef2 m tcref
+
+ // If we're not checking constraints, i.e. when we first assert the super/interfaces of a type definition, then just
+ // clear the constraint lists of the freshly generated type variables. A little ugly but fairly localized.
+ if checkCxs = NoCheckCxs then tps |> List.iter (fun tp -> tp.SetConstraints [])
+ let synArgTysLength = synArgTys.Length
+ let pathTypeArgsLength = pathTypeArgs.Length
+ if tinst.Length <> pathTypeArgsLength + synArgTysLength then
+ error (TyconBadArgs(env.DisplayEnv, tcref, pathTypeArgsLength + synArgTysLength, m))
+
+ let argTys, tpenv =
+ // Get the suffix of typars
+ let tpsForArgs = List.skip (tps.Length - synArgTysLength) tps
+ let kindsForArgs = tpsForArgs |> List.map (fun tp -> tp.Kind)
+ TcTypesOrMeasures (Some kindsForArgs) cenv newOk checkCxs occ env tpenv synArgTys m
+
+ // Add the types of the enclosing class for a nested type
+ let actualArgTys = pathTypeArgs @ argTys
+
+ if checkCxs = CheckCxs then
+ List.iter2 (UnifyTypes cenv env m) tinst actualArgTys
+
+ // Try to decode System.Tuple --> F~ tuple types etc.
+ let ty = g.decompileType tcref actualArgTys
+
+ ty, tpenv
+
+and TcTypeOrMeasureAndRecover optKind cenv newOk checkCxs occ env tpenv ty =
+ try TcTypeOrMeasure optKind cenv newOk checkCxs occ env tpenv ty
+ with e ->
+ errorRecovery e ty.Range
+ let rty =
+ match optKind, newOk with
+ | Some TyparKind.Measure, NoNewTypars -> TType_measure Measure.One
+ | Some TyparKind.Measure, _ -> TType_measure (NewErrorMeasure ())
+ | _, NoNewTypars -> cenv.g.obj_ty
+ | _ -> NewErrorType ()
+ rty, tpenv
+
+
+and TcTypeAndRecover cenv newOk checkCxs occ env tpenv ty =
+ TcTypeOrMeasureAndRecover (Some TyparKind.Type) cenv newOk checkCxs occ env tpenv ty
+
+and TcNestedTypeApplication cenv newOk checkCxs occ env tpenv mWholeTypeApp ty pathTypeArgs tyargs =
+ let ty = convertToTypeWithMetadataIfPossible cenv.g ty
+ if not (isAppTy cenv.g ty) then error(Error(FSComp.SR.tcTypeHasNoNestedTypes(), mWholeTypeApp))
+ match ty with
+ | TType_app(tcref, _) ->
+ TcTypeApp cenv newOk checkCxs occ env tpenv mWholeTypeApp tcref pathTypeArgs tyargs
+ | _ -> error(InternalError("TcNestedTypeApplication: expected type application", mWholeTypeApp))
+
+
+and TryAdjustHiddenVarNameToCompGenName cenv env (id: Ident) altNameRefCellOpt =
+ match altNameRefCellOpt with
+ | Some ({contents = Undecided altId } as altNameRefCell) ->
+ match ResolvePatternLongIdent cenv.tcSink cenv.nameResolver AllIdsOK false id.idRange env.eAccessRights env.eNameResEnv TypeNameResolutionInfo.Default [id] with
+ | Item.NewDef _ -> None // the name is not in scope as a pattern identifier (e.g. union case), so do not use the alternate ID
+ | _ -> altNameRefCell := Decided altId; Some altId // the name is in scope as a pattern identifier, so use the alternate ID
+ | Some ({contents = Decided altId }) -> Some altId
+ | None -> None
+
+/// Bind the patterns used in a lambda. Not clear why we don't use TcPat.
+and TcSimplePat optArgsOK checkCxs cenv ty env (tpenv, names, takenNames) p =
+ match p with
+ | SynSimplePat.Id (id, altNameRefCellOpt, compgen, isMemberThis, isOpt, m) ->
+ // Check to see if pattern translation decides to use an alternative identifier.
+ match TryAdjustHiddenVarNameToCompGenName cenv env id altNameRefCellOpt with
+ | Some altId -> TcSimplePat optArgsOK checkCxs cenv ty env (tpenv, names, takenNames) (SynSimplePat.Id (altId, None, compgen, isMemberThis, isOpt, m) )
+ | None ->
+ if isOpt then
+ if not optArgsOK then
+ errorR(Error(FSComp.SR.tcOptionalArgsOnlyOnMembers(), m))
+
+ let tyarg = NewInferenceType ()
+ UnifyTypes cenv env m ty (mkOptionTy cenv.g tyarg)
+
+ let _, names, takenNames = TcPatBindingName cenv env id ty isMemberThis None None (ValInline.Optional, permitInferTypars, noArgOrRetAttribs, false, None, compgen) (names, takenNames)
+ id.idText,
+ (tpenv, names, takenNames)
+
+ | SynSimplePat.Typed (p, cty, m) ->
+ let cty', tpenv = TcTypeAndRecover cenv NewTyparsOK checkCxs ItemOccurence.UseInType env tpenv cty
+ match p with
+ // Optional arguments on members
+ | SynSimplePat.Id(_, _, _, _, true, _) -> UnifyTypes cenv env m ty (mkOptionTy cenv.g cty')
+ | _ -> UnifyTypes cenv env m ty cty'
+
+ TcSimplePat optArgsOK checkCxs cenv ty env (tpenv, names, takenNames) p
+
+ | SynSimplePat.Attrib (p, _, _) ->
+ TcSimplePat optArgsOK checkCxs cenv ty env (tpenv, names, takenNames) p
+
+// raise an error if any optional args precede any non-optional args
+and ValidateOptArgOrder (spats: SynSimplePats) =
+
+ let rec getPats spats =
+ match spats with
+ | SynSimplePats.SimplePats(p, m) -> p, m
+ | SynSimplePats.Typed(p, _, _) -> getPats p
+
+ let rec isOptArg pat =
+ match pat with
+ | SynSimplePat.Id (_, _, _, _, isOpt, _) -> isOpt
+ | SynSimplePat.Typed (p, _, _) -> isOptArg p
+ | SynSimplePat.Attrib (p, _, _) -> isOptArg p
+
+ let pats, m = getPats spats
+
+ let mutable hitOptArg = false
+
+ List.iter (fun pat -> if isOptArg pat then hitOptArg <- true elif hitOptArg then error(Error(FSComp.SR.tcOptionalArgsMustComeAfterNonOptionalArgs(), m))) pats
+
+
+/// Bind the patterns used in argument position for a function, method or lambda.
+and TcSimplePats cenv optArgsOK checkCxs ty env (tpenv, names, takenNames: Set<_>) p =
+
+ // validate optional argument declaration
+ ValidateOptArgOrder p
+
+ match p with
+ | SynSimplePats.SimplePats ([], m) ->
+ // Unit "()" patterns in argument position become SynSimplePats.SimplePats([], _) in the
+ // syntactic translation when building bindings. This is done because the
+ // use of "()" has special significance for arity analysis and argument counting.
+ //
+ // Here we give a name to the single argument implied by those patterns.
+ // This is a little awkward since it would be nice if this was
+ // uniform with the process where we give names to other (more complex)
+ // patterns used in argument position, e.g. "let f (D(x)) = ..."
+ let id = ident("unitVar" + string takenNames.Count, m)
+ UnifyTypes cenv env m ty cenv.g.unit_ty
+ let _, names, takenNames = TcPatBindingName cenv env id ty false None None (ValInline.Optional, permitInferTypars, noArgOrRetAttribs, false, None, true) (names, takenNames)
+ [id.idText], (tpenv, names, takenNames)
+
+ | SynSimplePats.SimplePats ([p], _) ->
+ let v, (tpenv, names, takenNames) = TcSimplePat optArgsOK checkCxs cenv ty env (tpenv, names, takenNames) p
+ [v], (tpenv, names, takenNames)
+
+ | SynSimplePats.SimplePats (ps, m) ->
+ let ptys = UnifyRefTupleType env.eContextInfo cenv env.DisplayEnv m ty ps
+ let ps', (tpenv, names, takenNames) = List.mapFold (fun tpenv (ty, e) -> TcSimplePat optArgsOK checkCxs cenv ty env tpenv e) (tpenv, names, takenNames) (List.zip ptys ps)
+ ps', (tpenv, names, takenNames)
+
+ | SynSimplePats.Typed (p, cty, m) ->
+ let cty', tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv cty
+
+ match p with
+ // Solitary optional arguments on members
+ | SynSimplePats.SimplePats([SynSimplePat.Id(_, _, _, _, true, _)], _) -> UnifyTypes cenv env m ty (mkOptionTy cenv.g cty')
+ | _ -> UnifyTypes cenv env m ty cty'
+
+ TcSimplePats cenv optArgsOK checkCxs ty env (tpenv, names, takenNames) p
+
+and TcSimplePatsOfUnknownType cenv optArgsOK checkCxs env tpenv spats =
+ let argty = NewInferenceType ()
+ TcSimplePats cenv optArgsOK checkCxs argty env (tpenv, NameMap.empty, Set.empty) spats
+
+and TcPatBindingName cenv env id ty isMemberThis vis1 topValData (inlineFlag, declaredTypars, argAttribs, isMutable, vis2, compgen) (names, takenNames: Set) =
+ let vis = if Option.isSome vis1 then vis1 else vis2
+ if takenNames.Contains id.idText then errorR (VarBoundTwice id)
+ let compgen = compgen || IsCompilerGeneratedName id.idText
+ let baseOrThis = if isMemberThis then MemberThisVal else NormalVal
+ let names = Map.add id.idText (PrelimValScheme1(id, declaredTypars, ty, topValData, None, isMutable, inlineFlag, baseOrThis, argAttribs, vis, compgen)) names
+ let takenNames = Set.add id.idText takenNames
+ (fun (TcPatPhase2Input (values, isLeftMost)) ->
+ let (vspec, typeScheme) =
+ let name = id.idText
+ match values.TryGetValue name with
+ | true, value ->
+ if not (String.IsNullOrEmpty name) && not (String.isLeadingIdentifierCharacterUpperCase name) then
+ match env.eNameResEnv.ePatItems.TryGetValue name with
+ | true, Item.Value vref when vref.LiteralValue.IsSome ->
+ warning(Error(FSComp.SR.checkLowercaseLiteralBindingInPattern name, id.idRange))
+ | _ -> ()
+ value
+ | _ -> error(Error(FSComp.SR.tcNameNotBoundInPattern name, id.idRange))
+
+ // isLeftMost indicates we are processing the left-most path through a disjunctive or pattern.
+ // For those binding locations, CallNameResolutionSink is called in MakeAndPublishValue, like all other bindings
+ // For non-left-most paths, we register the name resolutions here
+ if not isLeftMost && not vspec.IsCompilerGenerated && not (vspec.LogicalName.StartsWithOrdinal("_")) then
+ let item = Item.Value(mkLocalValRef vspec)
+ CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Binding, env.AccessRights)
+
+ PBind(vspec, typeScheme)),
+ names, takenNames
+
+and TcPatAndRecover warnOnUpper cenv (env: TcEnv) topValInfo vFlags (tpenv, names, takenNames) ty (pat: SynPat) =
+ try
+ TcPat warnOnUpper cenv env topValInfo vFlags (tpenv, names, takenNames) ty pat
+ with e ->
+ // Error recovery - return some rubbish expression, but replace/annotate
+ // the type of the current expression with a type variable that indicates an error
+ let m = pat.Range
+ errorRecovery e m
+ //solveTypAsError cenv env.DisplayEnv m ty
+ (fun _ -> TPat_error m), (tpenv, names, takenNames)
+
+/// Typecheck a pattern. Patterns are type-checked in three phases:
+/// 1. TcPat builds a List.map from simple variable names to inferred types for
+/// those variables. It also returns a function to perform the second phase.
+/// 2. The second phase assumes the caller has built the actual value_spec's
+/// for the values being defined, and has decided if the types of these
+/// variables are to be generalized. The caller hands this information to
+/// the second-phase function in terms of a List.map from names to actual
+/// value specifications.
+and TcPat warnOnUpper cenv env topValInfo vFlags (tpenv, names, takenNames) ty pat =
+ let ad = env.AccessRights
+ match pat with
+ | SynPat.Const (c, m) ->
+ match c with
+ | SynConst.Bytes (bytes, m) ->
+ UnifyTypes cenv env m ty (mkByteArrayTy cenv.g)
+ TcPat warnOnUpper cenv env None vFlags (tpenv, names, takenNames) ty (SynPat.ArrayOrList (true, [ for b in bytes -> SynPat.Const(SynConst.Byte b, m) ], m))
+
+ | SynConst.UserNum _ ->
+ errorR (Error (FSComp.SR.tcInvalidNonPrimitiveLiteralInPatternMatch (), m))
+ (fun _ -> TPat_error m), (tpenv, names, takenNames)
+
+ | _ ->
+ try
+ let c' = TcConst cenv ty m env c
+ (fun _ -> TPat_const (c', m)), (tpenv, names, takenNames)
+ with e ->
+ errorRecovery e m
+ (fun _ -> TPat_error m), (tpenv, names, takenNames)
+
+ | SynPat.Wild m ->
+ (fun _ -> TPat_wild m), (tpenv, names, takenNames)
+
+ | SynPat.IsInst(cty, m)
+ | SynPat.Named (SynPat.IsInst(cty, m), _, _, _, _) ->
+ let srcTy = ty
+ let tgtTy, tpenv = TcTypeAndRecover cenv NewTyparsOKButWarnIfNotRigid CheckCxs ItemOccurence.UseInType env tpenv cty
+ TcRuntimeTypeTest (*isCast*)false (*isOperator*)true cenv env.DisplayEnv m tgtTy srcTy
+ match pat with
+ | SynPat.IsInst(_, m) ->
+ (fun _ -> TPat_isinst (srcTy, tgtTy, None, m)), (tpenv, names, takenNames)
+ | SynPat.Named (SynPat.IsInst _, id, isMemberThis, vis, m) ->
+ let bindf, names, takenNames = TcPatBindingName cenv env id tgtTy isMemberThis vis None vFlags (names, takenNames)
+ (fun values -> TPat_isinst (srcTy, tgtTy, Some(bindf values), m)),
+ (tpenv, names, takenNames)
+ | _ -> failwith "TcPat"
+
+ | SynPat.OptionalVal (id, m) ->
+ errorR (Error (FSComp.SR.tcOptionalArgsOnlyOnMembers (), m))
+ let bindf, names, takenNames = TcPatBindingName cenv env id ty false None topValInfo vFlags (names, takenNames)
+ (fun values -> TPat_as (TPat_wild m, bindf values, m)), (tpenv, names, takenNames)
+
+ | SynPat.Named (p, id, isMemberThis, vis, m) ->
+ let bindf, names, takenNames = TcPatBindingName cenv env id ty isMemberThis vis topValInfo vFlags (names, takenNames)
+ let pat', acc = TcPat warnOnUpper cenv env None vFlags (tpenv, names, takenNames) ty p
+ (fun values -> TPat_as (pat' values, bindf values, m)),
+ acc
+
+ | SynPat.Typed (p, cty, m) ->
+ let cty', tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv cty
+ UnifyTypes cenv env m ty cty'
+ TcPat warnOnUpper cenv env topValInfo vFlags (tpenv, names, takenNames) ty p
+
+ | SynPat.Attrib (p, attrs, _) ->
+ errorR (Error (FSComp.SR.tcAttributesInvalidInPatterns (), rangeOfNonNilAttrs attrs))
+ for attrList in attrs do
+ TcAttributes cenv env Unchecked.defaultof<_> attrList.Attributes |> ignore
+ TcPat warnOnUpper cenv env None vFlags (tpenv, names, takenNames) ty p
+
+ | SynPat.Or (pat1, pat2, m) ->
+ let pat1', (tpenv, names1, takenNames1) = TcPat warnOnUpper cenv env None vFlags (tpenv, names, takenNames) ty pat1
+ let pat2', (tpenv, names2, takenNames2) = TcPat warnOnUpper cenv env None vFlags (tpenv, names, takenNames) ty pat2
+ if not (takenNames1 = takenNames2) then
+ errorR (UnionPatternsBindDifferentNames m)
+
+ names1 |> Map.iter (fun _ (PrelimValScheme1 (id1, _, ty1, _, _, _, _, _, _, _, _)) ->
+ match names2.TryGetValue id1.idText with
+ | true, PrelimValScheme1 (id2, _, ty2, _, _, _, _, _, _, _, _) ->
+ try UnifyTypes cenv env id2.idRange ty1 ty2
+ with e -> errorRecovery e m
+ | _ -> ())
+
+ let names = NameMap.layer names1 names2
+ let takenNames = Set.union takenNames1 takenNames2
+ (fun values -> TPat_disjs ([pat1' values; pat2' values.RightPath], m)), (tpenv, names, takenNames)
+
+ | SynPat.Ands (pats, m) ->
+ let pats', acc = TcPatterns warnOnUpper cenv env vFlags (tpenv, names, takenNames) (List.map (fun _ -> ty) pats) pats
+ (fun values -> TPat_conjs(List.map (fun f -> f values) pats', m)), acc
+
+ | SynPat.LongIdent (LongIdentWithDots(longId, _), _, tyargs, args, vis, m) ->
+ if Option.isSome tyargs then errorR(Error(FSComp.SR.tcInvalidTypeArgumentUsage(), m))
+ let warnOnUpperForId =
+ match args with
+ | SynArgPats.Pats [] -> warnOnUpper
+ | _ -> AllIdsOK
+
+ let lidRange = rangeOfLid longId
+
+ let checkNoArgsForLiteral () =
+ match args with
+ | SynArgPats.Pats []
+ | SynArgPats.NamePatPairs ([], _) -> ()
+ | _ -> errorR (Error (FSComp.SR.tcLiteralDoesNotTakeArguments (), m))
+
+ let getArgPatterns () =
+ match args with
+ | SynArgPats.Pats args -> args
+ | SynArgPats.NamePatPairs (pairs, _) -> List.map snd pairs
+
+ let tcArgPatterns () =
+ let args = getArgPatterns ()
+ TcPatterns warnOnUpper cenv env vFlags (tpenv, names, takenNames) (NewInferenceTypes args) args
+
+ // Note we parse arguments to parameterized pattern labels as patterns, not expressions.
+ // This means the range of syntactic expression forms that can be used here is limited.
+ let rec convSynPatToSynExpr x =
+ match x with
+ | SynPat.FromParseError(p, _) -> convSynPatToSynExpr p
+ | SynPat.Const (c, m) -> SynExpr.Const (c, m)
+ | SynPat.Named (SynPat.Wild _, id, _, None, _) -> SynExpr.Ident id
+ | SynPat.Typed (p, cty, m) -> SynExpr.Typed (convSynPatToSynExpr p, cty, m)
+ | SynPat.LongIdent (LongIdentWithDots(longId, dotms) as lidwd, _, _tyargs, args, None, m) ->
+ let args = match args with SynArgPats.Pats args -> args | _ -> failwith "impossible: active patterns can be used only with SynConstructorArgs.Pats"
+ let e =
+ if dotms.Length = longId.Length then
+ let e = SynExpr.LongIdent (false, LongIdentWithDots(longId, List.truncate (dotms.Length - 1) dotms), None, m)
+ SynExpr.DiscardAfterMissingQualificationAfterDot (e, unionRanges e.Range (List.last dotms))
+ else SynExpr.LongIdent (false, lidwd, None, m)
+ List.fold (fun f x -> mkSynApp1 f (convSynPatToSynExpr x) m) e args
+ | SynPat.Tuple (isStruct, args, m) -> SynExpr.Tuple (isStruct, List.map convSynPatToSynExpr args, [], m)
+ | SynPat.Paren (p, _) -> convSynPatToSynExpr p
+ | SynPat.ArrayOrList (isArray, args, m) -> SynExpr.ArrayOrList (isArray,List.map convSynPatToSynExpr args, m)
+ | SynPat.QuoteExpr (e,_) -> e
+ | SynPat.Null m -> SynExpr.Null m
+ | _ -> error(Error(FSComp.SR.tcInvalidArgForParameterizedPattern(), x.Range))
+
+ let isNameof (id: Ident) =
+ id.idText = "nameof" &&
+ try
+ match ResolveExprLongIdent cenv.tcSink cenv.nameResolver m ad env.NameEnv TypeNameResolutionInfo.Default [id] with
+ | Result (_, Item.Value vref, _) -> valRefEq cenv.g vref cenv.g.nameof_vref
+ | _ -> false
+ with _ -> false
+
+ match ResolvePatternLongIdent cenv.tcSink cenv.nameResolver warnOnUpperForId false m ad env.NameEnv TypeNameResolutionInfo.Default longId with
+ | Item.NewDef id ->
+ match getArgPatterns () with
+ | [] ->
+ TcPat warnOnUpperForId cenv env topValInfo vFlags (tpenv, names, takenNames) ty (mkSynPatVar vis id)
+
+ | [arg]
+ when cenv.g.langVersion.SupportsFeature LanguageFeature.NameOf && isNameof id ->
+ match TcNameOfExpr cenv env tpenv (convSynPatToSynExpr arg) with
+ | Expr.Const(c, m, _) -> (fun _ -> TPat_const (c, m)), (tpenv, names, takenNames)
+ | _ -> failwith "Impossible: TcNameOfExpr must return an Expr.Const"
+ | _ ->
+ let _, acc = tcArgPatterns ()
+ errorR (UndefinedName (0, FSComp.SR.undefinedNamePatternDiscriminator, id, NoSuggestions))
+ (fun _ -> TPat_error m), acc
+
+ | Item.ActivePatternCase (APElemRef (apinfo, vref, idx)) as item ->
+ // Report information about the 'active recognizer' occurrence to IDE
+ CallNameResolutionSink cenv.tcSink (rangeOfLid longId, env.NameEnv, item, emptyTyparInst, ItemOccurence.Pattern, env.eAccessRights)
+
+ match args with
+ | SynArgPats.Pats _ -> ()
+ | _ -> errorR (Error (FSComp.SR.tcNamedActivePattern (apinfo.ActiveTags.[idx]), m))
+
+ let args = getArgPatterns ()
+
+ // TOTAL/PARTIAL ACTIVE PATTERNS
+ let _, vexp, _, _, tinst, _ = TcVal true cenv env tpenv vref None None m
+ let vexp = MakeApplicableExprWithFlex cenv env vexp
+ let vexpty = vexp.Type
+
+ let activePatArgsAsSynPats, patarg =
+ match args with
+ | [] -> [], SynPat.Const(SynConst.Unit, m)
+ | _ ->
+ // This bit of type-directed analysis ensures that parameterized partial active patterns returning unit do not need to take an argument
+ // See FSharp 1.0 3502
+ let dtys, rty = stripFunTy cenv.g vexpty
+
+ if dtys.Length = args.Length + 1 && isOptionTy cenv.g rty && isUnitTy cenv.g (destOptionTy cenv.g rty) then
+ args, SynPat.Const(SynConst.Unit, m)
+ else
+ List.frontAndBack args
+
+ if not (isNil activePatArgsAsSynPats) && apinfo.ActiveTags.Length <> 1 then
+ errorR (Error (FSComp.SR.tcRequireActivePatternWithOneResult (), m))
+
+ let activePatArgsAsSynExprs = List.map convSynPatToSynExpr activePatArgsAsSynPats
+
+ let activePatResTys = NewInferenceTypes apinfo.Names
+ let activePatType = apinfo.OverallType cenv.g m ty activePatResTys
+
+ let delayed = activePatArgsAsSynExprs |> List.map (fun arg -> DelayedApp(ExprAtomicFlag.NonAtomic, arg, unionRanges (rangeOfLid longId) arg.Range))
+ let activePatExpr, tpenv = PropagateThenTcDelayed cenv activePatType env tpenv m vexp vexpty ExprAtomicFlag.NonAtomic delayed
+
+ if idx >= activePatResTys.Length then error(Error(FSComp.SR.tcInvalidIndexIntoActivePatternArray(), m))
+ let argty = List.item idx activePatResTys
+
+ let arg', acc = TcPat warnOnUpper cenv env None vFlags (tpenv, names, takenNames) argty patarg
+
+ // The identity of an active pattern consists of its value and the types it is applied to.
+ // If there are any expression args then we've lost identity.
+ let activePatIdentity = if isNil activePatArgsAsSynExprs then Some (vref, tinst) else None
+ (fun values ->
+ TPat_query((activePatExpr, activePatResTys, activePatIdentity, idx, apinfo), arg' values, m)), acc
+
+ | (Item.UnionCase _ | Item.ExnCase _) as item ->
+ // Report information about the case occurrence to IDE
+ CallNameResolutionSink cenv.tcSink (lidRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Pattern, env.eAccessRights)
+
+ let mkf, argTys, argNames = ApplyUnionCaseOrExnTypesForPat m cenv env ty item
+ let numArgTys = argTys.Length
+
+ let args, extraPatternsFromNames =
+ match args with
+ | SynArgPats.Pats args -> args, []
+ | SynArgPats.NamePatPairs (pairs, m) ->
+ // rewrite patterns from the form (name-N = pat-N; ...) to (..._, pat-N, _...)
+ // so type T = Case of name: int * value: int
+ // | Case(value = v)
+ // will become
+ // | Case(_, v)
+ let result = Array.zeroCreate numArgTys
+ let extraPatterns = List ()
+
+ for (id, pat) in pairs do
+ match argNames |> List.tryFindIndex (fun id2 -> id.idText = id2.idText) with
+ | None ->
+ extraPatterns.Add pat
+ match item with
+ | Item.UnionCase(uci, _) ->
+ errorR (Error (FSComp.SR.tcUnionCaseConstructorDoesNotHaveFieldWithGivenName (uci.Name, id.idText), id.idRange))
+ | Item.ExnCase tcref ->
+ errorR (Error (FSComp.SR.tcExceptionConstructorDoesNotHaveFieldWithGivenName (tcref.DisplayName, id.idText), id.idRange))
+ | _ ->
+ errorR (Error (FSComp.SR.tcConstructorDoesNotHaveFieldWithGivenName (id.idText), id.idRange))
+
+ | Some idx ->
+ let argItem =
+ match item with
+ | Item.UnionCase (uci, _) -> Item.UnionCaseField (uci, idx)
+ | Item.ExnCase tref -> Item.RecdField (RecdFieldInfo ([], RecdFieldRef (tref, id.idText)))
+ | _ -> failwithf "Expecting union case or exception item, got: %O" item
+
+ CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, argItem, emptyTyparInst, ItemOccurence.Pattern, ad)
+
+ match box result.[idx] with
+ | null -> result.[idx] <- pat
+ | _ ->
+ extraPatterns.Add pat
+ errorR (Error (FSComp.SR.tcUnionCaseFieldCannotBeUsedMoreThanOnce (id.idText), id.idRange))
+
+ for i = 0 to numArgTys - 1 do
+ if isNull (box result.[i]) then
+ result.[i] <- SynPat.Wild (m.MakeSynthetic())
+
+ let extraPatterns =
+ if isNull extraPatterns then [] else List.ofSeq extraPatterns
+
+ let args = List.ofArray result
+ if result.Length = 1 then args, extraPatterns
+ else [ SynPat.Tuple(false, args, m) ], extraPatterns
+
+ let args, extraPatterns =
+ match args with
+ | [] -> [], []
+
+ // note: the next will always be parenthesized
+ | [SynPatErrorSkip(SynPat.Tuple (false, args, _)) | SynPatErrorSkip(SynPat.Paren(SynPatErrorSkip(SynPat.Tuple (false, args, _)), _))] when numArgTys > 1 -> args, []
+
+ // note: we allow both 'C _' and 'C (_)' regardless of number of argument of the pattern
+ | [SynPatErrorSkip(SynPat.Wild _ as e) | SynPatErrorSkip(SynPat.Paren(SynPatErrorSkip(SynPat.Wild _ as e), _))] -> List.replicate numArgTys e, []
+
+
+ | args when numArgTys = 0 ->
+ errorR (Error (FSComp.SR.tcUnionCaseDoesNotTakeArguments (), m))
+ [], args
+
+ | arg :: rest when numArgTys = 1 ->
+ if numArgTys = 1 && not (List.isEmpty rest) then
+ errorR (Error (FSComp.SR.tcUnionCaseRequiresOneArgument (), m))
+ [arg], rest
+
+ | [arg] -> [arg], []
+
+ | args ->
+ [], args
+
+ let args, extraPatterns =
+ let numArgs = args.Length
+ if numArgs = numArgTys then
+ args, extraPatterns
+ elif numArgs < numArgTys then
+ if numArgTys > 1 then
+ // Expects tuple without enough args
+ errorR (Error (FSComp.SR.tcUnionCaseExpectsTupledArguments numArgTys, m))
+ else
+ errorR (UnionCaseWrongArguments (env.DisplayEnv, numArgTys, numArgs, m))
+ args @ (List.init (numArgTys - numArgs) (fun _ -> SynPat.Wild (m.MakeSynthetic()))), extraPatterns
+ else
+ let args, remaining = args |> List.splitAt numArgTys
+ for remainingArg in remaining do
+ errorR (UnionCaseWrongArguments (env.DisplayEnv, numArgTys, numArgs, remainingArg.Range))
+ args, extraPatterns @ remaining
+
+ let extraPatterns = extraPatterns @ extraPatternsFromNames
+ let args', acc = TcPatterns warnOnUpper cenv env vFlags (tpenv, names, takenNames) argTys args
+ let _, acc = TcPatterns warnOnUpper cenv env vFlags acc (NewInferenceTypes extraPatterns) extraPatterns
+ (fun values -> mkf m (List.map (fun f -> f values) args')), acc
+
+ | Item.ILField finfo ->
+ CheckILFieldInfoAccessible cenv.g cenv.amap lidRange env.AccessRights finfo
+ if not finfo.IsStatic then
+ errorR (Error (FSComp.SR.tcFieldIsNotStatic (finfo.FieldName), lidRange))
+ CheckILFieldAttributes cenv.g finfo m
+ match finfo.LiteralValue with
+ | None -> error (Error (FSComp.SR.tcFieldNotLiteralCannotBeUsedInPattern (), lidRange))
+ | Some lit ->
+ checkNoArgsForLiteral ()
+ let _, acc = tcArgPatterns ()
+
+ UnifyTypes cenv env m ty (finfo.FieldType (cenv.amap, m))
+ let c' = TcFieldInit lidRange lit
+ let item = Item.ILField finfo
+ CallNameResolutionSink cenv.tcSink (lidRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Pattern, env.AccessRights)
+ (fun _ -> TPat_const (c', m)), acc
+
+ | Item.RecdField rfinfo ->
+ CheckRecdFieldInfoAccessible cenv.amap lidRange env.AccessRights rfinfo
+ if not rfinfo.IsStatic then errorR (Error (FSComp.SR.tcFieldIsNotStatic(rfinfo.Name), lidRange))
+ CheckRecdFieldInfoAttributes cenv.g rfinfo lidRange |> CommitOperationResult
+ match rfinfo.LiteralValue with
+ | None -> error (Error(FSComp.SR.tcFieldNotLiteralCannotBeUsedInPattern(), lidRange))
+ | Some lit ->
+ checkNoArgsForLiteral()
+ let _, acc = tcArgPatterns ()
+
+ UnifyTypes cenv env m ty rfinfo.FieldType
+ let item = Item.RecdField rfinfo
+ // FUTURE: can we do better than emptyTyparInst here, in order to display instantiations
+ // of type variables in the quick info provided in the IDE.
+ CallNameResolutionSink cenv.tcSink (lidRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Pattern, env.AccessRights)
+ (fun _ -> TPat_const (lit, m)), acc
+
+ | Item.Value vref ->
+ match vref.LiteralValue with
+ | None -> error (Error(FSComp.SR.tcNonLiteralCannotBeUsedInPattern(), m))
+ | Some lit ->
+ let _, _, _, vexpty, _, _ = TcVal true cenv env tpenv vref None None lidRange
+ CheckValAccessible lidRange env.AccessRights vref
+ CheckFSharpAttributes cenv.g vref.Attribs lidRange |> CommitOperationResult
+ checkNoArgsForLiteral()
+ let _, acc = tcArgPatterns ()
+
+ UnifyTypes cenv env m ty vexpty
+ let item = Item.Value vref
+ CallNameResolutionSink cenv.tcSink (lidRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Pattern, env.AccessRights)
+ (fun _ -> TPat_const (lit, m)), acc
+
+ | _ -> error (Error(FSComp.SR.tcRequireVarConstRecogOrLiteral(), m))
+
+ | SynPat.QuoteExpr(_, m) ->
+ errorR (Error(FSComp.SR.tcInvalidPattern(), m))
+ (fun _ -> TPat_error m), (tpenv, names, takenNames)
+
+ | SynPat.Tuple (isExplicitStruct, args, m) ->
+ try
+ let tupInfo, argTys = UnifyTupleTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv m ty isExplicitStruct args
+ let args', acc = TcPatterns warnOnUpper cenv env vFlags (tpenv, names, takenNames) argTys args
+ (fun values -> TPat_tuple(tupInfo, List.map (fun f -> f values) args', argTys, m)), acc
+ with e ->
+ errorRecovery e m
+ let _, acc = TcPatterns warnOnUpper cenv env vFlags (tpenv, names, takenNames) (NewInferenceTypes args) args
+ (fun _ -> TPat_error m), acc
+
+ | SynPat.Paren (p, _) ->
+ TcPat warnOnUpper cenv env None vFlags (tpenv, names, takenNames) ty p
+
+ | SynPat.ArrayOrList (isArray, args, m) ->
+ let argty = NewInferenceType ()
+ UnifyTypes cenv env m ty (if isArray then mkArrayType cenv.g argty else mkListTy cenv.g argty)
+ let args', acc = TcPatterns warnOnUpper cenv env vFlags (tpenv, names, takenNames) (List.map (fun _ -> argty) args) args
+ (fun values ->
+ let args' = List.map (fun f -> f values) args'
+ if isArray then TPat_array(args', argty, m)
+ else List.foldBack (mkConsListPat cenv.g argty) args' (mkNilListPat cenv.g m argty)), acc
+
+ | SynPat.Record (flds, m) ->
+ let tinst, tcref, fldsmap, _fldsList = BuildFieldMap cenv env true ty flds m
+ // REVIEW: use _fldsList to type check pattern in code order not field defn order
+ let gtyp = mkAppTy tcref tinst
+ let inst = List.zip (tcref.Typars m) tinst
+ UnifyTypes cenv env m ty gtyp
+ let fields = tcref.TrueInstanceFieldsAsList
+ let ftys = fields |> List.map (fun fsp -> actualTyOfRecdField inst fsp, fsp)
+ let fldsmap', acc =
+ ((tpenv, names, takenNames), ftys) ||> List.mapFold (fun s (ty, fsp) ->
+ match fldsmap.TryGetValue fsp.rfield_id.idText with
+ | true, v -> TcPat warnOnUpper cenv env None vFlags s ty v
+ | _ -> (fun _ -> TPat_wild m), s)
+ (fun values -> TPat_recd (tcref, tinst, List.map (fun f -> f values) fldsmap', m)),
+ acc
+
+ | SynPat.DeprecatedCharRange (c1, c2, m) ->
+ errorR(Deprecated(FSComp.SR.tcUseWhenPatternGuard(), m))
+ UnifyTypes cenv env m ty (cenv.g.char_ty)
+ (fun _ -> TPat_range(c1, c2, m)), (tpenv, names, takenNames)
+
+ | SynPat.Null m ->
+ try AddCxTypeMustSupportNull env.DisplayEnv cenv.css m NoTrace ty
+ with e -> errorRecovery e m
+ (fun _ -> TPat_null m), (tpenv, names, takenNames)
+
+ | SynPat.InstanceMember (_, _, _, _, m) ->
+ errorR(Error(FSComp.SR.tcIllegalPattern(), pat.Range))
+ (fun _ -> TPat_wild m), (tpenv, names, takenNames)
+
+ | SynPat.FromParseError (pat, _) ->
+ suppressErrorReporting (fun () -> TcPatAndRecover warnOnUpper cenv env topValInfo vFlags (tpenv, names, takenNames) (NewErrorType()) pat)
+
+and TcPatterns warnOnUpper cenv env vFlags s argTys args =
+ assert (List.length args = List.length argTys)
+ List.mapFold (fun s (ty, pat) -> TcPat warnOnUpper cenv env None vFlags s ty pat) s (List.zip argTys args)
+
+and solveTypAsError cenv denv m ty = ConstraintSolver.SolveTypeAsError denv cenv.css m ty
+
+and RecordNameAndTypeResolutions_IdeallyWithoutHavingOtherEffects cenv env tpenv expr =
+ // This function is motivated by cases like
+ // query { for ... join(for x in f(). }
+ // where there is incomplete code in a query, and we are current just dropping a piece of the AST on the floor (above, the bit inside the 'join').
+ //
+ // The problem with dropping the AST on the floor is that we get no captured resolutions, which means no Intellisense/QuickInfo/ParamHelp.
+ //
+ // The idea behind the fix is to semi-typecheck this AST-fragment, just to get resolutions captured.
+ //
+ // The tricky bit is to not also have any other effects from typechecking, namely producing error diagnostics (which may be spurious) or having
+ // side-effects on the typecheck environment.
+ //
+ // REVIEW: We are yet to deal with the tricky bit. As it stands, we turn off error logging, but still have typechecking environment effects. As a result,
+ // at the very least, you cannot call this function unless you're already reported a typechecking error (the 'worst' possible outcome would be
+ // to incorrectly solve typecheck constraints as a result of effects in this function, and then have the code compile successfully and behave
+ // in some weird way; so ensure the code can't possibly compile before calling this function as an expedient way to get better IntelliSense).
+ suppressErrorReporting (fun () ->
+ try ignore(TcExprOfUnknownType cenv env tpenv expr)
+ with e -> ())
+
+and RecordNameAndTypeResolutions_IdeallyWithoutHavingOtherEffects_Delayed cenv env tpenv delayed =
+
+ let rec dummyCheckedDelayed delayed =
+ match delayed with
+ | DelayedApp (_hpa, arg, _mExprAndArg) :: otherDelayed ->
+ RecordNameAndTypeResolutions_IdeallyWithoutHavingOtherEffects cenv env tpenv arg
+ dummyCheckedDelayed otherDelayed
+ | _ -> ()
+ dummyCheckedDelayed delayed
+
+// Calls UnifyTypes, but upon error only does the minimal error recovery
+// so that IntelliSense information can continue to be collected.
+and UnifyTypesAndRecover cenv env m expectedTy actualTy =
+ try
+ UnifyTypes cenv env m expectedTy actualTy
+ with e ->
+ errorRecovery e m
+
+and TcExprOfUnknownType cenv env tpenv expr =
+ let exprty = NewInferenceType ()
+ let expr', tpenv = TcExpr cenv exprty env tpenv expr
+ expr', exprty, tpenv
+
+and TcExprFlex cenv flex compat ty (env: TcEnv) tpenv (e: SynExpr) =
+ if flex then
+ let argty = NewInferenceType ()
+ if compat then
+ (destTyparTy cenv.g argty).SetIsCompatFlex(true)
+ AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css e.Range NoTrace ty argty
+ let e', tpenv = TcExpr cenv argty env tpenv e
+ let e' = mkCoerceIfNeeded cenv.g ty argty e'
+ e', tpenv
+ else
+ TcExpr cenv ty env tpenv e
+
+
+and TcExpr cenv ty (env: TcEnv) tpenv (expr: SynExpr) =
+ // Start an error recovery handler
+ // Note the try/with can lead to tail-recursion problems for iterated constructs, e.g. let... in...
+ // So be careful!
+ try
+ TcExprNoRecover cenv ty env tpenv expr
+ with e ->
+ let m = expr.Range
+ // Error recovery - return some rubbish expression, but replace/annotate
+ // the type of the current expression with a type variable that indicates an error
+ errorRecovery e m
+ solveTypAsError cenv env.DisplayEnv m ty
+ mkThrow m ty (mkOne cenv.g m), tpenv
+
+and TcExprNoRecover cenv ty (env: TcEnv) tpenv (expr: SynExpr) =
+
+ // Count our way through the expression shape that makes up an object constructor
+ // See notes at definition of "ctor" re. object model constructors.
+ let env =
+ if GetCtorShapeCounter env > 0 then AdjustCtorShapeCounter (fun x -> x - 1) env
+ else env
+
+ TcExprThen cenv ty env tpenv expr []
+
+
+// This recursive entry is only used from one callsite (DiscardAfterMissingQualificationAfterDot)
+// and has been added relatively late in F# 4.0 to preserve the structure of previous code. It pushes a 'delayed' parameter
+// through TcExprOfUnknownType, TcExpr and TcExprNoRecover
+and TcExprOfUnknownTypeThen cenv env tpenv expr delayed =
+ let exprty = NewInferenceType ()
+ let expr', tpenv =
+ try
+ TcExprThen cenv exprty env tpenv expr delayed
+ with e ->
+ let m = expr.Range
+ errorRecovery e m
+ solveTypAsError cenv env.DisplayEnv m exprty
+ mkThrow m exprty (mkOne cenv.g m), tpenv
+ expr', exprty, tpenv
+
+/// This is used to typecheck legitimate 'main body of constructor' expressions
+and TcExprThatIsCtorBody safeInitInfo cenv overallTy env tpenv expr =
+ let env = {env with eCtorInfo = Some (InitialExplicitCtorInfo safeInitInfo) }
+ let expr, tpenv = TcExpr cenv overallTy env tpenv expr
+ let expr = CheckAndRewriteObjectCtor cenv.g env expr
+ expr, tpenv
+
+/// This is used to typecheck all ordinary expressions including constituent
+/// parts of ctor.
+and TcExprThatCanBeCtorBody cenv overallTy env tpenv expr =
+ let env = if AreWithinCtorShape env then AdjustCtorShapeCounter (fun x -> x + 1) env else env
+ TcExpr cenv overallTy env tpenv expr
+
+/// This is used to typecheck legitimate 'non-main body of object constructor' expressions
+and TcExprThatCantBeCtorBody cenv overallTy env tpenv expr =
+ let env = if AreWithinCtorShape env then ExitCtorShapeRegion env else env
+ TcExpr cenv overallTy env tpenv expr
+
+/// This is used to typecheck legitimate 'non-main body of object constructor' expressions
+and TcStmtThatCantBeCtorBody cenv env tpenv expr =
+ let env = if AreWithinCtorShape env then ExitCtorShapeRegion env else env
+ TcStmt cenv env tpenv expr
+
+and TcStmt cenv env tpenv synExpr =
+ let expr, ty, tpenv = TcExprOfUnknownType cenv env tpenv synExpr
+ let m = synExpr.Range
+ let wasUnit = UnifyUnitType cenv env m ty expr
+ if wasUnit then
+ expr, tpenv
+ else
+ mkCompGenSequential m expr (mkUnit cenv.g m), tpenv
+
+and TryTcStmt cenv env tpenv synExpr =
+ let expr, ty, tpenv = TcExprOfUnknownType cenv env tpenv synExpr
+ let m = synExpr.Range
+ let hasTypeUnit = TryUnifyUnitTypeWithoutWarning cenv env m ty
+ hasTypeUnit, expr, tpenv
+
+/// During checking of expressions of the form (x(y)).z(w1, w2)
+/// keep a stack of things on the right. This lets us recognize
+/// method applications and other item-based syntax.
+and TcExprThen cenv overallTy env tpenv synExpr delayed =
+ match synExpr with
+
+ | LongOrSingleIdent (isOpt, longId, altNameRefCellOpt, mLongId) ->
+ if isOpt then errorR(Error(FSComp.SR.tcSyntaxErrorUnexpectedQMark(), mLongId))
+ // Check to see if pattern translation decided to use an alternative identifier.
+ match altNameRefCellOpt with
+ | Some {contents = Decided altId} -> TcExprThen cenv overallTy env tpenv (SynExpr.LongIdent (isOpt, LongIdentWithDots([altId], []), None, mLongId)) delayed
+ | _ -> TcLongIdentThen cenv overallTy env tpenv longId delayed
+
+ // f x
+ | SynExpr.App (hpa, _, func, arg, mFuncAndArg) ->
+ TcExprThen cenv overallTy env tpenv func ((DelayedApp (hpa, arg, mFuncAndArg)) :: delayed)
+
+ // e
+ | SynExpr.TypeApp (func, _, typeArgs, _, _, mTypeArgs, mFuncAndTypeArgs) ->
+ TcExprThen cenv overallTy env tpenv func ((DelayedTypeApp (typeArgs, mTypeArgs, mFuncAndTypeArgs)) :: delayed)
+
+ // e1.id1
+ // e1.id1.id2
+ // etc.
+ | SynExpr.DotGet (e1, _, LongIdentWithDots(longId, _), _) ->
+ TcExprThen cenv overallTy env tpenv e1 ((DelayedDotLookup (longId, synExpr.RangeSansAnyExtraDot)) :: delayed)
+
+ // e1.[e2]
+ // e1.[e21, ..., e2n]
+ // etc.
+ | SynExpr.DotIndexedGet (e1, e2, mDot, mWholeExpr) ->
+ TcIndexerThen cenv env overallTy mWholeExpr mDot tpenv synExpr e1 e2 delayed
+
+ // e1.[e2] <- e3
+ // e1.[e21, ..., e2n] <- e3
+ // etc.
+ | SynExpr.DotIndexedSet (e1, e2, _, _, mDot, mWholeExpr) ->
+ TcIndexerThen cenv env overallTy mWholeExpr mDot tpenv synExpr e1 e2 delayed
+
+ | _ ->
+ match delayed with
+ | [] -> TcExprUndelayed cenv overallTy env tpenv synExpr
+ | _ ->
+ let expr, exprty, tpenv = TcExprUndelayedNoType cenv env tpenv synExpr
+ PropagateThenTcDelayed cenv overallTy env tpenv synExpr.Range (MakeApplicableExprNoFlex cenv expr) exprty ExprAtomicFlag.NonAtomic delayed
+
+and TcExprs cenv env m tpenv flexes argTys args =
+ if List.length args <> List.length argTys then error(Error(FSComp.SR.tcExpressionCountMisMatch((List.length argTys), (List.length args)), m))
+ (tpenv, List.zip3 flexes argTys args) ||> List.mapFold (fun tpenv (flex, ty, e) ->
+ TcExprFlex cenv flex false ty env tpenv e)
+
+and CheckSuperInit cenv objTy m =
+ // Check the type is not abstract
+ match tryTcrefOfAppTy cenv.g objTy with
+ | ValueSome tcref when isAbstractTycon tcref.Deref ->
+ errorR(Error(FSComp.SR.tcAbstractTypeCannotBeInstantiated(), m))
+ | _ -> ()
+
+//-------------------------------------------------------------------------
+// TcExprUndelayed
+//-------------------------------------------------------------------------
+
+and TcExprUndelayedNoType cenv env tpenv synExpr: Expr * TType * _ =
+ let overallTy = NewInferenceType ()
+ let expr, tpenv = TcExprUndelayed cenv overallTy env tpenv synExpr
+ expr, overallTy, tpenv
+
+and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) =
+
+ match synExpr with
+ | SynExpr.Paren (expr2, _, _, mWholeExprIncludingParentheses) ->
+ // We invoke CallExprHasTypeSink for every construct which is atomic in the syntax, i.e. where a '.' immediately following the
+ // construct is a dot-lookup for the result of the construct.
+ CallExprHasTypeSink cenv.tcSink (mWholeExprIncludingParentheses, env.NameEnv, overallTy, env.AccessRights)
+ let env = ShrinkContext env mWholeExprIncludingParentheses expr2.Range
+ TcExpr cenv overallTy env tpenv expr2
+
+ | SynExpr.DotIndexedGet _ | SynExpr.DotIndexedSet _
+ | SynExpr.TypeApp _ | SynExpr.Ident _ | SynExpr.LongIdent _ | SynExpr.App _ | SynExpr.DotGet _ -> error(Error(FSComp.SR.tcExprUndelayed(), synExpr.Range))
+
+ | SynExpr.Const (SynConst.String (s, m), _) ->
+ CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights)
+ TcConstStringExpr cenv overallTy env m tpenv s
+
+ | SynExpr.InterpolatedString (parts, m) ->
+ checkLanguageFeatureError cenv.g.langVersion LanguageFeature.StringInterpolation m
+
+ CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights)
+
+ TcInterpolatedStringExpr cenv overallTy env m tpenv parts
+
+ | SynExpr.Const (synConst, m) ->
+ CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights)
+ TcConstExpr cenv overallTy env m tpenv synConst
+
+ | SynExpr.Lambda _ ->
+ TcIteratedLambdas cenv true env overallTy Set.empty tpenv synExpr
+
+ | SynExpr.Match (spMatch, synInputExpr, synClauses, _m) ->
+
+ let inputExpr, inputTy, tpenv = TcExprOfUnknownType cenv env tpenv synInputExpr
+ let mInputExpr = inputExpr.Range
+ let matchVal, matchExpr, tpenv = TcAndPatternCompileMatchClauses mInputExpr mInputExpr ThrowIncompleteMatchException cenv (Some inputExpr) inputTy overallTy env tpenv synClauses
+ let overallExpr = mkLet spMatch mInputExpr matchVal inputExpr matchExpr
+ overallExpr, tpenv
+
+ // (function[spMatch] pat1 -> expr1 ... | patN -> exprN)
+ //
+ // -->
+ // (fun anonArg -> let[spMatch] anonVal = anonArg in pat1 -> expr1 ... | patN -> exprN)
+ //
+ // Note the presence of the "let" is visible in quotations regardless of the presence of sequence points, so
+ // <@ function x -> (x: int) @>
+ // is
+ // Lambda (_arg2, Let (x, _arg2, x))
+
+ | SynExpr.MatchLambda (isExnMatch, mArg, clauses, spMatch, m) ->
+
+ let domainTy, resultTy = UnifyFunctionType None cenv env.DisplayEnv m overallTy
+ let idv1, idve1 = mkCompGenLocal mArg (cenv.synArgNameGenerator.New()) domainTy
+ let envinner = ExitFamilyRegion env
+ let idv2, matchExpr, tpenv = TcAndPatternCompileMatchClauses m mArg (if isExnMatch then Throw else ThrowIncompleteMatchException) cenv None domainTy resultTy envinner tpenv clauses
+ let overallExpr = mkMultiLambda m [idv1] ((mkLet spMatch m idv2 idve1 matchExpr), resultTy)
+ overallExpr, tpenv
+
+ | SynExpr.Assert (x, m) ->
+ TcAssertExpr cenv overallTy env m tpenv x
+
+ | SynExpr.Fixed (_, m) ->
+ error(Error(FSComp.SR.tcFixedNotAllowed(), m))
+
+ // e: ty
+ | SynExpr.Typed (synBodyExpr, synType, m) ->
+ let tgtTy, tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType
+ UnifyTypes cenv env m overallTy tgtTy
+ let expr, tpenv = TcExpr cenv overallTy env tpenv synBodyExpr
+ expr, tpenv
+
+ // e :? ty
+ | SynExpr.TypeTest (synInnerExpr, tgtTy, m) ->
+ let innerExpr, srcTy, tpenv = TcExprOfUnknownType cenv env tpenv synInnerExpr
+ UnifyTypes cenv env m overallTy cenv.g.bool_ty
+ let tgtTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tgtTy
+ TcRuntimeTypeTest (*isCast*)false (*isOperator*)true cenv env.DisplayEnv m tgtTy srcTy
+ let expr = mkCallTypeTest cenv.g m tgtTy innerExpr
+ expr, tpenv
+
+ // SynExpr.AddressOf is noted in the syntax ast in order to recognize it as concrete type information
+ // during type checking, in particular prior to resolving overloads. This helps distinguish
+ // its use at method calls from the use of the conflicting 'ref' mechanism for passing byref parameters
+ | SynExpr.AddressOf (byref, synInnerExpr, opm, m) ->
+ TcExpr cenv overallTy env tpenv (mkSynPrefixPrim opm m (if byref then "~&" else "~&&") synInnerExpr)
+
+ | SynExpr.Upcast (synInnerExpr, _, m) | SynExpr.InferredUpcast (synInnerExpr, m) ->
+ let innerExpr, srcTy, tpenv = TcExprOfUnknownType cenv env tpenv synInnerExpr
+ let tgtTy, tpenv =
+ match synExpr with
+ | SynExpr.Upcast (_, tgtTy, m) ->
+ let tgtTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tgtTy
+ UnifyTypes cenv env m tgtTy overallTy
+ tgtTy, tpenv
+ | SynExpr.InferredUpcast _ ->
+ overallTy, tpenv
+ | _ -> failwith "upcast"
+ TcStaticUpcast cenv env.DisplayEnv m tgtTy srcTy
+ let expr = mkCoerceExpr(innerExpr, tgtTy, m, srcTy)
+ expr, tpenv
+
+ | SynExpr.Downcast (synInnerExpr, _, m) | SynExpr.InferredDowncast (synInnerExpr, m) ->
+ let innerExpr, srcTy, tpenv = TcExprOfUnknownType cenv env tpenv synInnerExpr
+ let tgtTy, tpenv, isOperator =
+ match synExpr with
+ | SynExpr.Downcast (_, tgtTy, m) ->
+ let tgtTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tgtTy
+ UnifyTypes cenv env m tgtTy overallTy
+ tgtTy, tpenv, true
+ | SynExpr.InferredDowncast _ -> overallTy, tpenv, false
+ | _ -> failwith "downcast"
+ TcRuntimeTypeTest (*isCast*)true isOperator cenv env.DisplayEnv m tgtTy srcTy
+
+ // TcRuntimeTypeTest ensures tgtTy is a nominal type. Hence we can insert a check here
+ // based on the nullness semantics of the nominal type.
+ let expr = mkCallUnbox cenv.g m tgtTy innerExpr
+ expr, tpenv
+
+ | SynExpr.Null m ->
+ AddCxTypeMustSupportNull env.DisplayEnv cenv.css m NoTrace overallTy
+ mkNull m overallTy, tpenv
+
+ | SynExpr.Lazy (synInnerExpr, m) ->
+ let innerTy = NewInferenceType ()
+ UnifyTypes cenv env m overallTy (mkLazyTy cenv.g innerTy)
+ let innerExpr, tpenv = TcExpr cenv innerTy env tpenv synInnerExpr
+ let expr = mkLazyDelayed cenv.g m innerTy (mkUnitDelayLambda cenv.g m innerExpr)
+ expr, tpenv
+
+ | SynExpr.Tuple (isExplicitStruct, args, _, m) ->
+ let tupInfo, argTys = UnifyTupleTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv m overallTy isExplicitStruct args
+ // No subsumption at tuple construction
+ let flexes = argTys |> List.map (fun _ -> false)
+ let args', tpenv = TcExprs cenv env m tpenv flexes argTys args
+ let expr = mkAnyTupled cenv.g m tupInfo args' argTys
+ expr, tpenv
+
+ | SynExpr.AnonRecd (isStruct, optOrigExpr, unsortedFieldExprs, mWholeExpr) ->
+ TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigExpr, unsortedFieldExprs, mWholeExpr)
+
+ | SynExpr.ArrayOrList (isArray, args, m) ->
+ CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights)
+
+ let argty = NewInferenceType ()
+ UnifyTypes cenv env m overallTy (if isArray then mkArrayType cenv.g argty else mkListTy cenv.g argty)
+
+ // Always allow subsumption if a nominal type is known prior to type checking any arguments
+ let flex = not (isTyparTy cenv.g argty)
+ let mutable first = true
+ let getInitEnv m =
+ if first then
+ first <- false
+ env
+ else
+ { env with eContextInfo = ContextInfo.CollectionElement (isArray, m) }
+
+ let args', tpenv = List.mapFold (fun tpenv (x: SynExpr) -> TcExprFlex cenv flex false argty (getInitEnv x.Range) tpenv x) tpenv args
+
+ let expr =
+ if isArray then Expr.Op (TOp.Array, [argty], args', m)
+ else List.foldBack (mkCons cenv.g argty) args' (mkNil cenv.g m argty)
+ expr, tpenv
+
+ | SynExpr.New (superInit, synObjTy, arg, mNewExpr) ->
+ let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.Use env tpenv synObjTy
+ UnifyTypes cenv env mNewExpr overallTy objTy
+ TcNewExpr cenv env tpenv objTy (Some synObjTy.Range) superInit arg mNewExpr
+
+ | SynExpr.ObjExpr (objTy, argopt, binds, extraImpls, mNewExpr, m) ->
+ CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.eAccessRights)
+ TcObjectExpr cenv overallTy env tpenv (objTy, argopt, binds, extraImpls, mNewExpr, m)
+
+ | SynExpr.Record (inherits, optOrigExpr, flds, mWholeExpr) ->
+ CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy, env.AccessRights)
+ TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr)
+
+ | SynExpr.While (spWhile, synGuardExpr, synBodyExpr, m) ->
+ UnifyTypes cenv env m overallTy cenv.g.unit_ty
+ let guardExpr, tpenv = TcExpr cenv cenv.g.bool_ty env tpenv synGuardExpr
+ let bodyExpr, tpenv = TcStmt cenv env tpenv synBodyExpr
+ mkWhile cenv.g (spWhile, NoSpecialWhileLoopMarker, guardExpr, bodyExpr, m), tpenv
+
+ | SynExpr.For (spBind, id, start, dir, finish, body, m) ->
+ UnifyTypes cenv env m overallTy cenv.g.unit_ty
+ let startExpr, tpenv = TcExpr cenv cenv.g.int_ty env tpenv start
+ let finishExpr, tpenv = TcExpr cenv cenv.g.int_ty env tpenv finish
+ let idv, _ = mkLocal id.idRange id.idText cenv.g.int_ty
+ let envinner = AddLocalVal cenv.tcSink m idv env
+
+ // notify name resolution sink about loop variable
+ let item = Item.Value(mkLocalValRef idv)
+ CallNameResolutionSink cenv.tcSink (idv.Range, env.NameEnv, item, emptyTyparInst, ItemOccurence.Binding, env.AccessRights)
+
+ let bodyExpr, tpenv = TcStmt cenv envinner tpenv body
+ mkFastForLoop cenv.g (spBind, m, idv, startExpr, dir, finishExpr, bodyExpr), tpenv
+
+ | SynExpr.ForEach (spForLoop, SeqExprOnly seqExprOnly, isFromSource, pat, enumSynExpr, bodySynExpr, m) ->
+ assert isFromSource
+ if seqExprOnly then warning (Error(FSComp.SR.tcExpressionRequiresSequence(), m))
+ TcForEachExpr cenv overallTy env tpenv (pat, enumSynExpr, bodySynExpr, m, spForLoop)
+
+ | SynExpr.CompExpr (isArrayOrList, isNotNakedRefCell, comp, m) ->
+ let env = ExitFamilyRegion env
+ cenv.TcSequenceExpressionEntry cenv env overallTy tpenv (isArrayOrList, isNotNakedRefCell, comp) m
+
+ | SynExpr.ArrayOrListOfSeqExpr (isArray, comp, m) ->
+ CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.eAccessRights)
+ cenv.TcArrayOrListSequenceExpression cenv env overallTy tpenv (isArray, comp) m
+
+ | SynExpr.LetOrUse _ ->
+ TcLinearExprs (TcExprThatCanBeCtorBody cenv) cenv env overallTy tpenv false synExpr (fun x -> x)
+
+ | SynExpr.TryWith (synBodyExpr, _mTryToWith, synWithClauses, mWithToLast, mTryToLast, spTry, spWith) ->
+ let bodyExpr, tpenv = TcExpr cenv overallTy env tpenv synBodyExpr
+ // Compile the pattern twice, once as a List.filter with all succeeding targets returning "1", and once as a proper catch block.
+ let filterClauses = synWithClauses |> List.map (function (Clause(pat, optWhenExpr, _, m, _)) -> Clause(pat, optWhenExpr, (SynExpr.Const (SynConst.Int32 1, m)), m, DebugPointForTarget.No))
+ let checkedFilterClauses, tpenv = TcMatchClauses cenv cenv.g.exn_ty cenv.g.int_ty env tpenv filterClauses
+ let checkedHandlerClauses, tpenv = TcMatchClauses cenv cenv.g.exn_ty overallTy env tpenv synWithClauses
+ let v1, filterExpr = CompilePatternForMatchClauses cenv env mWithToLast mWithToLast true FailFilter None cenv.g.exn_ty cenv.g.int_ty checkedFilterClauses
+ let v2, handlerExpr = CompilePatternForMatchClauses cenv env mWithToLast mWithToLast true Rethrow None cenv.g.exn_ty overallTy checkedHandlerClauses
+ mkTryWith cenv.g (bodyExpr, v1, filterExpr, v2, handlerExpr, mTryToLast, overallTy, spTry, spWith), tpenv
+
+ | SynExpr.TryFinally (synBodyExpr, synFinallyExpr, mTryToLast, spTry, spFinally) ->
+ let bodyExpr, tpenv = TcExpr cenv overallTy env tpenv synBodyExpr
+ let finallyExpr, tpenv = TcStmt cenv env tpenv synFinallyExpr
+ mkTryFinally cenv.g (bodyExpr, finallyExpr, mTryToLast, overallTy, spTry, spFinally), tpenv
+
+ | SynExpr.JoinIn (e1, mInToken, e2, mAll) ->
+ errorR(Error(FSComp.SR.parsUnfinishedExpression("in"), mInToken))
+ let _, _, tpenv = suppressErrorReporting (fun () -> TcExprOfUnknownType cenv env tpenv e1)
+ let _, _, tpenv = suppressErrorReporting (fun () -> TcExprOfUnknownType cenv env tpenv e2)
+ mkDefault(mAll, overallTy), tpenv
+
+ | SynExpr.ArbitraryAfterError (_debugStr, m) ->
+ //solveTypAsError cenv env.DisplayEnv m overallTy
+ mkDefault(m, overallTy), tpenv
+
+ // expr. (already reported as an error)
+ | SynExpr.DiscardAfterMissingQualificationAfterDot (e1, m) ->
+ let _, _, tpenv = suppressErrorReporting (fun () -> TcExprOfUnknownTypeThen cenv env tpenv e1 [DelayedDot])
+ mkDefault(m, overallTy), tpenv
+
+ | SynExpr.FromParseError (e1, m) ->
+ //solveTypAsError cenv env.DisplayEnv m overallTy
+ let _, tpenv = suppressErrorReporting (fun () -> TcExpr cenv overallTy env tpenv e1)
+ mkDefault(m, overallTy), tpenv
+
+ | SynExpr.Sequential (sp, dir, synExpr1, synExpr2, m) ->
+ if dir then
+ TcLinearExprs (TcExprThatCanBeCtorBody cenv) cenv env overallTy tpenv false synExpr (fun x -> x)
+ else
+ // Constructors using "new (...) = then "
+ let expr1, tpenv = TcExprThatCanBeCtorBody cenv overallTy env tpenv synExpr1
+ if (GetCtorShapeCounter env) <> 1 then
+ errorR(Error(FSComp.SR.tcExpressionFormRequiresObjectConstructor(), m))
+ let expr2, tpenv = TcStmtThatCantBeCtorBody cenv env tpenv synExpr2
+ Expr.Sequential (expr1, expr2, ThenDoSeq, sp, m), tpenv
+
+ // Used to implement the type-directed 'implicit yield' rule for computation expressions
+ | SynExpr.SequentialOrImplicitYield (sp, synExpr1, synExpr2, otherExpr, m) ->
+ let isStmt, expr1, tpenv = TryTcStmt cenv env tpenv synExpr1
+ if isStmt then
+ let env = ShrinkContext env m synExpr2.Range
+ let expr2, tpenv = TcExprThatCanBeCtorBody cenv overallTy env tpenv synExpr2
+ Expr.Sequential(expr1, expr2, NormalSeq, sp, m), tpenv
+ else
+ // The first expression wasn't unit-typed, so proceed to the alternative interpretation
+ // Note a copy of the first expression is embedded in 'otherExpr' and thus
+ // this will type-check the first expression over again.
+ TcExpr cenv overallTy env tpenv otherExpr
+
+ | SynExpr.Do (synInnerExpr, m) ->
+ UnifyTypes cenv env m overallTy cenv.g.unit_ty
+ TcStmtThatCantBeCtorBody cenv env tpenv synInnerExpr
+
+ | SynExpr.IfThenElse _ ->
+ TcLinearExprs (TcExprThatCanBeCtorBody cenv) cenv env overallTy tpenv false synExpr (fun x -> x)
+
+ // This is for internal use in the libraries only
+ | SynExpr.LibraryOnlyStaticOptimization (constraints, e2, e3, m) ->
+ let constraints', tpenv = List.mapFold (TcStaticOptimizationConstraint cenv env) tpenv constraints
+ // Do not force the types of the two expressions to be equal
+ // This means uses of this construct have to be very carefully written
+ let e2', _, tpenv = TcExprOfUnknownType cenv env tpenv e2
+ let e3', tpenv = TcExpr cenv overallTy env tpenv e3
+ Expr.StaticOptimization (constraints', e2', e3', m), tpenv
+
+ /// e1.longId <- e2
+ | SynExpr.DotSet (e1, (LongIdentWithDots(longId, _) as lidwd), e2, mStmt) ->
+ if lidwd.ThereIsAnExtraDotAtTheEnd then
+ // just drop rhs on the floor
+ let mExprAndDotLookup = unionRanges e1.Range (rangeOfLid longId)
+ TcExprThen cenv overallTy env tpenv e1 [DelayedDotLookup(longId, mExprAndDotLookup)]
+ else
+ let mExprAndDotLookup = unionRanges e1.Range (rangeOfLid longId)
+ TcExprThen cenv overallTy env tpenv e1 [DelayedDotLookup(longId, mExprAndDotLookup); MakeDelayedSet(e2, mStmt)]
+
+ /// e1 <- e2
+ | SynExpr.Set (e1, e2, mStmt) ->
+ TcExprThen cenv overallTy env tpenv e1 [MakeDelayedSet(e2, mStmt)]
+
+ /// e1.longId(e2) <- e3, very rarely used named property setters
+ | SynExpr.DotNamedIndexedPropertySet (e1, (LongIdentWithDots(longId, _) as lidwd), e2, e3, mStmt) ->
+ if lidwd.ThereIsAnExtraDotAtTheEnd then
+ // just drop rhs on the floor
+ let mExprAndDotLookup = unionRanges e1.Range (rangeOfLid longId)
+ TcExprThen cenv overallTy env tpenv e1 [DelayedDotLookup(longId, mExprAndDotLookup)]
+ else
+ let mExprAndDotLookup = unionRanges e1.Range (rangeOfLid longId)
+ TcExprThen cenv overallTy env tpenv e1 [DelayedDotLookup(longId, mExprAndDotLookup); DelayedApp(ExprAtomicFlag.Atomic, e2, mStmt); MakeDelayedSet(e3, mStmt)]
+
+ | SynExpr.LongIdentSet (lidwd, e2, m) ->
+ if lidwd.ThereIsAnExtraDotAtTheEnd then
+ // just drop rhs on the floor
+ TcLongIdentThen cenv overallTy env tpenv lidwd [ ]
+ else
+ TcLongIdentThen cenv overallTy env tpenv lidwd [ MakeDelayedSet(e2, m) ]
+
+ // Type.Items(e1) <- e2
+ | SynExpr.NamedIndexedPropertySet (lidwd, e1, e2, mStmt) ->
+ if lidwd.ThereIsAnExtraDotAtTheEnd then
+ // just drop rhs on the floor
+ TcLongIdentThen cenv overallTy env tpenv lidwd [ ]
+ else
+ TcLongIdentThen cenv overallTy env tpenv lidwd [ DelayedApp(ExprAtomicFlag.Atomic, e1, mStmt); MakeDelayedSet(e2, mStmt) ]
+
+ | SynExpr.TraitCall (tps, memSpfn, arg, m) ->
+ let synTypes = tps |> List.map (fun tp -> SynType.Var(tp, m))
+ let traitInfo, tpenv = TcPseudoMemberSpec cenv NewTyparsOK env synTypes tpenv memSpfn m
+ if BakedInTraitConstraintNames.Contains traitInfo.MemberName then
+ warning(BakedInMemberConstraintName(traitInfo.MemberName, m))
+
+ let argTys = traitInfo.ArgumentTypes
+ let returnTy = GetFSharpViewOfReturnType cenv.g traitInfo.ReturnType
+ let args, namedCallerArgs = GetMethodArgs arg
+ if not (isNil namedCallerArgs) then errorR(Error(FSComp.SR.tcNamedArgumentsCannotBeUsedInMemberTraits(), m))
+ // Subsumption at trait calls if arguments have nominal type prior to unification of any arguments or return type
+ let flexes = argTys |> List.map (isTyparTy cenv.g >> not)
+ let args', tpenv = TcExprs cenv env m tpenv flexes argTys args
+ AddCxMethodConstraint env.DisplayEnv cenv.css m NoTrace traitInfo
+ UnifyTypes cenv env m overallTy returnTy
+ Expr.Op (TOp.TraitCall traitInfo, [], args', m), tpenv
+
+ | SynExpr.LibraryOnlyUnionCaseFieldGet (e1, c, n, m) ->
+ let e1', ty1, tpenv = TcExprOfUnknownType cenv env tpenv e1
+ let mkf, ty2 = TcUnionCaseOrExnField cenv env ty1 m c n
+ ((fun (a, b) n -> mkUnionCaseFieldGetUnproven cenv.g (e1', a, b, n, m)),
+ (fun a n -> mkExnCaseFieldGet(e1', a, n, m)))
+ UnifyTypes cenv env m overallTy ty2
+ mkf n, tpenv
+
+ | SynExpr.LibraryOnlyUnionCaseFieldSet (e1, c, n, e2, m) ->
+ UnifyTypes cenv env m overallTy cenv.g.unit_ty
+ let e1', ty1, tpenv = TcExprOfUnknownType cenv env tpenv e1
+ let mkf, ty2 = TcUnionCaseOrExnField cenv env ty1 m c n
+ ((fun (a, b) n e2' ->
+ if not (isUnionCaseFieldMutable cenv.g a n) then errorR(Error(FSComp.SR.tcFieldIsNotMutable(), m))
+ mkUnionCaseFieldSet(e1', a, b, n, e2', m)),
+ (fun a n e2' ->
+ if not (isExnFieldMutable a n) then errorR(Error(FSComp.SR.tcFieldIsNotMutable(), m))
+ mkExnCaseFieldSet(e1', a, n, e2', m)))
+ let e2', tpenv = TcExpr cenv ty2 env tpenv e2
+ mkf n e2', tpenv
+
+ | SynExpr.LibraryOnlyILAssembly (s, tyargs, args, rtys, m) ->
+ let s = (s :?> ILInstr[])
+ let argTys = NewInferenceTypes args
+ let tyargs', tpenv = TcTypes cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tyargs
+ // No subsumption at uses of IL assembly code
+ let flexes = argTys |> List.map (fun _ -> false)
+ let args', tpenv = TcExprs cenv env m tpenv flexes argTys args
+ let rtys', tpenv = TcTypes cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv rtys
+ let returnTy =
+ match rtys' with
+ | [] -> cenv.g.unit_ty
+ | [ returnTy ] -> returnTy
+ | _ -> error(InternalError("Only zero or one pushed items are permitted in IL assembly code", m))
+ UnifyTypes cenv env m overallTy returnTy
+ mkAsmExpr (Array.toList s, tyargs', args', rtys', m), tpenv
+
+ | SynExpr.Quote (oper, raw, ast, isFromQueryExpression, m) ->
+ CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights)
+ TcQuotationExpr cenv overallTy env tpenv (oper, raw, ast, isFromQueryExpression, m)
+
+ | SynExpr.YieldOrReturn ((isTrueYield, _), _, m)
+ | SynExpr.YieldOrReturnFrom ((isTrueYield, _), _, m) when isTrueYield ->
+ error(Error(FSComp.SR.tcConstructRequiresListArrayOrSequence(), m))
+
+ | SynExpr.YieldOrReturn ((_, isTrueReturn), _, m)
+ | SynExpr.YieldOrReturnFrom ((_, isTrueReturn), _, m) when isTrueReturn ->
+ error(Error(FSComp.SR.tcConstructRequiresComputationExpressions(), m))
+
+ | SynExpr.YieldOrReturn (_, _, m)
+ | SynExpr.YieldOrReturnFrom (_, _, m)
+ | SynExpr.ImplicitZero m ->
+ error(Error(FSComp.SR.tcConstructRequiresSequenceOrComputations(), m))
+
+ | SynExpr.DoBang (_, m)
+ | SynExpr.LetOrUseBang (range=m) ->
+ error(Error(FSComp.SR.tcConstructRequiresComputationExpression(), m))
+
+ | SynExpr.MatchBang (_, _, _, m) ->
+ error(Error(FSComp.SR.tcConstructRequiresComputationExpression(), m))
+
+/// Check lambdas as a group, to catch duplicate names in patterns
+and TcIteratedLambdas cenv isFirst (env: TcEnv) overallTy takenNames tpenv e =
+ match e with
+ | SynExpr.Lambda (isMember, isSubsequent, spats, bodyExpr, _, m) when isMember || isFirst || isSubsequent ->
+ let domainTy, resultTy = UnifyFunctionType None cenv env.DisplayEnv m overallTy
+ let vs, (tpenv, names, takenNames) = TcSimplePats cenv isMember CheckCxs domainTy env (tpenv, Map.empty, takenNames) spats
+ let envinner, _, vspecMap = MakeAndPublishSimpleValsForMergedScope cenv env m names
+ let byrefs = vspecMap |> Map.map (fun _ v -> isByrefTy cenv.g v.Type, v)
+ let envinner = if isMember then envinner else ExitFamilyRegion envinner
+ let bodyExpr, tpenv = TcIteratedLambdas cenv false envinner resultTy takenNames tpenv bodyExpr
+ // See bug 5758: Non-monotonicity in inference: need to ensure that parameters are never inferred to have byref type, instead it is always declared
+ byrefs |> Map.iter (fun _ (orig, v) ->
+ if not orig && isByrefTy cenv.g v.Type then errorR(Error(FSComp.SR.tcParameterInferredByref v.DisplayName, v.Range)))
+ mkMultiLambda m (List.map (fun nm -> NameMap.find nm vspecMap) vs) (bodyExpr, resultTy), tpenv
+ | e ->
+ // Dive into the expression to check for syntax errors and suppress them if they show.
+ conditionallySuppressErrorReporting (not isFirst && synExprContainsError e) (fun () ->
+ //TcExprFlex cenv true true overallTy env tpenv e)
+ TcExpr cenv overallTy env tpenv e)
+
+
+// Check expr.[idx]
+// This is a little over complicated for my liking. Basically we want to interpret e1.[idx] as e1.Item(idx).
+// However it's not so simple as all that. First "Item" can have a different name according to an attribute in
+// .NET metadata. This means we manually typecheck 'e1' and look to see if it has a nominal type. We then
+// do the right thing in each case.
+and TcIndexerThen cenv env overallTy mWholeExpr mDot tpenv wholeExpr e1 indexArgs delayed =
+ let ad = env.AccessRights
+ let e1', e1ty, tpenv = TcExprOfUnknownType cenv env tpenv e1
+
+ // Find the first type in the effective hierarchy that either has a DefaultMember attribute OR
+ // has a member called 'Item'
+ let isIndex = indexArgs |> List.forall( fun x -> match x with SynIndexerArg.One _ -> true | _ -> false)
+ let propName =
+ if isIndex then
+ FoldPrimaryHierarchyOfType (fun ty acc ->
+ match acc with
+ | None ->
+ match tryTcrefOfAppTy cenv.g ty with
+ | ValueSome tcref ->
+ TryFindTyconRefStringAttribute cenv.g mWholeExpr cenv.g.attrib_DefaultMemberAttribute tcref
+ | _ ->
+ let item = Some "Item"
+ match AllPropInfosOfTypeInScope ResultCollectionSettings.AtMostOneResult cenv.infoReader env.NameEnv item ad IgnoreOverrides mWholeExpr ty with
+ | [] -> None
+ | _ -> item
+ | _ -> acc)
+ cenv.g
+ cenv.amap
+ mWholeExpr
+ AllowMultiIntfInstantiations.Yes
+ e1ty
+ None
+ else Some "GetSlice"
+
+ let isNominal = isAppTy cenv.g e1ty
+
+ let isArray = isArrayTy cenv.g e1ty
+ let isString = typeEquiv cenv.g cenv.g.string_ty e1ty
+
+ let idxRange = indexArgs |> List.map (fun e -> e.Range) |> List.reduce unionRanges
+
+ // xs.GetReverseIndex rank offset - 1
+ let rewriteReverseExpr (rank: int) (offset: SynExpr) (range: range) =
+ let rankExpr = SynExpr.Const(SynConst.Int32(rank), range)
+ let sliceArgs = SynExpr.Paren(SynExpr.Tuple(false, [rankExpr; offset], [], range), range, Some range, range)
+ let xsId = e1
+
+ mkSynApp1
+ (mkSynDot range range xsId (mkSynId range "GetReverseIndex"))
+ sliceArgs
+ range
+
+ let rewriteReverseOption (app: SynExpr) (rank: int) (range: range) =
+ match app with
+ | SynExpr.App(atomicFlag, isInfix, funcExpr, e1, outerRange) -> SynExpr.App(atomicFlag, isInfix, funcExpr, rewriteReverseExpr rank e1 range, outerRange)
+ | _ -> app
+
+ let expandedIndexArgs =
+ indexArgs
+ |> List.mapi ( fun pos indexerArg ->
+ match indexerArg with
+ | SynIndexerArg.One(expr, fromEnd, range) ->
+ [ if fromEnd then rewriteReverseExpr pos expr range else expr ]
+ | SynIndexerArg.Two
+ (
+ a1,
+ fromEnd1,
+ a2,
+ fromEnd2,
+ range1,
+ range2) ->
+ [
+ if fromEnd1 then rewriteReverseOption a1 pos range1 else a1 ;
+ if fromEnd2 then rewriteReverseOption a2 pos range2 else a2
+ ]
+ )
+ |> List.collect (id)
+
+ let MakeIndexParam setSliceArrayOption =
+ match indexArgs with
+ | [] -> failwith "unexpected empty index list"
+ | [SynIndexerArg.One _] -> SynExpr.Paren (expandedIndexArgs.Head, range0, None, idxRange)
+ | _ -> SynExpr.Paren (SynExpr.Tuple (false, expandedIndexArgs @ Option.toList setSliceArrayOption, [], idxRange), range0, None, idxRange)
+
+ let attemptArrayString =
+ let indexOpPath = ["Microsoft";"FSharp";"Core";"LanguagePrimitives";"IntrinsicFunctions"]
+ let sliceOpPath = ["Microsoft";"FSharp";"Core";"Operators";"OperatorIntrinsics"]
+
+ let info =
+ if isArray then
+ let fixedIndex3d4dEnabled = cenv.g.langVersion.SupportsFeature LanguageFeature.FixedIndexSlice3d4d
+ match wholeExpr with
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _; SynIndexerArg.One _], _, _) -> Some (indexOpPath, "GetArray2D", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _; SynIndexerArg.One _; SynIndexerArg.One _;], _, _) -> Some (indexOpPath, "GetArray3D", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _; SynIndexerArg.One _; SynIndexerArg.One _; SynIndexerArg.One _], _, _) -> Some (indexOpPath, "GetArray4D", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _], _, _) -> Some (indexOpPath, "GetArray", expandedIndexArgs)
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _; SynIndexerArg.One _], e3, _, _, _) -> Some (indexOpPath, "SetArray2D", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _; SynIndexerArg.One _; SynIndexerArg.One _;], e3, _, _, _) -> Some (indexOpPath, "SetArray3D", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _; SynIndexerArg.One _; SynIndexerArg.One _; SynIndexerArg.One _], e3, _, _, _) -> Some (indexOpPath, "SetArray4D", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _], e3, _, _, _) -> Some (indexOpPath, "SetArray", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice2DFixed1", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.One _], _, _) -> Some (sliceOpPath, "GetArraySlice2DFixed2", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice2D", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice3D", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice4D", expandedIndexArgs)
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice2D", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice2DFixed1", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.One _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice2DFixed2", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice3D", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4D", (expandedIndexArgs @ [e3]))
+ | _ when fixedIndex3d4dEnabled ->
+ match wholeExpr with
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice3DFixedSingle1", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice3DFixedSingle2", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.One _], _, _) -> Some (sliceOpPath, "GetArraySlice3DFixedSingle3", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice3DFixedDouble1", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.One _], _, _) -> Some (sliceOpPath, "GetArraySlice3DFixedDouble2", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.One _], _, _) -> Some (sliceOpPath, "GetArraySlice3DFixedDouble3", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedSingle1", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedSingle2", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedSingle3", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.One _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedSingle4", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedDouble1", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedDouble2", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.One _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedDouble3", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedDouble4", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.One _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedDouble5", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.One _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedDouble6", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.One _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedTriple1", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.One _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedTriple2", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.One _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedTriple3", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetArraySlice4DFixedTriple4", expandedIndexArgs)
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice3DFixedSingle1", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice3DFixedSingle2", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.One _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice3DFixedSingle3", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice3DFixedDouble1", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.One _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice3DFixedDouble2", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.One _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice3DFixedDouble3", (expandedIndexArgs @ [e3]))
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedSingle1", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedSingle2", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedSingle3", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.One _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedSingle4", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedDouble1", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedDouble2", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.One _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedDouble3", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedDouble4", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.One _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedDouble5", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.One _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedDouble6", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.One _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedTriple1", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.One _;SynIndexerArg.One _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedTriple2", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.Two _;SynIndexerArg.One _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedTriple3", expandedIndexArgs @ [e3])
+ | SynExpr.DotIndexedSet (_, [SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.One _;SynIndexerArg.Two _], e3, _, _, _) -> Some (sliceOpPath, "SetArraySlice4DFixedTriple4", expandedIndexArgs @ [e3])
+ | _ -> None
+ | _ -> None
+
+ elif isString then
+ match wholeExpr with
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.Two _], _, _) -> Some (sliceOpPath, "GetStringSlice", expandedIndexArgs)
+ | SynExpr.DotIndexedGet (_, [SynIndexerArg.One _], _, _) -> Some (indexOpPath, "GetString", expandedIndexArgs)
+ | _ -> None
+
+ else None
+
+ match info with
+ | None -> None
+ | Some (path, functionName, indexArgs) ->
+ let operPath = mkSynLidGet mDot path (CompileOpName functionName)
+ let f, fty, tpenv = TcExprOfUnknownType cenv env tpenv operPath
+ let domainTy, resultTy = UnifyFunctionType (Some mWholeExpr) cenv env.DisplayEnv mWholeExpr fty
+ UnifyTypes cenv env mWholeExpr domainTy e1ty
+ let f', resultTy = buildApp cenv (MakeApplicableExprNoFlex cenv f) resultTy e1' mWholeExpr
+ let delayed = List.foldBack (fun idx acc -> DelayedApp(ExprAtomicFlag.Atomic, idx, mWholeExpr) :: acc) indexArgs delayed // atomic, otherwise no ar.[1] <- xyz
+ Some (PropagateThenTcDelayed cenv overallTy env tpenv mWholeExpr f' resultTy ExprAtomicFlag.Atomic delayed )
+
+ match attemptArrayString with
+ | Some res -> res
+ | None ->
+ if isNominal || Option.isSome propName then
+ let nm =
+ match propName with
+ | None -> "Item"
+ | Some nm -> nm
+ let delayed =
+ match wholeExpr with
+ // e1.[e2]
+ | SynExpr.DotIndexedGet _ ->
+ DelayedDotLookup([ident(nm, mWholeExpr)], mWholeExpr) :: DelayedApp(ExprAtomicFlag.Atomic, MakeIndexParam None, mWholeExpr) :: delayed
+ // e1.[e2] <- e3
+ | SynExpr.DotIndexedSet (_, _, e3, mOfLeftOfSet, _, _) ->
+ match isIndex with
+ | true -> DelayedDotLookup([ident(nm, mOfLeftOfSet)], mOfLeftOfSet) :: DelayedApp(ExprAtomicFlag.Atomic, MakeIndexParam None, mOfLeftOfSet) :: MakeDelayedSet(e3, mWholeExpr) :: delayed
+ | false -> DelayedDotLookup([ident("SetSlice", mOfLeftOfSet)], mOfLeftOfSet) :: DelayedApp(ExprAtomicFlag.Atomic, MakeIndexParam (Some e3), mWholeExpr) :: delayed
+
+ | _ -> error(InternalError("unreachable", mWholeExpr))
+ PropagateThenTcDelayed cenv overallTy env tpenv mDot (MakeApplicableExprNoFlex cenv e1') e1ty ExprAtomicFlag.Atomic delayed
+
+ else
+ // deprecated constrained lookup
+ error(Error(FSComp.SR.tcObjectOfIndeterminateTypeUsedRequireTypeConstraint(), mWholeExpr))
+
+
+/// Check a 'new Type(args)' expression, also an 'inheritedTys declaration in an implicit or explicit class
+/// For 'new Type(args)', mWholeExprOrObjTy is the whole expression
+/// For 'inherit Type(args)', mWholeExprOrObjTy is the whole expression
+/// For an implicit inherit from System.Object or a default constructor, mWholeExprOrObjTy is the type name of the type being defined
+and TcNewExpr cenv env tpenv objTy mObjTyOpt superInit arg mWholeExprOrObjTy =
+ let ad = env.AccessRights
+ // Handle the case 'new 'a()'
+ if (isTyparTy cenv.g objTy) then
+ if superInit then error(Error(FSComp.SR.tcCannotInheritFromVariableType(), mWholeExprOrObjTy))
+ AddCxTypeMustSupportDefaultCtor env.DisplayEnv cenv.css mWholeExprOrObjTy NoTrace objTy
+
+ match arg with
+ | SynExpr.Const (SynConst.Unit, _) -> ()
+ | _ -> errorR(Error(FSComp.SR.tcObjectConstructorsOnTypeParametersCannotTakeArguments(), mWholeExprOrObjTy))
+
+ mkCallCreateInstance cenv.g mWholeExprOrObjTy objTy, tpenv
+ else
+ if not (isAppTy cenv.g objTy) && not (isAnyTupleTy cenv.g objTy) then error(Error(FSComp.SR.tcNamedTypeRequired(if superInit then "inherit" else "new"), mWholeExprOrObjTy))
+ let item = ForceRaise (ResolveObjectConstructor cenv.nameResolver env.DisplayEnv mWholeExprOrObjTy ad objTy)
+
+ TcCtorCall false cenv env tpenv objTy objTy mObjTyOpt item superInit [arg] mWholeExprOrObjTy [] None
+
+/// Check an 'inheritedTys declaration in an implicit or explicit class
+and TcCtorCall isNaked cenv env tpenv overallTy objTy mObjTyOpt item superInit args mWholeCall delayed afterTcOverloadResolutionOpt =
+ let ad = env.AccessRights
+ let isSuperInit = (if superInit then CtorValUsedAsSuperInit else NormalValUse)
+ let mItem = match mObjTyOpt with Some m -> m | None -> mWholeCall
+
+ if isInterfaceTy cenv.g objTy then
+ error(Error((if superInit then FSComp.SR.tcInheritCannotBeUsedOnInterfaceType() else FSComp.SR.tcNewCannotBeUsedOnInterfaceType()), mWholeCall))
+
+ match item, args with
+ | Item.CtorGroup(methodName, minfos), _ ->
+ let meths = List.map (fun minfo -> minfo, None) minfos
+ if isNaked && TypeFeasiblySubsumesType 0 cenv.g cenv.amap mWholeCall cenv.g.system_IDisposable_ty NoCoerce objTy then
+ warning(Error(FSComp.SR.tcIDisposableTypeShouldUseNew(), mWholeCall))
+
+ // Check the type is not abstract
+ // skip this check if this ctor call is either 'inherit(...)' or call is located within constructor shape
+ if not (superInit || AreWithinCtorShape env)
+ then CheckSuperInit cenv objTy mWholeCall
+
+ let afterResolution =
+ match mObjTyOpt, afterTcOverloadResolutionOpt with
+ | _, Some action -> action
+ | Some mObjTy, None -> ForNewConstructors cenv.tcSink env mObjTy methodName minfos
+ | None, _ -> AfterResolution.DoNothing
+
+ TcMethodApplicationThen cenv env overallTy (Some objTy) tpenv None [] mWholeCall mItem methodName ad PossiblyMutates false meths afterResolution isSuperInit args ExprAtomicFlag.NonAtomic delayed
+
+ | Item.DelegateCtor ty, [arg] ->
+ // Re-record the name resolution since we now know it's a constructor call
+ match mObjTyOpt with
+ | Some mObjTy -> CallNameResolutionSink cenv.tcSink (mObjTy, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.AccessRights)
+ | None -> ()
+ TcNewDelegateThen cenv objTy env tpenv mItem mWholeCall ty arg ExprAtomicFlag.NonAtomic delayed
+
+ | _ ->
+ error(Error(FSComp.SR.tcSyntaxCanOnlyBeUsedToCreateObjectTypes(if superInit then "inherit" else "new"), mWholeCall))
+
+
+// Check a record construction expression
+and TcRecordConstruction cenv overallTy env tpenv optOrigExprInfo objTy fldsList m =
+ let tcref, tinst = destAppTy cenv.g objTy
+ let tycon = tcref.Deref
+ UnifyTypes cenv env m overallTy objTy
+
+ // Types with implicit constructors can't use record or object syntax: all constructions must go through the implicit constructor
+ if tycon.MembersOfFSharpTyconByName |> NameMultiMap.existsInRange (fun v -> v.IsIncrClassConstructor) then
+ errorR(Error(FSComp.SR.tcConstructorRequiresCall(tycon.DisplayName), m))
+
+ let fspecs = tycon.TrueInstanceFieldsAsList
+ // Freshen types and work out their subtype flexibility
+ let fldsList =
+ [ for (fname, fexpr) in fldsList do
+ let fspec =
+ try
+ fspecs |> List.find (fun fspec -> fspec.Name = fname)
+ with :? KeyNotFoundException ->
+ error (Error(FSComp.SR.tcUndefinedField(fname, NicePrint.minimalStringOfType env.DisplayEnv objTy), m))
+ let fty = actualTyOfRecdFieldForTycon tycon tinst fspec
+ let flex = not (isTyparTy cenv.g fty)
+ yield (fname, fexpr, fty, flex) ]
+
+ // Type check and generalize the supplied bindings
+ let fldsList, tpenv =
+ let env = { env with eContextInfo = ContextInfo.RecordFields }
+ (tpenv, fldsList) ||> List.mapFold (fun tpenv (fname, fexpr, fty, flex) ->
+ let fieldExpr, tpenv = TcExprFlex cenv flex false fty env tpenv fexpr
+ (fname, fieldExpr), tpenv)
+
+ // Add rebindings for unbound field when an "old value" is available
+ // Effect order: mutable fields may get modified by other bindings...
+ let oldFldsList =
+ match optOrigExprInfo with
+ | None -> []
+ | Some (_, _, oldvaddre) ->
+ let fieldNameUnbound nom = List.forall (fun (name, _) -> name <> nom) fldsList
+ let flds =
+ fspecs |> List.choose (fun rfld ->
+ if fieldNameUnbound rfld.Name && not rfld.IsZeroInit
+ then Some(rfld.Name, mkRecdFieldGetViaExprAddr (oldvaddre, tcref.MakeNestedRecdFieldRef rfld, tinst, m))
+ else None)
+ flds
+
+ let fldsList = fldsList @ oldFldsList
+
+ // From now on only interested in fspecs that truly need values.
+ let fspecs = fspecs |> List.filter (fun f -> not f.IsZeroInit)
+
+ // Check all fields are bound
+ fspecs |> List.iter (fun fspec ->
+ if not (fldsList |> List.exists (fun (fname, _) -> fname = fspec.Name)) then
+ error(Error(FSComp.SR.tcFieldRequiresAssignment(fspec.rfield_id.idText, fullDisplayTextOfTyconRef tcref), m)))
+
+ // Other checks (overlap with above check now clear)
+ let ns1 = NameSet.ofList (List.map fst fldsList)
+ let ns2 = NameSet.ofList (List.map (fun x -> x.rfield_id.idText) fspecs)
+
+ if optOrigExprInfo.IsNone && not (Zset.subset ns2 ns1) then
+ error (MissingFields(Zset.elements (Zset.diff ns2 ns1), m))
+
+ if not (Zset.subset ns1 ns2) then
+ error (Error(FSComp.SR.tcExtraneousFieldsGivenValues(), m))
+
+ // Build record
+ let rfrefs = List.map (fst >> mkRecdFieldRef tcref) fldsList
+
+ // Check accessibility: this is also done in BuildFieldMap, but also need to check
+ // for fields in { new R with a=1 and b=2 } constructions and { r with a=1 } copy-and-update expressions
+ rfrefs |> List.iter (fun rfref ->
+ CheckRecdFieldAccessible cenv.amap m env.eAccessRights rfref |> ignore
+ CheckFSharpAttributes cenv.g rfref.PropertyAttribs m |> CommitOperationResult)
+
+ let args = List.map snd fldsList
+
+ let expr = mkRecordExpr cenv.g (GetRecdInfo env, tcref, tinst, rfrefs, args, m)
+
+ let expr =
+ match optOrigExprInfo with
+ | None ->
+ // '{ recd fields }'. //
+ expr
+
+ | Some (old, oldvaddr, _) ->
+ // '{ recd with fields }'.
+ // Assign the first object to a tmp and then construct
+ let wrap, oldaddr, _readonly, _writeonly = mkExprAddrOfExpr cenv.g tycon.IsStructOrEnumTycon false NeverMutates old None m
+ wrap (mkCompGenLet m oldvaddr oldaddr expr)
+
+ expr, tpenv
+
+//-------------------------------------------------------------------------
+// TcObjectExpr
+//-------------------------------------------------------------------------
+
+and GetNameAndArityOfObjExprBinding _cenv _env b =
+ let (NormalizedBinding (_, _, _, _, _, _, _, valSynData, pat, rhsExpr, mBinding, _)) = b
+ let (SynValData(memberFlagsOpt, valSynInfo, _)) = valSynData
+ match pat, memberFlagsOpt with
+
+ // This is the normal case for F# 'with member x.M(...) = ...'
+ | SynPat.InstanceMember(_thisId, memberId, _, None, _), Some memberFlags ->
+ let logicalMethId = ident (ComputeLogicalName memberId memberFlags, memberId.idRange)
+ logicalMethId.idText, valSynInfo
+
+ | _ ->
+ // This is for the deprecated form 'with M(...) = ...'
+ let rec lookPat pat =
+ match pat with
+ | SynPat.Typed(pat, _, _) -> lookPat pat
+ | SynPat.FromParseError(pat, _) -> lookPat pat
+ | SynPat.Named (SynPat.Wild _, id, _, None, _) ->
+ let (NormalizedBindingRhs(pushedPats, _, _)) = rhsExpr
+ let infosForExplicitArgs = pushedPats |> List.map SynInfo.InferSynArgInfoFromSimplePats
+ let infosForExplicitArgs = SynInfo.AdjustMemberArgs MemberKind.Member infosForExplicitArgs
+ let infosForExplicitArgs = SynInfo.AdjustArgsForUnitElimination infosForExplicitArgs
+ let argInfos = [SynInfo.selfMetadata] @ infosForExplicitArgs
+ let retInfo = SynInfo.unnamedRetVal //SynInfo.InferSynReturnData pushedRetInfoOpt
+ let valSynData = SynValInfo(argInfos, retInfo)
+ (id.idText, valSynData)
+ | _ -> error(Error(FSComp.SR.tcObjectExpressionsCanOnlyOverrideAbstractOrVirtual(), mBinding))
+
+ lookPat pat
+
+
+and FreshenObjExprAbstractSlot cenv (env: TcEnv) (implty: TType) virtNameAndArityPairs (bind, bindAttribs, bindName, absSlots:(_ * MethInfo) list) =
+ let (NormalizedBinding (_, _, _, _, _, _, synTyparDecls, _, _, _, mBinding, _)) = bind
+ match absSlots with
+ | [] when not (CompileAsEvent cenv.g bindAttribs) ->
+ let absSlotsByName = List.filter (fst >> fst >> (=) bindName) virtNameAndArityPairs
+ let getSignature absSlot = (NicePrint.stringOfMethInfo cenv.amap mBinding env.DisplayEnv absSlot).Replace("abstract ", "")
+ let getDetails (absSlot: MethInfo) =
+ if absSlot.GetParamTypes(cenv.amap, mBinding, []) |> List.existsSquared (isAnyTupleTy cenv.g) then
+ FSComp.SR.tupleRequiredInAbstractMethod()
+ else ""
+
+ // Compute the argument counts of the member arguments
+ let _, synValInfo = GetNameAndArityOfObjExprBinding cenv env bind
+ let arity =
+ match SynInfo.AritiesOfArgs synValInfo with
+ | _ :: x :: _ -> x
+ | _ -> 0
+
+ match absSlotsByName with
+ | [] ->
+ let tcref = tcrefOfAppTy cenv.g implty
+ let containsNonAbstractMemberWithSameName =
+ tcref.MembersOfFSharpTyconByName
+ |> Seq.exists (fun kv -> kv.Value |> List.exists (fun valRef -> valRef.DisplayName = bindName))
+
+ let suggestVirtualMembers (addToBuffer: string -> unit) =
+ for ((x,_),_) in virtNameAndArityPairs do
+ addToBuffer x
+
+ if containsNonAbstractMemberWithSameName then
+ errorR(ErrorWithSuggestions(FSComp.SR.tcMemberFoundIsNotAbstractOrVirtual(tcref.DisplayName, bindName), mBinding, bindName, suggestVirtualMembers))
+ else
+ errorR(ErrorWithSuggestions(FSComp.SR.tcNoAbstractOrVirtualMemberFound bindName, mBinding, bindName, suggestVirtualMembers))
+ | [(_, absSlot: MethInfo)] ->
+ errorR(Error(FSComp.SR.tcArgumentArityMismatch(bindName, List.sum absSlot.NumArgs, arity, getSignature absSlot, getDetails absSlot), mBinding))
+ | (_, absSlot: MethInfo) :: _ ->
+ errorR(Error(FSComp.SR.tcArgumentArityMismatchOneOverload(bindName, List.sum absSlot.NumArgs, arity, getSignature absSlot, getDetails absSlot), mBinding))
+
+ None
+
+ | [(_, absSlot)] ->
+
+ let typarsFromAbsSlotAreRigid, typarsFromAbsSlot, argTysFromAbsSlot, retTyFromAbsSlot
+ = FreshenAbstractSlot cenv.g cenv.amap mBinding synTyparDecls absSlot
+
+ // Work out the required type of the member
+ let bindingTy = implty --> (mkMethodTy cenv.g argTysFromAbsSlot retTyFromAbsSlot)
+
+ Some(typarsFromAbsSlotAreRigid, typarsFromAbsSlot, bindingTy)
+
+ | _ ->
+ None
+
+
+and TcObjectExprBinding cenv (env: TcEnv) implty tpenv (absSlotInfo, bind) =
+ // 4a1. normalize the binding (note: needlessly repeating what we've done above)
+ let (NormalizedBinding(vis, bkind, isInline, isMutable, attrs, doc, synTyparDecls, valSynData, p, bindingRhs, mBinding, spBind)) = bind
+ let (SynValData(memberFlagsOpt, _, _)) = valSynData
+ // 4a2. adjust the binding, especially in the "member" case, a subset of the logic of AnalyzeAndMakeAndPublishRecursiveValue
+ let bindingRhs, logicalMethId, memberFlags =
+ let rec lookPat p =
+ match p, memberFlagsOpt with
+ | SynPat.FromParseError(pat, _), _ -> lookPat pat
+ | SynPat.Named (SynPat.Wild _, id, _, _, _), None ->
+ let bindingRhs = PushOnePatternToRhs cenv true (mkSynThisPatVar (ident (CompilerGeneratedName "this", id.idRange))) bindingRhs
+ let logicalMethId = id
+ let memberFlags = OverrideMemberFlags MemberKind.Member
+ bindingRhs, logicalMethId, memberFlags
+
+ | SynPat.InstanceMember(thisId, memberId, _, _, _), Some memberFlags ->
+ CheckMemberFlags None NewSlotsOK OverridesOK memberFlags mBinding
+ let bindingRhs = PushOnePatternToRhs cenv true (mkSynThisPatVar thisId) bindingRhs
+ let logicalMethId = ident (ComputeLogicalName memberId memberFlags, memberId.idRange)
+ bindingRhs, logicalMethId, memberFlags
+ | _ ->
+ error(InternalError("unexpected member binding", mBinding))
+ lookPat p
+ let bind = NormalizedBinding (vis, bkind, isInline, isMutable, attrs, doc, synTyparDecls, valSynData, mkSynPatVar vis logicalMethId, bindingRhs, mBinding, spBind)
+
+ // 4b. typecheck the binding
+ let bindingTy =
+ match absSlotInfo with
+ | Some(_, _, memberTyFromAbsSlot) ->
+ memberTyFromAbsSlot
+ | _ ->
+ implty --> NewInferenceType ()
+
+ let (CheckedBindingInfo(inlineFlag, bindingAttribs, _, _, ExplicitTyparInfo(_, declaredTypars, _), nameToPrelimValSchemeMap, rhsExpr, _, _, m, _, _, _, _), tpenv) =
+ let explicitTyparInfo, tpenv = TcNonrecBindingTyparDecls cenv env tpenv bind
+ TcNormalizedBinding ObjectExpressionOverrideBinding cenv env tpenv bindingTy None NoSafeInitInfo ([], explicitTyparInfo) bind
+
+ // 4c. generalize the binding - only relevant when implementing a generic virtual method
+
+ match NameMap.range nameToPrelimValSchemeMap with
+ | [PrelimValScheme1(id, _, _, _, _, _, _, _, _, _, _)] ->
+ let denv = env.DisplayEnv
+
+ let declaredTypars =
+ match absSlotInfo with
+ | Some(typarsFromAbsSlotAreRigid, typarsFromAbsSlot, _) ->
+ if typarsFromAbsSlotAreRigid then typarsFromAbsSlot else declaredTypars
+ | _ ->
+ declaredTypars
+ // Canonicalize constraints prior to generalization
+ ConstraintSolver.CanonicalizePartialInferenceProblem cenv.css denv m declaredTypars
+
+ let freeInEnv = GeneralizationHelpers.ComputeUngeneralizableTypars env
+
+ let generalizedTypars = GeneralizationHelpers.ComputeAndGeneralizeGenericTypars(cenv, denv, m, freeInEnv, false, CanGeneralizeConstrainedTypars, inlineFlag, Some rhsExpr, declaredTypars, [], bindingTy, false)
+ let declaredTypars = ChooseCanonicalDeclaredTyparsAfterInference cenv.g env.DisplayEnv declaredTypars m
+
+ let generalizedTypars = PlaceTyparsInDeclarationOrder declaredTypars generalizedTypars
+
+ (id, memberFlags, (generalizedTypars +-> bindingTy), bindingAttribs, rhsExpr), tpenv
+ | _ ->
+ error(Error(FSComp.SR.tcSimpleMethodNameRequired(), m))
+
+and ComputeObjectExprOverrides cenv (env: TcEnv) tpenv impls =
+
+ // Compute the method sets each implemented type needs to implement
+ let slotImplSets = DispatchSlotChecking.GetSlotImplSets cenv.infoReader env.DisplayEnv env.AccessRights true (impls |> List.map (fun (m, ty, _) -> ty, m))
+
+ let allImpls =
+ (impls, slotImplSets) ||> List.map2 (fun (m, ty, binds) implTySet ->
+ let binds = binds |> List.map (BindingNormalization.NormalizeBinding ObjExprBinding cenv env)
+ m, ty, binds, implTySet)
+
+ let overridesAndVirts, tpenv =
+ (tpenv, allImpls) ||> List.mapFold (fun tpenv (m, implty, binds, SlotImplSet(reqdSlots, dispatchSlotsKeyed, availPriorOverrides, _) ) ->
+
+ // Generate extra bindings fo object expressions with bindings using the CLIEvent attribute
+ let binds, bindsAttributes =
+ [ for binding in binds do
+ let (NormalizedBinding(_, _, _, _, bindingSynAttribs, _, _, valSynData, _, _, _, _)) = binding
+ let (SynValData(memberFlagsOpt, _, _)) = valSynData
+ let attrTgt = DeclKind.AllowedAttribTargets memberFlagsOpt ObjectExpressionOverrideBinding
+ let bindingAttribs = TcAttributes cenv env attrTgt bindingSynAttribs
+ yield binding, bindingAttribs
+ for extraBinding in EventDeclarationNormalization.GenerateExtraBindings cenv (bindingAttribs, binding) do
+ yield extraBinding, [] ]
+ |> List.unzip
+
+ // 2. collect all name/arity of all overrides
+ let dispatchSlots = reqdSlots |> List.map (fun reqdSlot -> reqdSlot.MethodInfo)
+ let virtNameAndArityPairs = dispatchSlots |> List.map (fun virt ->
+ let vkey = (virt.LogicalName, virt.NumArgs)
+ //dprintfn "vkey = %A" vkey
+ (vkey, virt))
+ let bindNameAndSynInfoPairs = binds |> List.map (GetNameAndArityOfObjExprBinding cenv env)
+ let bindNames = bindNameAndSynInfoPairs |> List.map fst
+ let bindKeys =
+ bindNameAndSynInfoPairs |> List.map (fun (name, valSynData) ->
+ // Compute the argument counts of the member arguments
+ let argCounts = (SynInfo.AritiesOfArgs valSynData).Tail
+ //dprintfn "name = %A, argCounts = %A" name argCounts
+ (name, argCounts))
+
+ // 3. infer must-have types by name/arity
+ let preAssignedVirtsPerBinding =
+ bindKeys |> List.map (fun bkey -> List.filter (fst >> (=) bkey) virtNameAndArityPairs)
+
+ let absSlotInfo =
+ (List.zip4 binds bindsAttributes bindNames preAssignedVirtsPerBinding)
+ |> List.map (FreshenObjExprAbstractSlot cenv env implty virtNameAndArityPairs)
+
+ // 4. typecheck/typeinfer/generalizer overrides using this information
+ let overrides, tpenv = (tpenv, List.zip absSlotInfo binds) ||> List.mapFold (TcObjectExprBinding cenv env implty)
+
+ // Convert the syntactic info to actual info
+ let overrides =
+ (overrides, bindNameAndSynInfoPairs) ||> List.map2 (fun (id: Ident, memberFlags, ty, bindingAttribs, bindingBody) (_, valSynData) ->
+ let partialValInfo = TranslateTopValSynInfo id.idRange (TcAttributes cenv env) valSynData
+ let tps, _ = tryDestForallTy cenv.g ty
+ let valInfo = TranslatePartialArity tps partialValInfo
+ DispatchSlotChecking.GetObjectExprOverrideInfo cenv.g cenv.amap (implty, id, memberFlags, ty, valInfo, bindingAttribs, bindingBody))
+
+ (m, implty, reqdSlots, dispatchSlotsKeyed, availPriorOverrides, overrides), tpenv)
+
+ overridesAndVirts, tpenv
+
+and CheckSuperType cenv ty m =
+ if typeEquiv cenv.g ty cenv.g.system_Value_ty ||
+ typeEquiv cenv.g ty cenv.g.system_Enum_ty ||
+ typeEquiv cenv.g ty cenv.g.system_Array_ty ||
+ typeEquiv cenv.g ty cenv.g.system_MulticastDelegate_ty ||
+ typeEquiv cenv.g ty cenv.g.system_Delegate_ty then
+ error(Error(FSComp.SR.tcPredefinedTypeCannotBeUsedAsSuperType(), m))
+ if isErasedType cenv.g ty then
+ errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m))
+
+
+and TcObjectExpr cenv overallTy env tpenv (synObjTy, argopt, binds, extraImpls, mNewExpr, mWholeExpr) =
+ let mObjTy = synObjTy.Range
+
+ let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synObjTy
+ match tryTcrefOfAppTy cenv.g objTy with
+ | ValueNone -> error(Error(FSComp.SR.tcNewMustBeUsedWithNamedType(), mNewExpr))
+ | ValueSome tcref ->
+ let isRecordTy = tcref.IsRecordTycon
+ if not isRecordTy && not (isInterfaceTy cenv.g objTy) && isSealedTy cenv.g objTy then errorR(Error(FSComp.SR.tcCannotCreateExtensionOfSealedType(), mNewExpr))
+
+ CheckSuperType cenv objTy synObjTy.Range
+
+ // Add the object type to the ungeneralizable items
+ let env = {env with eUngeneralizableItems = addFreeItemOfTy objTy env.eUngeneralizableItems }
+
+ // Object expression members can access protected members of the implemented type
+ let env = EnterFamilyRegion tcref env
+ let ad = env.AccessRights
+
+ if // record construction ?
+ isRecordTy ||
+ // object construction?
+ (isFSharpObjModelTy cenv.g objTy && not (isInterfaceTy cenv.g objTy) && argopt.IsNone) then
+
+ if argopt.IsSome then error(Error(FSComp.SR.tcNoArgumentsForRecordValue(), mWholeExpr))
+ if not (isNil extraImpls) then error(Error(FSComp.SR.tcNoInterfaceImplementationForConstructionExpression(), mNewExpr))
+ if isFSharpObjModelTy cenv.g objTy && GetCtorShapeCounter env <> 1 then
+ error(Error(FSComp.SR.tcObjectConstructionCanOnlyBeUsedInClassTypes(), mNewExpr))
+ let fldsList =
+ binds |> List.map (fun b ->
+ match BindingNormalization.NormalizeBinding ObjExprBinding cenv env b with
+ | NormalizedBinding (_, _, _, _, [], _, _, _, SynPat.Named(SynPat.Wild _, id, _, _, _), NormalizedBindingRhs(_, _, rhsExpr), _, _) -> id.idText, rhsExpr
+ | _ -> error(Error(FSComp.SR.tcOnlySimpleBindingsCanBeUsedInConstructionExpressions(), b.RangeOfBindingSansRhs)))
+
+ TcRecordConstruction cenv overallTy env tpenv None objTy fldsList mWholeExpr
+ else
+ let item = ForceRaise (ResolveObjectConstructor cenv.nameResolver env.DisplayEnv mObjTy ad objTy)
+
+ if isFSharpObjModelTy cenv.g objTy && GetCtorShapeCounter env = 1 then
+ error(Error(FSComp.SR.tcObjectsMustBeInitializedWithObjectExpression(), mNewExpr))
+
+ // Work out the type of any interfaces to implement
+ let extraImpls, tpenv =
+ (tpenv, extraImpls) ||> List.mapFold (fun tpenv (InterfaceImpl(synIntfTy, overrides, m)) ->
+ let intfTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synIntfTy
+ if not (isInterfaceTy cenv.g intfTy) then
+ error(Error(FSComp.SR.tcExpectedInterfaceType(), m))
+ if isErasedType cenv.g intfTy then
+ errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m))
+ (m, intfTy, overrides), tpenv)
+
+ let realObjTy = if isObjTy cenv.g objTy && not (isNil extraImpls) then (p23 (List.head extraImpls)) else objTy
+ UnifyTypes cenv env mWholeExpr overallTy realObjTy
+
+ let ctorCall, baseIdOpt, tpenv =
+ match item, argopt with
+ | Item.CtorGroup(methodName, minfos), Some (arg, baseIdOpt) ->
+ let meths = minfos |> List.map (fun minfo -> minfo, None)
+ let afterResolution = ForNewConstructors cenv.tcSink env synObjTy.Range methodName minfos
+ let ad = env.AccessRights
+
+ let expr, tpenv = TcMethodApplicationThen cenv env objTy None tpenv None [] mWholeExpr mObjTy methodName ad PossiblyMutates false meths afterResolution CtorValUsedAsSuperInit [arg] ExprAtomicFlag.Atomic []
+ // The 'base' value is always bound
+ let baseIdOpt = (match baseIdOpt with None -> Some(ident("base", mObjTy)) | Some id -> Some id)
+ expr, baseIdOpt, tpenv
+ | Item.FakeInterfaceCtor intfTy, None ->
+ UnifyTypes cenv env mWholeExpr objTy intfTy
+ let expr = BuildObjCtorCall cenv.g mWholeExpr
+ expr, None, tpenv
+ | Item.FakeInterfaceCtor _, Some _ ->
+ error(Error(FSComp.SR.tcConstructorForInterfacesDoNotTakeArguments(), mNewExpr))
+ | Item.CtorGroup _, None ->
+ error(Error(FSComp.SR.tcConstructorRequiresArguments(), mNewExpr))
+ | _ -> error(Error(FSComp.SR.tcNewRequiresObjectConstructor(), mNewExpr))
+
+ let baseValOpt = MakeAndPublishBaseVal cenv env baseIdOpt objTy
+ let env = Option.foldBack (AddLocalVal cenv.tcSink mNewExpr) baseValOpt env
+
+
+ let impls = (mWholeExpr, objTy, binds) :: extraImpls
+
+
+ // 1. collect all the relevant abstract slots for each type we have to implement
+
+ let overridesAndVirts, tpenv = ComputeObjectExprOverrides cenv env tpenv impls
+
+
+ overridesAndVirts |> List.iter (fun (m, implty, dispatchSlots, dispatchSlotsKeyed, availPriorOverrides, overrides) ->
+ let overrideSpecs = overrides |> List.map fst
+
+ DispatchSlotChecking.CheckOverridesAreAllUsedOnce (env.DisplayEnv, cenv.g, cenv.amap, true, implty, dispatchSlotsKeyed, availPriorOverrides, overrideSpecs)
+
+ DispatchSlotChecking.CheckDispatchSlotsAreImplemented (env.DisplayEnv, cenv.infoReader, m, env.NameEnv, cenv.tcSink, false, implty, dispatchSlots, availPriorOverrides, overrideSpecs) |> ignore)
+
+ // 6c. create the specs of overrides
+ let allTypeImpls =
+ overridesAndVirts |> List.map (fun (m, implty, _, dispatchSlotsKeyed, _, overrides) ->
+ let overrides' =
+ [ for overrideMeth in overrides do
+ let (Override(_, _, id, (mtps, _), _, _, isFakeEventProperty, _) as ovinfo), (_, thisVal, methodVars, bindingAttribs, bindingBody) = overrideMeth
+ if not isFakeEventProperty then
+ let searchForOverride =
+ dispatchSlotsKeyed
+ |> NameMultiMap.find id.idText
+ |> List.tryPick (fun reqdSlot ->
+ let virt = reqdSlot.MethodInfo
+ if DispatchSlotChecking.IsExactMatch cenv.g cenv.amap m virt ovinfo then
+ Some virt
+ else
+ None)
+
+ let overridden =
+ match searchForOverride with
+ | Some x -> x
+ | None -> error(Error(FSComp.SR.tcAtLeastOneOverrideIsInvalid(), synObjTy.Range))
+
+ yield TObjExprMethod(overridden.GetSlotSig(cenv.amap, m), bindingAttribs, mtps, [thisVal] :: methodVars, bindingBody, id.idRange) ]
+ (implty, overrides'))
+
+ let (objTy', overrides') = allTypeImpls.Head
+ let extraImpls = allTypeImpls.Tail
+
+ // 7. Build the implementation
+ let expr = mkObjExpr(objTy', baseValOpt, ctorCall, overrides', extraImpls, mWholeExpr)
+ let expr = mkCoerceIfNeeded cenv.g realObjTy objTy' expr
+ expr, tpenv
+
+
+
+//-------------------------------------------------------------------------
+// TcConstStringExpr
+//-------------------------------------------------------------------------
+
+/// Check a constant string expression. It might be a 'printf' format string
+and TcConstStringExpr cenv overallTy env m tpenv s =
+
+ if (AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy cenv.g.string_ty) then
+ mkString cenv.g m s, tpenv
+ else
+ TcFormatStringExpr cenv overallTy env m tpenv s
+
+and TcFormatStringExpr cenv overallTy env m tpenv (fmtString: string) =
+ let g = cenv.g
+ let aty = NewInferenceType ()
+ let bty = NewInferenceType ()
+ let cty = NewInferenceType ()
+ let dty = NewInferenceType ()
+ let ety = NewInferenceType ()
+ let formatTy = mkPrintfFormatTy g aty bty cty dty ety
+
+ // This might qualify as a format string - check via a type directed rule
+ let ok = not (isObjTy g overallTy) && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy formatTy
+
+ if ok then
+ // Parse the format string to work out the phantom types
+ let formatStringCheckContext = match cenv.tcSink.CurrentSink with None -> None | Some sink -> sink.FormatStringCheckContext
+ let normalizedString = (fmtString.Replace("\r\n", "\n").Replace("\r", "\n"))
+
+ let _argTys, atyRequired, etyRequired, _percentATys, specifierLocations, _dotnetFormatString =
+ try CheckFormatStrings.ParseFormatString m [m] g false false formatStringCheckContext normalizedString bty cty dty
+ with Failure errString -> error (Error(FSComp.SR.tcUnableToParseFormatString errString, m))
+
+ match cenv.tcSink.CurrentSink with
+ | None -> ()
+ | Some sink ->
+ for specifierLocation, numArgs in specifierLocations do
+ sink.NotifyFormatSpecifierLocation(specifierLocation, numArgs)
+
+ UnifyTypes cenv env m aty atyRequired
+ UnifyTypes cenv env m ety etyRequired
+ let fmtExpr = mkCallNewFormat g m aty bty cty dty ety (mkString g m fmtString)
+ fmtExpr, tpenv
+
+ else
+ UnifyTypes cenv env m overallTy g.string_ty
+ mkString g m fmtString, tpenv
+
+/// Check an interpolated string expression
+and TcInterpolatedStringExpr cenv overallTy env m tpenv (parts: SynInterpolatedStringPart list) =
+ let g = cenv.g
+
+ let synFillExprs =
+ parts
+ |> List.choose (function
+ | SynInterpolatedStringPart.String _ -> None
+ | SynInterpolatedStringPart.FillExpr (fillExpr, _) ->
+ match fillExpr with
+ // Detect "x" part of "...{x,3}..."
+ | SynExpr.Tuple (false, [e; SynExpr.Const (SynConst.Int32 _align, _)], _, _) -> Some e
+ | e -> Some e)
+
+ let stringFragmentRanges =
+ parts
+ |> List.choose (function
+ | SynInterpolatedStringPart.String (_,m) -> Some m
+ | SynInterpolatedStringPart.FillExpr _ -> None)
+
+ let printerTy = NewInferenceType ()
+ let printerArgTy = NewInferenceType ()
+ let printerResidueTy = NewInferenceType ()
+ let printerResultTy = NewInferenceType ()
+ let printerTupleTy = NewInferenceType ()
+ let formatTy = mkPrintfFormatTy g printerTy printerArgTy printerResidueTy printerResultTy printerTupleTy
+
+ // Check the library support is available in the referenced FSharp.Core
+ let newFormatMethod =
+ match GetIntrinsicConstructorInfosOfType cenv.infoReader m formatTy |> List.filter (fun minfo -> minfo.NumArgs = [3]) with
+ | [ctorInfo] -> ctorInfo
+ | _ -> languageFeatureNotSupportedInLibraryError cenv.g.langVersion LanguageFeature.StringInterpolation m
+
+ let stringKind =
+ // If this is an interpolated string then try to force the result to be a string
+ if (AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy g.string_ty) then
+
+ // And if that succeeds, the result of printing is a string
+ UnifyTypes cenv env m printerArgTy g.unit_ty
+ UnifyTypes cenv env m printerResidueTy g.string_ty
+ UnifyTypes cenv env m printerResultTy overallTy
+
+ // And if that succeeds, the printerTy and printerResultTy must be the same (there are no curried arguments)
+ UnifyTypes cenv env m printerTy printerResultTy
+
+ Choice1Of2 (true, newFormatMethod)
+
+ // ... or if that fails then may be a FormattableString by a type-directed rule....
+ elif (not (isObjTy g overallTy) &&
+ ((g.system_FormattableString_tcref.CanDeref && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy g.system_FormattableString_ty)
+ || (g.system_IFormattable_tcref.CanDeref && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy g.system_IFormattable_ty))) then
+
+ // And if that succeeds, the result of printing is a string
+ UnifyTypes cenv env m printerArgTy g.unit_ty
+ UnifyTypes cenv env m printerResidueTy g.string_ty
+ UnifyTypes cenv env m printerResultTy overallTy
+
+ // Find the FormattableStringFactor.Create method in the .NET libraries
+ let ad = env.eAccessRights
+ let createMethodOpt =
+ match TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AllResults cenv env m ad "Create" g.system_FormattableStringFactory_ty with
+ | [x] -> Some x
+ | _ -> None
+
+ match createMethodOpt with
+ | Some createMethod -> Choice2Of2 createMethod
+ | None -> languageFeatureNotSupportedInLibraryError cenv.g.langVersion LanguageFeature.StringInterpolation m
+
+ // ... or if that fails then may be a PrintfFormat by a type-directed rule....
+ elif not (isObjTy g overallTy) && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy formatTy then
+
+ // And if that succeeds, the printerTy and printerResultTy must be the same (there are no curried arguments)
+ UnifyTypes cenv env m printerTy printerResultTy
+ Choice1Of2 (false, newFormatMethod)
+
+ else
+ // this should fail and produce an error
+ UnifyTypes cenv env m overallTy g.string_ty
+ Choice1Of2 (true, newFormatMethod)
+
+ let isFormattableString = (match stringKind with Choice2Of2 _ -> true | _ -> false)
+
+ // The format string used for checking in CheckFormatStrings. This replaces interpolation holes with %P
+ let printfFormatString =
+ parts
+ |> List.map (function
+ | SynInterpolatedStringPart.String (s, _) -> s
+ | SynInterpolatedStringPart.FillExpr (fillExpr, format) ->
+ let alignText =
+ match fillExpr with
+ // Validate and detect ",3" part of "...{x,3}..."
+ | SynExpr.Tuple (false, args, _, _) ->
+ match args with
+ | [_; SynExpr.Const (SynConst.Int32 align, _)] -> string align
+ | _ -> errorR(Error(FSComp.SR.tcInvalidAlignmentInInterpolatedString(), m)); ""
+ | _ -> ""
+ let formatText = match format with None -> "()" | Some n -> "(" + n.idText + ")"
+ "%" + alignText + "P" + formatText )
+ |> String.concat ""
+
+ // Parse the format string to work out the phantom types and check for absence of '%' specifiers in FormattableString
+ //
+ // If FormatStringCheckContext is set (i.e. we are doing foreground checking in the IDE)
+ // then we check the string twice, once to collect % positions and once to get errors.
+ // The process of getting % positions doesn't process the string in a semantically accurate way
+ // (but is enough to report % locations correctly), as it fetched the pieces from the
+ // original source and this may include some additional characters,
+ // and also doesn't raise all necessary errors
+ match cenv.tcSink.CurrentSink with
+ | Some sink when sink.FormatStringCheckContext.IsSome ->
+ try
+ let _argTys, _printerTy, _printerTupleTyRequired, _percentATys, specifierLocations, _dotnetFormatString =
+ CheckFormatStrings.ParseFormatString m stringFragmentRanges g true isFormattableString sink.FormatStringCheckContext printfFormatString printerArgTy printerResidueTy printerResultTy
+ for specifierLocation, numArgs in specifierLocations do
+ sink.NotifyFormatSpecifierLocation(specifierLocation, numArgs)
+ with _err->
+ ()
+ | _ -> ()
+
+ let argTys, _printerTy, printerTupleTyRequired, percentATys, _specifierLocations, dotnetFormatString =
+ try
+ CheckFormatStrings.ParseFormatString m stringFragmentRanges g true isFormattableString None printfFormatString printerArgTy printerResidueTy printerResultTy
+ with Failure errString ->
+ error (Error(FSComp.SR.tcUnableToParseInterpolatedString errString, m))
+
+ // Check the expressions filling the holes
+ if argTys.Length <> synFillExprs.Length then
+ error (Error(FSComp.SR.tcInterpolationMixedWithPercent(), m))
+
+ match stringKind with
+
+ // The case for $"..." used as type string and $"...%d{x}..." used as type PrintfFormat - create a PrintfFormat that captures
+ // is arguments
+ | Choice1Of2 (isString, newFormatMethod) ->
+
+ UnifyTypes cenv env m printerTupleTy printerTupleTyRequired
+
+ // Type check the expressions filling the holes
+ let flexes = argTys |> List.map (fun _ -> false)
+ let fillExprs, tpenv = TcExprs cenv env m tpenv flexes argTys synFillExprs
+
+ let fillExprsBoxed = (argTys, fillExprs) ||> List.map2 (mkCallBox g m)
+
+ let argsExpr = mkArray (g.obj_ty, fillExprsBoxed, m)
+ let percentATysExpr =
+ if percentATys.Length = 0 then
+ mkNull m (mkArrayType g g.system_Type_ty)
+ else
+ let tyExprs = percentATys |> Array.map (mkCallTypeOf g m) |> Array.toList
+ mkArray (g.system_Type_ty, tyExprs, m)
+
+ let fmtExpr = MakeMethInfoCall cenv.amap m newFormatMethod [] [mkString g m printfFormatString; argsExpr; percentATysExpr]
+
+ if isString then
+ // Make the call to sprintf
+ mkCall_sprintf g m printerTy fmtExpr [], tpenv
+ else
+ fmtExpr, tpenv
+
+ // The case for $"..." used as type FormattableString or IFormattable
+ | Choice2Of2 createFormattableStringMethod ->
+
+ // Type check the expressions filling the holes
+ let flexes = argTys |> List.map (fun _ -> false)
+ let fillExprs, tpenv = TcExprs cenv env m tpenv flexes argTys synFillExprs
+
+ let fillExprsBoxed = (argTys, fillExprs) ||> List.map2 (mkCallBox g m)
+
+ let dotnetFormatStringExpr = mkString g m dotnetFormatString
+ let argsExpr = mkArray (g.obj_ty, fillExprsBoxed, m)
+
+ // FormattableString are *always* turned into FormattableStringFactory.Create calls, boxing each argument
+ let createExpr, _ = BuildPossiblyConditionalMethodCall cenv env NeverMutates m false createFormattableStringMethod NormalValUse [] [dotnetFormatStringExpr; argsExpr] []
+
+ let resultExpr =
+ if typeEquiv g overallTy g.system_IFormattable_ty then
+ mkCoerceIfNeeded g g.system_IFormattable_ty g.system_FormattableString_ty createExpr
+ else
+ createExpr
+ resultExpr, tpenv
+
+//-------------------------------------------------------------------------
+// TcConstExpr
+//-------------------------------------------------------------------------
+
+/// Check a constant expression.
+and TcConstExpr cenv overallTy env m tpenv c =
+ match c with
+
+ // NOTE: these aren't "really" constants
+ | SynConst.Bytes (bytes, m) ->
+ UnifyTypes cenv env m overallTy (mkByteArrayTy cenv.g)
+ Expr.Op (TOp.Bytes bytes, [], [], m), tpenv
+
+ | SynConst.UInt16s arr ->
+ UnifyTypes cenv env m overallTy (mkArrayType cenv.g cenv.g.uint16_ty); Expr.Op (TOp.UInt16s arr, [], [], m), tpenv
+
+ | SynConst.UserNum (s, suffix) ->
+ let expr =
+ let modName = "NumericLiteral" + suffix
+ let ad = env.eAccessRights
+ match ResolveLongIdentAsModuleOrNamespace cenv.tcSink ResultCollectionSettings.AtMostOneResult cenv.amap m true OpenQualified env.eNameResEnv ad (ident (modName, m)) [] false with
+ | Result []
+ | Exception _ -> error(Error(FSComp.SR.tcNumericLiteralRequiresModule modName, m))
+ | Result ((_, mref, _) :: _) ->
+ let expr =
+ try
+ match int32 s with
+ | 0 -> SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromZero", SynExpr.Const (SynConst.Unit, m), m)
+ | 1 -> SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromOne", SynExpr.Const (SynConst.Unit, m), m)
+ | i32 -> SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromInt32", SynExpr.Const (SynConst.Int32 i32, m), m)
+ with _ ->
+ try
+ let i64 = int64 s
+ SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromInt64", SynExpr.Const (SynConst.Int64 i64, m), m)
+ with _ ->
+ SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet m [modName] "FromString", SynExpr.Const (SynConst.String (s, m), m), m)
+
+ if suffix <> "I" then
+ expr
+ else
+ match ccuOfTyconRef mref with
+ | Some ccu when ccuEq ccu cenv.g.fslibCcu ->
+ SynExpr.Typed (expr, SynType.LongIdent(LongIdentWithDots(pathToSynLid m ["System";"Numerics";"BigInteger"], [])), m)
+ | _ ->
+ expr
+
+ TcExpr cenv overallTy env tpenv expr
+
+ | _ ->
+ let c' = TcConst cenv overallTy m env c
+ Expr.Const (c', m, overallTy), tpenv
+
+
+//-------------------------------------------------------------------------
+// TcAssertExpr
+//-------------------------------------------------------------------------
+
+// Check an 'assert x' expression.
+and TcAssertExpr cenv overallTy env (m: range) tpenv x =
+ let synm = m.MakeSynthetic() // Mark as synthetic so the language service won't pick it up.
+ let callDiagnosticsExpr = SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet synm ["System";"Diagnostics";"Debug"] "Assert",
+ // wrap an extra parentheses so 'assert(x=1) isn't considered a named argument to a method call
+ SynExpr.Paren (x, range0, None, synm), synm)
+
+ TcExpr cenv overallTy env tpenv callDiagnosticsExpr
+
+
+and TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr) =
+
+ let requiresCtor = (GetCtorShapeCounter env = 1) // Get special expression forms for constructors
+ let haveCtor = Option.isSome inherits
+
+ let optOrigExpr, tpenv =
+ match optOrigExpr with
+ | None -> None, tpenv
+ | Some (origExpr, _) ->
+ match inherits with
+ | Some (_, _, mInherits, _, _) -> error(Error(FSComp.SR.tcInvalidRecordConstruction(), mInherits))
+ | None ->
+ let olde, tpenv = TcExpr cenv overallTy env tpenv origExpr
+ Some (olde), tpenv
+
+ let hasOrigExpr = optOrigExpr.IsSome
+
+ let fldsList =
+ let flds =
+ [
+ // if we met at least one field that is not syntactically correct - raise ReportedError to transfer control to the recovery routine
+ for ((lidwd, isOk), v, _) in flds do
+ if not isOk then
+ // raising ReportedError None transfers control to the closest errorRecovery point but do not make any records into log
+ // we assume that parse errors were already reported
+ raise (ReportedError None)
+
+ yield (List.frontAndBack lidwd.Lid, v)
+ ]
+
+ match flds with
+ | [] -> []
+ | _ ->
+ let tinst, tcref, _, fldsList = BuildFieldMap cenv env hasOrigExpr overallTy flds mWholeExpr
+ let gtyp = mkAppTy tcref tinst
+ UnifyTypes cenv env mWholeExpr overallTy gtyp
+
+ [ for n, v in fldsList do
+ match v with
+ | Some v -> yield n, v
+ | None -> () ]
+
+ let optOrigExprInfo =
+ match optOrigExpr with
+ | None -> None
+ | Some(olde) ->
+ let oldvaddr, oldvaddre = mkCompGenLocal mWholeExpr "inputRecord" (if isStructTy cenv.g overallTy then mkByrefTy cenv.g overallTy else overallTy)
+ Some(olde, oldvaddr, oldvaddre)
+
+ if hasOrigExpr && not (isRecdTy cenv.g overallTy) then
+ errorR(Error(FSComp.SR.tcExpressionFormRequiresRecordTypes(), mWholeExpr))
+
+ if requiresCtor || haveCtor then
+ if not (isFSharpObjModelTy cenv.g overallTy) then
+ // Deliberate no-recovery failure here to prevent cascading internal errors
+ error(Error(FSComp.SR.tcInheritedTypeIsNotObjectModelType(), mWholeExpr))
+ if not requiresCtor then
+ errorR(Error(FSComp.SR.tcObjectConstructionExpressionCanOnlyImplementConstructorsInObjectModelTypes(), mWholeExpr))
+ else
+ if isNil flds then
+ let errorInfo = if hasOrigExpr then FSComp.SR.tcEmptyCopyAndUpdateRecordInvalid() else FSComp.SR.tcEmptyRecordInvalid()
+ error(Error(errorInfo, mWholeExpr))
+
+ if isFSharpObjModelTy cenv.g overallTy then errorR(Error(FSComp.SR.tcTypeIsNotARecordTypeNeedConstructor(), mWholeExpr))
+ elif not (isRecdTy cenv.g overallTy) then errorR(Error(FSComp.SR.tcTypeIsNotARecordType(), mWholeExpr))
+
+ let superTy, tpenv =
+ match inherits, GetSuperTypeOfType cenv.g cenv.amap mWholeExpr overallTy with
+ | Some (superTy, arg, m, _, _), Some realSuperTy ->
+ // Constructor expression, with an explicit 'inheritedTys clause. Check the inherits clause.
+ let e, tpenv = TcExpr cenv realSuperTy env tpenv (SynExpr.New (true, superTy, arg, m))
+ Some e, tpenv
+ | None, Some realSuperTy when requiresCtor ->
+ // Constructor expression, No 'inherited' clause, hence look for a default constructor
+ let e, tpenv = TcNewExpr cenv env tpenv realSuperTy None true (SynExpr.Const (SynConst.Unit, mWholeExpr)) mWholeExpr
+ Some e, tpenv
+ | None, _ ->
+ None, tpenv
+ | _, None ->
+ errorR(InternalError("Unexpected failure in getting super type", mWholeExpr))
+ None, tpenv
+
+ let expr, tpenv = TcRecordConstruction cenv overallTy env tpenv optOrigExprInfo overallTy fldsList mWholeExpr
+
+ let expr =
+ match superTy with
+ | _ when isStructTy cenv.g overallTy -> expr
+ | Some e -> mkCompGenSequential mWholeExpr e expr
+ | None -> expr
+ expr, tpenv
+
+
+// Check '{| .... |}'
+and TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigSynExpr, unsortedFieldIdsAndSynExprsGiven, mWholeExpr) =
+ let unsortedFieldSynExprsGiven = List.map snd unsortedFieldIdsAndSynExprsGiven
+
+ match optOrigSynExpr with
+ | None ->
+ let unsortedFieldIds = unsortedFieldIdsAndSynExprsGiven |> List.map fst |> List.toArray
+ let anonInfo, sortedFieldTys = UnifyAnonRecdTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv mWholeExpr overallTy isStruct unsortedFieldIds
+
+ // Sort into canonical order
+ let sortedIndexedArgs =
+ unsortedFieldIdsAndSynExprsGiven
+ |> List.indexed
+ |> List.sortBy (fun (i,_) -> unsortedFieldIds.[i].idText)
+
+ // Map from sorted indexes to unsorted indexes
+ let sigma = List.map fst sortedIndexedArgs |> List.toArray
+ let sortedFieldExprs = List.map snd sortedIndexedArgs
+
+ sortedFieldExprs |> List.iteri (fun j (x, _) ->
+ let item = Item.AnonRecdField(anonInfo, sortedFieldTys, j, x.idRange)
+ CallNameResolutionSink cenv.tcSink (x.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.eAccessRights))
+
+ let unsortedFieldTys =
+ sortedFieldTys
+ |> List.indexed
+ |> List.sortBy (fun (sortedIdx, _) -> sigma.[sortedIdx])
+ |> List.map snd
+
+ let flexes = unsortedFieldTys |> List.map (fun _ -> true)
+
+ let unsortedCheckedArgs, tpenv = TcExprs cenv env mWholeExpr tpenv flexes unsortedFieldTys unsortedFieldSynExprsGiven
+
+ mkAnonRecd cenv.g mWholeExpr anonInfo unsortedFieldIds unsortedCheckedArgs unsortedFieldTys, tpenv
+
+ | Some (origExpr, _) ->
+ // The fairly complex case '{| origExpr with X = 1; Y = 2 |}'
+ // The origExpr may be either a record or anonymous record.
+ // The origExpr may be either a struct or not.
+ // All the properties of origExpr are copied across except where they are overridden.
+ // The result is a field-sorted anonymous record.
+ //
+ // Unlike in the case of record type copy-and-update we do _not_ assume that the origExpr has the same type as the overall expression.
+ // Unlike in the case of record type copy-and-update {| a with X = 1 |} does not force a.X to exist or have had type 'int'
+
+ let origExprTy = NewInferenceType()
+ let origExprChecked, tpenv = TcExpr cenv origExprTy env tpenv origExpr
+ let oldv, oldve = mkCompGenLocal mWholeExpr "inputRecord" origExprTy
+ let mOrigExpr = origExpr.Range
+
+ if not (isAppTy cenv.g origExprTy || isAnonRecdTy cenv.g origExprTy) then
+ error (Error (FSComp.SR.tcCopyAndUpdateNeedsRecordType(), mOrigExpr))
+
+ let origExprIsStruct =
+ match tryDestAnonRecdTy cenv.g origExprTy with
+ | ValueSome (anonInfo, _) -> evalTupInfoIsStruct anonInfo.TupInfo
+ | ValueNone ->
+ let tcref, _ = destAppTy cenv.g origExprTy
+ tcref.IsStructOrEnumTycon
+
+ let wrap, oldveaddr, _readonly, _writeonly = mkExprAddrOfExpr cenv.g origExprIsStruct false NeverMutates oldve None mOrigExpr
+
+ // Put all the expressions in unsorted order. The new bindings come first. The origin of each is tracked using
+ /// - Choice1Of2 for a new binding
+ /// - Choice2Of2 for a binding coming from the original expression
+ let unsortedIdAndExprsAll =
+ [| for (id, e) in unsortedFieldIdsAndSynExprsGiven do
+ yield (id, Choice1Of2 e)
+ match tryDestAnonRecdTy cenv.g origExprTy with
+ | ValueSome (anonInfo, tinst) ->
+ for (i, id) in Array.indexed anonInfo.SortedIds do
+ yield id, Choice2Of2 (mkAnonRecdFieldGetViaExprAddr (anonInfo, oldveaddr, tinst, i, mOrigExpr))
+ | ValueNone ->
+ match tryAppTy cenv.g origExprTy with
+ | ValueSome(tcref, tinst) when tcref.IsRecordTycon ->
+ let fspecs = tcref.Deref.TrueInstanceFieldsAsList
+ for fspec in fspecs do
+ yield fspec.Id, Choice2Of2 (mkRecdFieldGetViaExprAddr (oldveaddr, tcref.MakeNestedRecdFieldRef fspec, tinst, mOrigExpr))
+ | _ ->
+ error (Error (FSComp.SR.tcCopyAndUpdateNeedsRecordType(), mOrigExpr)) |]
+ |> Array.distinctBy (fst >> textOfId)
+
+ let unsortedFieldIdsAll = Array.map fst unsortedIdAndExprsAll
+
+ let anonInfo, sortedFieldTysAll = UnifyAnonRecdTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv mWholeExpr overallTy isStruct unsortedFieldIdsAll
+
+ let sortedIndexedFieldsAll = unsortedIdAndExprsAll |> Array.indexed |> Array.sortBy (snd >> fst >> textOfId)
+
+ // map from sorted indexes to unsorted indexes
+ let sigma = Array.map fst sortedIndexedFieldsAll
+
+ let sortedFieldsAll = Array.map snd sortedIndexedFieldsAll
+
+ // Report _all_ identifiers to name resolution. We should likely just report the ones
+ // that are explicit in source code.
+ sortedFieldsAll |> Array.iteri (fun j (x, expr) ->
+ match expr with
+ | Choice1Of2 _ ->
+ let item = Item.AnonRecdField(anonInfo, sortedFieldTysAll, j, x.idRange)
+ CallNameResolutionSink cenv.tcSink (x.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.eAccessRights)
+ | Choice2Of2 _ -> ())
+
+ let unsortedFieldTysAll =
+ sortedFieldTysAll
+ |> List.indexed
+ |> List.sortBy (fun (sortedIdx, _) -> sigma.[sortedIdx])
+ |> List.map snd
+
+ let unsortedFieldTysGiven =
+ unsortedFieldTysAll
+ |> List.take unsortedFieldIdsAndSynExprsGiven.Length
+
+ let flexes = unsortedFieldTysGiven |> List.map (fun _ -> true)
+
+ // Check the expressions in unsorted order
+ let unsortedFieldExprsGiven, tpenv =
+ TcExprs cenv env mWholeExpr tpenv flexes unsortedFieldTysGiven unsortedFieldSynExprsGiven
+
+ let unsortedFieldExprsGiven = unsortedFieldExprsGiven |> List.toArray
+
+ let unsortedFieldIds =
+ unsortedIdAndExprsAll
+ |> Array.map fst
+
+ let unsortedFieldExprs =
+ unsortedIdAndExprsAll
+ |> Array.mapi (fun unsortedIdx (_, expr) ->
+ match expr with
+ | Choice1Of2 _ -> unsortedFieldExprsGiven.[unsortedIdx]
+ | Choice2Of2 subExpr -> UnifyTypes cenv env mOrigExpr (tyOfExpr cenv.g subExpr) unsortedFieldTysAll.[unsortedIdx]; subExpr)
+ |> List.ofArray
+
+ // Permute the expressions to sorted order in the TAST
+ let expr = mkAnonRecd cenv.g mWholeExpr anonInfo unsortedFieldIds unsortedFieldExprs unsortedFieldTysAll
+ let expr = wrap expr
+
+ // Bind the original expression
+ let expr = mkCompGenLet mOrigExpr oldv origExprChecked expr
+ expr, tpenv
+
+
+and TcForEachExpr cenv overallTy env tpenv (pat, enumSynExpr, bodySynExpr, mWholeExpr, spForLoop) =
+ let tryGetOptimizeSpanMethodsAux g m ty isReadOnlySpan =
+ match (if isReadOnlySpan then tryDestReadOnlySpanTy g m ty else tryDestSpanTy g m ty) with
+ | ValueSome(struct(_, destTy)) ->
+ match TryFindFSharpSignatureInstanceGetterProperty cenv env m "Item" ty [ g.int32_ty; (if isReadOnlySpan then mkInByrefTy g destTy else mkByrefTy g destTy) ],
+ TryFindFSharpSignatureInstanceGetterProperty cenv env m "Length" ty [ g.int32_ty ] with
+ | Some(itemPropInfo), Some(lengthPropInfo) ->
+ ValueSome(struct(itemPropInfo.GetterMethod, lengthPropInfo.GetterMethod, isReadOnlySpan))
+ | _ ->
+ ValueNone
+ | _ ->
+ ValueNone
+
+ let tryGetOptimizeSpanMethods g m ty =
+ let result = tryGetOptimizeSpanMethodsAux g m ty false
+ if result.IsSome then
+ result
+ else
+ tryGetOptimizeSpanMethodsAux g m ty true
+
+ UnifyTypes cenv env mWholeExpr overallTy cenv.g.unit_ty
+
+ let mPat = pat.Range
+ //let mBodyExpr = bodySynExpr.Range
+ let mEnumExpr = enumSynExpr.Range
+ let mForLoopStart = match spForLoop with DebugPointAtFor.Yes mStart -> mStart | DebugPointAtFor.No -> mEnumExpr
+
+ // Check the expression being enumerated
+ let enumExpr, enumExprTy, tpenv = TcExprOfUnknownType cenv env tpenv enumSynExpr
+
+ // Depending on its type we compile it in different ways
+ let enumElemTy, bodyExprFixup, overallExprFixup, iterationTechnique =
+ match enumExpr with
+
+ // optimize 'for i in n .. m do'
+ | Expr.App (Expr.Val (vf, _, _), _, [tyarg], [startExpr;finishExpr], _)
+ when valRefEq cenv.g vf cenv.g.range_op_vref && typeEquiv cenv.g tyarg cenv.g.int_ty ->
+ (cenv.g.int32_ty, (fun _ x -> x), id, Choice1Of3 (startExpr, finishExpr))
+
+ // optimize 'for i in arr do'
+ | _ when isArray1DTy cenv.g enumExprTy ->
+ let arrVar, arrExpr = mkCompGenLocal mEnumExpr "arr" enumExprTy
+ let idxVar, idxExpr = mkCompGenLocal mPat "idx" cenv.g.int32_ty
+ let elemTy = destArrayTy cenv.g enumExprTy
+
+ // Evaluate the array index lookup
+ let bodyExprFixup elemVar bodyExpr = mkCompGenLet mForLoopStart elemVar (mkLdelem cenv.g mForLoopStart elemTy arrExpr idxExpr) bodyExpr
+
+ // Evaluate the array expression once and put it in arrVar
+ let overallExprFixup overallExpr = mkCompGenLet mForLoopStart arrVar enumExpr overallExpr
+
+ // Ask for a loop over integers for the given range
+ (elemTy, bodyExprFixup, overallExprFixup, Choice2Of3 (idxVar, mkZero cenv.g mForLoopStart, mkDecr cenv.g mForLoopStart (mkLdlen cenv.g mForLoopStart arrExpr)))
+
+ | _ ->
+ // try optimize 'for i in span do' for span or readonlyspan
+ match tryGetOptimizeSpanMethods cenv.g mWholeExpr enumExprTy with
+ | ValueSome(struct(getItemMethInfo, getLengthMethInfo, isReadOnlySpan)) ->
+ let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g
+ let spanVar, spanExpr = mkCompGenLocal mEnumExpr "span" enumExprTy
+ let idxVar, idxExpr = mkCompGenLocal mPat "idx" cenv.g.int32_ty
+ let struct(_, elemTy) = if isReadOnlySpan then destReadOnlySpanTy cenv.g mWholeExpr enumExprTy else destSpanTy cenv.g mWholeExpr enumExprTy
+ let elemAddrTy = if isReadOnlySpan then mkInByrefTy cenv.g elemTy else mkByrefTy cenv.g elemTy
+
+ // Evaluate the span index lookup
+ let bodyExprFixup elemVar bodyExpr =
+ let elemAddrVar, _ = mkCompGenLocal mForLoopStart "addr" elemAddrTy
+ let e = mkCompGenLet mForLoopStart elemVar (mkAddrGet mForLoopStart (mkLocalValRef elemAddrVar)) bodyExpr
+ let getItemCallExpr, _ = BuildMethodCall tcVal cenv.g cenv.amap PossiblyMutates mWholeExpr true getItemMethInfo ValUseFlag.NormalValUse [] [ spanExpr ] [ idxExpr ]
+ mkCompGenLet mForLoopStart elemAddrVar getItemCallExpr e
+
+ // Evaluate the span expression once and put it in spanVar
+ let overallExprFixup overallExpr = mkCompGenLet mForLoopStart spanVar enumExpr overallExpr
+
+ let getLengthCallExpr, _ = BuildMethodCall tcVal cenv.g cenv.amap PossiblyMutates mWholeExpr true getLengthMethInfo ValUseFlag.NormalValUse [] [ spanExpr ] []
+
+ // Ask for a loop over integers for the given range
+ (elemTy, bodyExprFixup, overallExprFixup, Choice2Of3 (idxVar, mkZero cenv.g mForLoopStart, mkDecr cenv.g mForLoopStart getLengthCallExpr))
+
+ | _ ->
+ let enumerableVar, enumerableExprInVar = mkCompGenLocal mEnumExpr "inputSequence" enumExprTy
+ let enumeratorVar, enumeratorExpr, _, enumElemTy, getEnumExpr, getEnumTy, guardExpr, _, currentExpr =
+ AnalyzeArbitraryExprAsEnumerable cenv env true mEnumExpr enumExprTy enumerableExprInVar
+ (enumElemTy, (fun _ x -> x), id, Choice3Of3(enumerableVar, enumeratorVar, enumeratorExpr, getEnumExpr, getEnumTy, guardExpr, currentExpr))
+
+ let pat, _, vspecs, envinner, tpenv = TcMatchPattern cenv enumElemTy env tpenv (pat, None)
+ let elemVar, pat =
+ // nice: don't introduce awful temporary for r.h.s. in the 99% case where we know what we're binding it to
+ match pat with
+ | TPat_as (pat1, PBind(v, TypeScheme([], _)), _) ->
+ v, pat1
+ | _ ->
+ let tmp, _ = mkCompGenLocal pat.Range "forLoopVar" enumElemTy
+ tmp, pat
+
+ // Check the body of the loop
+ let bodyExpr, tpenv = TcStmt cenv envinner tpenv bodySynExpr
+
+ // Add the pattern match compilation
+ let bodyExpr =
+ let valsDefinedByMatching = ListSet.remove valEq elemVar vspecs
+ CompilePatternForMatch
+ cenv env enumSynExpr.Range pat.Range false IgnoreWithWarning (elemVar, [], None)
+ [TClause(pat, None, TTarget(valsDefinedByMatching, bodyExpr, DebugPointForTarget.Yes), mForLoopStart)]
+ enumElemTy
+ overallTy
+
+ // Apply the fixup to bind the elemVar if needed
+ let bodyExpr = bodyExprFixup elemVar bodyExpr
+
+ // Build the overall loop
+ let overallExpr =
+
+ match iterationTechnique with
+
+ // Build iteration as a for loop
+ | Choice1Of3(startExpr, finishExpr) ->
+ mkFastForLoop cenv.g (spForLoop, mWholeExpr, elemVar, startExpr, true, finishExpr, bodyExpr)
+
+ // Build iteration as a for loop with a specific index variable that is not the same as the elemVar
+ | Choice2Of3(idxVar, startExpr, finishExpr) ->
+ mkFastForLoop cenv.g (spForLoop, mWholeExpr, idxVar, startExpr, true, finishExpr, bodyExpr)
+
+ // Build iteration as a while loop with a try/finally disposal
+ | Choice3Of3(enumerableVar, enumeratorVar, _, getEnumExpr, _, guardExpr, currentExpr) ->
+
+ // This compiled for must be matched EXACTLY by CompiledForEachExpr in opt.fs and creflect.fs
+ mkCompGenLet mForLoopStart enumerableVar enumExpr
+ (let cleanupE = BuildDisposableCleanup cenv env mWholeExpr enumeratorVar
+ let spBind = match spForLoop with DebugPointAtFor.Yes spStart -> DebugPointAtBinding spStart | DebugPointAtFor.No -> NoDebugPointAtStickyBinding
+ (mkLet spBind mForLoopStart enumeratorVar getEnumExpr
+ (mkTryFinally cenv.g
+ (mkWhile cenv.g
+ (DebugPointAtWhile.No,
+ WhileLoopForCompiledForEachExprMarker, guardExpr,
+ mkCompGenLet mForLoopStart elemVar currentExpr bodyExpr,
+ mForLoopStart),
+ cleanupE, mForLoopStart, cenv.g.unit_ty, DebugPointAtTry.No, DebugPointAtFinally.No))))
+
+ let overallExpr = overallExprFixup overallExpr
+ overallExpr, tpenv
+
+//-------------------------------------------------------------------------
+// TcQuotationExpr
+//-------------------------------------------------------------------------
+
+and TcQuotationExpr cenv overallTy env tpenv (_oper, raw, ast, isFromQueryExpression, m) =
+ let astTy = NewInferenceType ()
+
+ // Assert the overall type for the domain of the quotation template
+ UnifyTypes cenv env m overallTy (if raw then mkRawQuotedExprTy cenv.g else mkQuotedExprTy cenv.g astTy)
+
+ // Check the expression
+ let expr, tpenv = TcExpr cenv astTy env tpenv ast
+
+ // Wrap the expression
+ let expr = Expr.Quote (expr, ref None, isFromQueryExpression, m, overallTy)
+
+ // Coerce it if needed
+ let expr = if raw then mkCoerceExpr(expr, (mkRawQuotedExprTy cenv.g), m, (tyOfExpr cenv.g expr)) else expr
+
+ // We serialize the quoted expression to bytes in IlxGen after type inference etc. is complete.
+ expr, tpenv
+
+
+/// When checking sequence of function applications,
+/// type applications and dot-notation projections, first extract known
+/// type information from the applications.
+///
+/// 'overallTy' is the type expected for the entire chain of expr + lookups.
+/// 'exprty' is the type of the expression on the left of the lookup chain.
+///
+/// We propagate information from the expected overall type 'overallTy'. The use
+/// of function application syntax unambiguously implies that 'overallTy' is a function type.
+and Propagate cenv overallTy env tpenv (expr: ApplicableExpr) exprty delayed =
+
+ let rec propagate isAddrOf delayedList mExpr exprty =
+ match delayedList with
+ | [] ->
+
+ if not (isNil delayed) then
+
+ // We generate a tag inference parameter to the return type for "&x" and 'NativePtr.toByRef'
+ // See RFC FS-1053.md
+ let exprty =
+ if isAddrOf && isByrefTy cenv.g exprty then
+ mkByrefTyWithInference cenv.g (destByrefTy cenv.g exprty) (NewByRefKindInferenceType cenv.g mExpr)
+ elif isByrefTy cenv.g exprty then
+ // Implicit dereference on byref on return
+ if isByrefTy cenv.g overallTy then
+ errorR(Error(FSComp.SR.tcByrefReturnImplicitlyDereferenced(), mExpr))
+ destByrefTy cenv.g exprty
+ else
+ exprty
+
+ UnifyTypesAndRecover cenv env mExpr overallTy exprty
+
+ | DelayedDot :: _
+ | DelayedSet _ :: _
+ | DelayedDotLookup _ :: _ -> ()
+ | DelayedTypeApp (_, _mTypeArgs, mExprAndTypeArgs) :: delayedList' ->
+ // Note this case should not occur: would eventually give an "Unexpected type application" error in TcDelayed
+ propagate isAddrOf delayedList' mExprAndTypeArgs exprty
+
+ | DelayedApp (_, arg, mExprAndArg) :: delayedList' ->
+ let denv = env.DisplayEnv
+ match UnifyFunctionTypeUndoIfFailed cenv denv mExpr exprty with
+ | ValueSome (_, resultTy) ->
+
+ // We add tag parameter to the return type for "&x" and 'NativePtr.toByRef'
+ // See RFC FS-1053.md
+ let isAddrOf =
+ match expr with
+ | ApplicableExpr(_, Expr.App (Expr.Val (vf, _, _), _, _, [], _), _)
+ when (valRefEq cenv.g vf cenv.g.addrof_vref ||
+ valRefEq cenv.g vf cenv.g.nativeptr_tobyref_vref) -> true
+ | _ -> false
+
+ propagate isAddrOf delayedList' mExprAndArg resultTy
+
+ | _ ->
+ let mArg = arg.Range
+ match arg with
+ | SynExpr.CompExpr _ -> ()
+ | SynExpr.ArrayOrListOfSeqExpr (false, _, _) ->
+ // 'delayed' is about to be dropped on the floor, first do rudimentary checking to get name resolutions in its body
+ RecordNameAndTypeResolutions_IdeallyWithoutHavingOtherEffects_Delayed cenv env tpenv delayed
+ if IsIndexerType cenv.g cenv.amap expr.Type then
+ match expr.Expr with
+ | Expr.Val (d, _, _) ->
+ error (NotAFunctionButIndexer(denv, overallTy, Some d.DisplayName, mExpr, mArg))
+ | _ ->
+ error (NotAFunctionButIndexer(denv, overallTy, None, mExpr, mArg))
+ else
+ error (NotAFunction(denv, overallTy, mExpr, mArg))
+ | _ ->
+ // 'delayed' is about to be dropped on the floor, first do rudimentary checking to get name resolutions in its body
+ RecordNameAndTypeResolutions_IdeallyWithoutHavingOtherEffects_Delayed cenv env tpenv delayed
+ error (NotAFunction(denv, overallTy, mExpr, mArg))
+
+ propagate false delayed expr.Range exprty
+
+and PropagateThenTcDelayed cenv overallTy env tpenv mExpr expr exprty (atomicFlag: ExprAtomicFlag) delayed =
+ Propagate cenv overallTy env tpenv expr exprty delayed
+ TcDelayed cenv overallTy env tpenv mExpr expr exprty atomicFlag delayed
+
+
+/// Typecheck "expr ... " constructs where "..." is a sequence of applications,
+/// type applications and dot-notation projections.
+and TcDelayed cenv overallTy env tpenv mExpr expr exprty (atomicFlag: ExprAtomicFlag) delayed =
+
+ // OK, we've typechecked the thing on the left of the delayed lookup chain.
+ // We can now record for posterity the type of this expression and the location of the expression.
+ if (atomicFlag = ExprAtomicFlag.Atomic) then
+ CallExprHasTypeSink cenv.tcSink (mExpr, env.NameEnv, exprty, env.eAccessRights)
+
+ match delayed with
+ | []
+ | DelayedDot :: _ ->
+ UnifyTypes cenv env mExpr overallTy exprty
+ expr.Expr, tpenv
+ // Expr.M (args) where x.M is a .NET method or index property
+ // expr.M(args) where x.M is a .NET method or index property
+ // expr.M where x.M is a .NET method or index property
+ | DelayedDotLookup (longId, mDotLookup) :: otherDelayed ->
+ TcLookupThen cenv overallTy env tpenv mExpr expr.Expr exprty longId otherDelayed mDotLookup
+ // f x
+ | DelayedApp (hpa, arg, mExprAndArg) :: otherDelayed ->
+ TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty arg hpa otherDelayed
+ // f
+ | DelayedTypeApp (_, mTypeArgs, _mExprAndTypeArgs) :: _ ->
+ error(Error(FSComp.SR.tcUnexpectedTypeArguments(), mTypeArgs))
+ | DelayedSet (synExpr2, mStmt) :: otherDelayed ->
+ if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mExpr))
+ UnifyTypes cenv env mExpr overallTy cenv.g.unit_ty
+ let expr = expr.Expr
+ let _wrap, exprAddress, _readonly, _writeonly = mkExprAddrOfExpr cenv.g true false DefinitelyMutates expr None mExpr
+ let vty = tyOfExpr cenv.g expr
+ // Always allow subsumption on assignment to fields
+ let expr2, tpenv = TcExprFlex cenv true false vty env tpenv synExpr2
+ let v, _ve = mkCompGenLocal mExpr "addr" (mkByrefTy cenv.g vty)
+ mkCompGenLet mStmt v exprAddress (mkAddrSet mStmt (mkLocalValRef v) expr2), tpenv
+
+
+/// Convert the delayed identifiers to a dot-lookup.
+///
+/// TcItemThen: For StaticItem [.Lookup], mPrior is the range of StaticItem
+/// TcLookupThen: For expr.InstanceItem [.Lookup], mPrior is the range of expr.InstanceItem
+and delayRest rest mPrior delayed =
+ match rest with
+ | [] -> delayed
+ | longId ->
+ let mPriorAndLongId = unionRanges mPrior (rangeOfLid longId)
+ DelayedDotLookup (rest, mPriorAndLongId) :: delayed
+
+/// Typecheck "nameof" expressions
+and TcNameOfExpr cenv env tpenv (synArg: SynExpr) =
+
+ let rec stripParens expr =
+ match expr with
+ | SynExpr.Paren(expr, _, _, _) -> stripParens expr
+ | _ -> expr
+
+ let cleanSynArg = stripParens synArg
+ let m = cleanSynArg.Range
+ let rec check overallTyOpt resultOpt expr (delayed: DelayedItem list) =
+ match expr with
+ | LongOrSingleIdent (false, (LongIdentWithDots(longId, _)), _, _) ->
+
+ let ad = env.eAccessRights
+ let result = defaultArg resultOpt (List.last longId)
+
+ // Demangle back to source operator name if the lengths in the ranges indicate the
+ // original source range matches exactly
+ let result =
+ if IsMangledOpName result.idText then
+ let demangled = DecompileOpName result.idText
+ if demangled.Length = result.idRange.EndColumn - result.idRange.StartColumn then
+ ident(demangled, result.idRange)
+ else result
+ else result
+
+ // Nameof resolution resolves to a symbol and in general we make that the same symbol as
+ // would resolve if the long ident was used as an expression at the given location.
+ //
+ // So we first check if the first identifier resolves as an expression, if so commit and and resolve.
+ //
+ // However we don't commit for a type names - nameof allows 'naked' type names and thus all type name
+ // resolutions are checked separately in the next step.
+ let typeNameResInfo = GetLongIdentTypeNameInfo delayed
+ let nameResolutionResult = ResolveLongIdentAsExprAndComputeRange cenv.tcSink cenv.nameResolver (rangeOfLid longId) ad env.eNameResEnv typeNameResInfo longId
+ let resolvesAsExpr =
+ match nameResolutionResult with
+ | Result ((_, item, _, _, _) as res)
+ when
+ (match item with
+ | Item.Types _
+ | Item.DelegateCtor _
+ | Item.CtorGroup _
+ | Item.FakeInterfaceCtor _ -> false
+ | _ -> true) ->
+ let overallTy = match overallTyOpt with None -> NewInferenceType() | Some t -> t
+ let _, _ = TcItemThen cenv overallTy env tpenv res delayed
+ true
+ | _ ->
+ false
+ if resolvesAsExpr then result else
+
+ // If it's not an expression then try to resolve it as a type name
+ let resolvedToTypeName =
+ if (match delayed with [DelayedTypeApp _] | [] -> true | _ -> false) then
+ let (TypeNameResolutionInfo(_, staticArgsInfo)) = GetLongIdentTypeNameInfo delayed
+ match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.UseInAttribute OpenQualified env.eNameResEnv ad longId staticArgsInfo PermitDirectReferenceToGeneratedType.No with
+ | Result (tinstEnclosing, tcref) when IsEntityAccessible cenv.amap m ad tcref ->
+ match delayed with
+ | [DelayedTypeApp (tyargs, _, mExprAndTypeArgs)] ->
+ TcTypeApp cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv mExprAndTypeArgs tcref tinstEnclosing tyargs |> ignore
+ | _ -> ()
+ true // resolved to a type name, done with checks
+ | _ ->
+ false
+ else
+ false
+ if resolvedToTypeName then result else
+
+ // If it's not an expression or type name then resolve it as a module
+ let resolvedToModuleOrNamespaceName =
+ if delayed.IsEmpty then
+ let id,rest = List.headAndTail longId
+ match ResolveLongIdentAsModuleOrNamespace cenv.tcSink ResultCollectionSettings.AllResults cenv.amap m true OpenQualified env.eNameResEnv ad id rest true with
+ | Result modref when delayed.IsEmpty && modref |> List.exists (p23 >> IsEntityAccessible cenv.amap m ad) ->
+ true // resolved to a module or namespace, done with checks
+ | _ ->
+ false
+ else
+ false
+ if resolvedToModuleOrNamespaceName then result else
+
+ ForceRaise nameResolutionResult |> ignore
+ // If that didn't give aan exception then raise a generic error
+ error (Error(FSComp.SR.expressionHasNoName(), m))
+
+ // expr allowed, even with qualifications
+ | SynExpr.TypeApp (hd, _, types, _, _, _, m) ->
+ check overallTyOpt resultOpt hd (DelayedTypeApp(types, m, m) :: delayed)
+
+ // expr.ID allowed
+ | SynExpr.DotGet (hd, _, LongIdentWithDots(longId, _), _) ->
+ let result = defaultArg resultOpt (List.last longId)
+ check overallTyOpt (Some result) hd ((DelayedDotLookup (longId, expr.RangeSansAnyExtraDot)) :: delayed)
+
+ // "(expr)" allowed with no subsequent qualifications
+ | SynExpr.Paren(expr, _, _, _) when delayed.IsEmpty && overallTyOpt.IsNone ->
+ check overallTyOpt resultOpt expr delayed
+
+ // expr : type" allowed with no subsequent qualifications
+ | SynExpr.Typed (synBodyExpr, synType, _m) when delayed.IsEmpty && overallTyOpt.IsNone ->
+ let tgtTy, _tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType
+ check (Some tgtTy) resultOpt synBodyExpr delayed
+
+ | _ ->
+ error (Error(FSComp.SR.expressionHasNoName(), m))
+
+ let lastIdent = check None None cleanSynArg []
+ TcNameOfExprResult cenv lastIdent m
+
+and TcNameOfExprResult cenv (lastIdent: Ident) m =
+ let constRange = mkRange m.FileName m.Start (mkPos m.StartLine (m.StartColumn + lastIdent.idText.Length + 2)) // `2` are for quotes
+ Expr.Const(Const.String(lastIdent.idText), constRange, cenv.g.string_ty)
+
+//-------------------------------------------------------------------------
+// TcFunctionApplicationThen: Typecheck "expr x" + projections
+//-------------------------------------------------------------------------
+
+and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty (synArg: SynExpr) atomicFlag delayed =
+ let denv = env.DisplayEnv
+ let mArg = synArg.Range
+ let mFunExpr = expr.Range
+
+ // If the type of 'synArg' unifies as a function type, then this is a function application, otherwise
+ // it is an error or a computation expression
+ match UnifyFunctionTypeUndoIfFailed cenv denv mFunExpr exprty with
+ | ValueSome (domainTy, resultTy) ->
+ match expr with
+ | ApplicableExpr(_, NameOfExpr cenv.g _, _) when cenv.g.langVersion.SupportsFeature LanguageFeature.NameOf ->
+ let replacementExpr = TcNameOfExpr cenv env tpenv synArg
+ TcDelayed cenv overallTy env tpenv mExprAndArg (ApplicableExpr(cenv, replacementExpr, true)) cenv.g.string_ty ExprAtomicFlag.Atomic delayed
+ | _ ->
+ // Notice the special case 'seq { ... }'. In this case 'seq' is actually a function in the F# library.
+ // Set a flag in the syntax tree to say we noticed a leading 'seq'
+ match synArg with
+ | SynExpr.CompExpr (false, isNotNakedRefCell, _comp, _m) ->
+ isNotNakedRefCell :=
+ !isNotNakedRefCell
+ ||
+ (match expr with
+ | ApplicableExpr(_, Expr.Op(TOp.Coerce, _, [SeqExpr cenv.g], _), _) -> true
+ | _ -> false)
+ | _ -> ()
+
+ let arg, tpenv = TcExpr cenv domainTy env tpenv synArg
+ let exprAndArg, resultTy = buildApp cenv expr resultTy arg mExprAndArg
+ TcDelayed cenv overallTy env tpenv mExprAndArg exprAndArg resultTy atomicFlag delayed
+
+ | ValueNone ->
+ // OK, 'expr' doesn't have function type, but perhaps 'expr' is a computation expression builder, and 'arg' is '{ ... }'
+ match synArg with
+ | SynExpr.CompExpr (false, _isNotNakedRefCell, comp, _m) ->
+ let bodyOfCompExpr, tpenv = cenv.TcComputationExpression cenv env overallTy tpenv (mFunExpr, expr.Expr, exprty, comp)
+ TcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv bodyOfCompExpr) (tyOfExpr cenv.g bodyOfCompExpr) ExprAtomicFlag.NonAtomic delayed
+ | _ ->
+ error (NotAFunction(denv, overallTy, mFunExpr, mArg))
+
+//-------------------------------------------------------------------------
+// TcLongIdentThen: Typecheck "A.B.C.E.F ... " constructs
+//-------------------------------------------------------------------------
+
+and GetLongIdentTypeNameInfo delayed =
+ // Given 'MyOverloadedType.MySubType...' use the number of given type arguments to help
+ // resolve type name lookup of 'MyOverloadedType'
+ // Also determine if type names should resolve to Item.Types or Item.CtorGroup
+ match delayed with
+ | DelayedTypeApp (tyargs, _, _) :: (DelayedDot | DelayedDotLookup _) :: _ ->
+ // cases like 'MyType.Sth'
+ TypeNameResolutionInfo(ResolveTypeNamesToTypeRefs, TypeNameResolutionStaticArgsInfo.FromTyArgs tyargs.Length)
+
+ | DelayedTypeApp (tyargs, _, _) :: _ ->
+ // Note, this also covers the case 'MyType.' (without LValue_get), which is needed for VS (when typing)
+ TypeNameResolutionInfo(ResolveTypeNamesToCtors, TypeNameResolutionStaticArgsInfo.FromTyArgs tyargs.Length)
+
+ | _ ->
+ TypeNameResolutionInfo.Default
+
+and TcLongIdentThen cenv overallTy env tpenv (LongIdentWithDots(longId, _)) delayed =
+
+ let ad = env.eAccessRights
+ let typeNameResInfo = GetLongIdentTypeNameInfo delayed
+ let nameResolutionResult =
+ ResolveLongIdentAsExprAndComputeRange cenv.tcSink cenv.nameResolver (rangeOfLid longId) ad env.eNameResEnv typeNameResInfo longId
+ |> ForceRaise
+ TcItemThen cenv overallTy env tpenv nameResolutionResult delayed
+
+//-------------------------------------------------------------------------
+// Typecheck "item+projections"
+//------------------------------------------------------------------------- *)
+// mItem is the textual range covered by the long identifiers that make up the item
+and TcItemThen cenv overallTy env tpenv (tinstEnclosing, item, mItem, rest, afterResolution) delayed =
+ let g = cenv.g
+ let delayed = delayRest rest mItem delayed
+ let ad = env.eAccessRights
+ match item with
+ // x where x is a union case or active pattern result tag.
+ | (Item.UnionCase _ | Item.ExnCase _ | Item.ActivePatternResult _) as item ->
+ // ucaseAppTy is the type of the union constructor applied to its (optional) argument
+ let ucaseAppTy = NewInferenceType ()
+ let mkConstrApp, argTys, argNames =
+ match item with
+ | Item.ActivePatternResult(apinfo, _, n, _) ->
+ let aparity = apinfo.Names.Length
+ match aparity with
+ | 0 | 1 ->
+ let mkConstrApp _mArgs = function [arg] -> arg | _ -> error(InternalError("ApplyUnionCaseOrExn", mItem))
+ mkConstrApp, [ucaseAppTy], [ for (s, m) in apinfo.ActiveTagsWithRanges -> mkSynId m s ]
+ | _ ->
+ let ucref = mkChoiceCaseRef g mItem aparity n
+ let _, _, tinst, _ = FreshenTyconRef2 mItem ucref.TyconRef
+ let ucinfo = UnionCaseInfo (tinst, ucref)
+ ApplyUnionCaseOrExnTypes mItem cenv env ucaseAppTy (Item.UnionCase(ucinfo, false))
+ | _ ->
+ ApplyUnionCaseOrExnTypes mItem cenv env ucaseAppTy item
+ let numArgTys = List.length argTys
+ // Subsumption at data constructions if argument type is nominal prior to equations for any arguments or return types
+ let flexes = argTys |> List.map (isTyparTy g >> not)
+
+ let (|FittedArgs|_|) arg =
+ match arg with
+ | SynExprParen(SynExpr.Tuple (false, args, _, _), _, _, _)
+ | SynExpr.Tuple (false, args, _, _) when numArgTys > 1 -> Some args
+ | SynExprParen(arg, _, _, _)
+ | arg when numArgTys = 1 -> Some [arg]
+ | _ -> None
+
+ match delayed with
+ // This is where the constructor is applied to an argument
+ | ((DelayedApp (atomicFlag, (FittedArgs args as origArg), mExprAndArg)) :: otherDelayed) ->
+ // assert the overall result type if possible
+ if isNil otherDelayed then
+ UnifyTypes cenv env mExprAndArg overallTy ucaseAppTy
+
+ let numArgs = List.length args
+ UnionCaseOrExnCheck env numArgTys numArgs mExprAndArg
+
+ // if we manage to get here - number of formal arguments = number of actual arguments
+ // apply named parameters
+ let args =
+ // GetMethodArgs checks that no named parameters are located before positional
+ let unnamedArgs, namedCallerArgs = GetMethodArgs origArg
+ match namedCallerArgs with
+ | [] ->
+ args
+ | _ ->
+ let fittedArgs = Array.zeroCreate numArgTys
+
+ // first: put all positional arguments
+ let mutable currentIndex = 0
+ for arg in unnamedArgs do
+ fittedArgs.[currentIndex] <- arg
+ currentIndex <- currentIndex + 1
+
+ let SEEN_NAMED_ARGUMENT = -1
+
+ // dealing with named arguments is a bit tricky since prior to these changes we have an ambiguous situation:
+ // regular notation for named parameters Some(Value = 5) can mean either 1) create option with value - result of equality operation or 2) create option using named arg syntax.
+ // so far we've used 1) so we cannot immediately switch to 2) since it will be a definite breaking change.
+
+ for (_, id, arg) in namedCallerArgs do
+ match argNames |> List.tryFindIndex (fun id2 -> id.idText = id2.idText) with
+ | Some i ->
+ if isNull(box fittedArgs.[i]) then
+ fittedArgs.[i] <- arg
+ let argItem =
+ match item with
+ | Item.UnionCase (uci, _) -> Item.UnionCaseField (uci, i)
+ | Item.ExnCase tref -> Item.RecdField (RecdFieldInfo ([], RecdFieldRef (tref, id.idText)))
+ | _ -> failwithf "Expecting union case or exception item, got: %O" item
+ CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, argItem, emptyTyparInst, ItemOccurence.Use, ad)
+ else error(Error(FSComp.SR.tcUnionCaseFieldCannotBeUsedMoreThanOnce(id.idText), id.idRange))
+ currentIndex <- SEEN_NAMED_ARGUMENT
+ | None ->
+ // ambiguity may appear only when if argument is boolean\generic.
+ // if
+ // - we didn't find argument with specified name AND
+ // - we have not seen any named arguments so far AND
+ // - type of current argument is bool\generic
+ // then we'll favor old behavior and treat current argument as positional.
+ let isSpecialCaseForBackwardCompatibility =
+ (currentIndex <> SEEN_NAMED_ARGUMENT) &&
+ (currentIndex < numArgTys) &&
+ match stripTyEqns g argTys.[currentIndex] with
+ | TType_app(tcref, _) -> tyconRefEq g g.bool_tcr tcref || tyconRefEq g g.system_Bool_tcref tcref
+ | TType_var(_) -> true
+ | _ -> false
+
+ if isSpecialCaseForBackwardCompatibility then
+ assert (isNull(box fittedArgs.[currentIndex]))
+ fittedArgs.[currentIndex] <- List.item currentIndex args // grab original argument, not item from the list of named parameters
+ currentIndex <- currentIndex + 1
+ else
+ match item with
+ | Item.UnionCase(uci, _) ->
+ error(Error(FSComp.SR.tcUnionCaseConstructorDoesNotHaveFieldWithGivenName(uci.Name, id.idText), id.idRange))
+ | Item.ExnCase tcref ->
+ error(Error(FSComp.SR.tcExceptionConstructorDoesNotHaveFieldWithGivenName(tcref.DisplayName, id.idText), id.idRange))
+ | Item.ActivePatternResult(_,_,_,_) ->
+ error(Error(FSComp.SR.tcActivePatternsDoNotHaveFields(), id.idRange))
+ | _ ->
+ error(Error(FSComp.SR.tcConstructorDoesNotHaveFieldWithGivenName(id.idText), id.idRange))
+
+ assert (Seq.forall (box >> ((<>) null) ) fittedArgs)
+ List.ofArray fittedArgs
+
+ let args', tpenv = TcExprs cenv env mExprAndArg tpenv flexes argTys args
+ PropagateThenTcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv (mkConstrApp mExprAndArg args')) ucaseAppTy atomicFlag otherDelayed
+
+ | DelayedTypeApp (_x, mTypeArgs, _mExprAndTypeArgs) :: _delayed' ->
+ error(Error(FSComp.SR.tcUnexpectedTypeArguments(), mTypeArgs))
+ | _ ->
+ // Work out how many syntactic arguments we really expect. Also return a function that builds the overall
+ // expression, but don't apply this function until after we've checked that the number of arguments is OK
+ // (or else we would be building an invalid expression)
+
+ // Unit-taking active pattern result can be applied to no args
+ let numArgs, mkExpr =
+ // This is where the constructor is an active pattern result applied to no argument
+ // Unit-taking active pattern result can be applied to no args
+ if (numArgTys = 1 && match item with Item.ActivePatternResult _ -> true | _ -> false) then
+ UnifyTypes cenv env mItem (List.head argTys) g.unit_ty
+ 1, (fun () -> mkConstrApp mItem [mkUnit g mItem])
+
+ // This is where the constructor expects no arguments and is applied to no argument
+ elif numArgTys = 0 then
+ 0, (fun () -> mkConstrApp mItem [])
+ else
+ // This is where the constructor expects arguments but is not applied to arguments, hence build a lambda
+ numArgTys,
+ (fun () ->
+ let vs, args = argTys |> List.mapi (fun i ty -> mkCompGenLocal mItem ("arg" + string i) ty) |> List.unzip
+ let constrApp = mkConstrApp mItem args
+ let lam = mkMultiLambda mItem vs (constrApp, tyOfExpr g constrApp)
+ lam)
+ UnionCaseOrExnCheck env numArgTys numArgs mItem
+ let expr = mkExpr()
+ let exprTy = tyOfExpr g expr
+ PropagateThenTcDelayed cenv overallTy env tpenv mItem (MakeApplicableExprNoFlex cenv expr) exprTy ExprAtomicFlag.Atomic delayed
+
+ | Item.Types(nm, (ty :: _)) ->
+
+ match delayed with
+ | ((DelayedTypeApp(tyargs, _mTypeArgs, mExprAndTypeArgs)) :: (DelayedDotLookup (longId, mLongId)) :: otherDelayed) ->
+ // If Item.Types is returned then the ty will be of the form TType_app(tcref, genericTyargs) where tyargs
+ // is a fresh instantiation for tcref. TcNestedTypeApplication will chop off precisely #genericTyargs args
+ // and replace them by 'tyargs'
+ let ty, tpenv = TcNestedTypeApplication cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv mExprAndTypeArgs ty tinstEnclosing tyargs
+
+ // Report information about the whole expression including type arguments to VS
+ let item = Item.Types(nm, [ty])
+ CallNameResolutionSink cenv.tcSink (mExprAndTypeArgs, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.eAccessRights)
+ let typeNameResInfo = GetLongIdentTypeNameInfo otherDelayed
+ let item, mItem, rest, afterResolution = ResolveExprDotLongIdentAndComputeRange cenv.tcSink cenv.nameResolver (unionRanges mExprAndTypeArgs mLongId) ad env.eNameResEnv ty longId typeNameResInfo IgnoreOverrides true
+ TcItemThen cenv overallTy env tpenv ((argsOfAppTy g ty), item, mItem, rest, afterResolution) otherDelayed
+
+ | ((DelayedTypeApp(tyargs, _mTypeArgs, mExprAndTypeArgs)) :: _delayed') ->
+ // A case where we have an incomplete name e.g. 'Foo.' - we still want to report it to VS!
+ let ty, _ = TcNestedTypeApplication cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv mExprAndTypeArgs ty tinstEnclosing tyargs
+ let item = Item.Types(nm, [ty])
+ CallNameResolutionSink cenv.tcSink (mExprAndTypeArgs, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.eAccessRights)
+
+ // Same error as in the following case
+ error(Error(FSComp.SR.tcInvalidUseOfTypeName(), mItem))
+
+ | _ ->
+ // In this case the type is not generic, and indeed we should never have returned Item.Types.
+ // That's because ResolveTypeNamesToCtors should have been set at the original
+ // call to ResolveLongIdentAsExprAndComputeRange
+ error(Error(FSComp.SR.tcInvalidUseOfTypeName(), mItem))
+
+ | Item.MethodGroup (methodName, minfos, _) ->
+ // Static method calls Type.Foo(arg1, ..., argn)
+ let meths = List.map (fun minfo -> minfo, None) minfos
+ match delayed with
+ | (DelayedApp (atomicFlag, arg, mExprAndArg) :: otherDelayed) ->
+ TcMethodApplicationThen cenv env overallTy None tpenv None [] mExprAndArg mItem methodName ad NeverMutates false meths afterResolution NormalValUse [arg] atomicFlag otherDelayed
+
+ | (DelayedTypeApp(tys, mTypeArgs, mExprAndTypeArgs) :: otherDelayed) ->
+
+#if !NO_EXTENSIONTYPING
+ match TryTcMethodAppToStaticConstantArgs cenv env tpenv (minfos, Some (tys, mTypeArgs), mExprAndTypeArgs, mItem) with
+ | Some minfoAfterStaticArguments ->
+
+ // Replace the resolution including the static parameters, plus the extra information about the original method info
+ let item = Item.MethodGroup(methodName, [minfoAfterStaticArguments], Some minfos.[0])
+ CallNameResolutionSinkReplacing cenv.tcSink (mItem, env.NameEnv, item, [], ItemOccurence.Use, env.eAccessRights)
+
+ match otherDelayed with
+ | DelayedApp(atomicFlag, arg, mExprAndArg) :: otherDelayed ->
+ TcMethodApplicationThen cenv env overallTy None tpenv None [] mExprAndArg mItem methodName ad NeverMutates false [(minfoAfterStaticArguments, None)] afterResolution NormalValUse [arg] atomicFlag otherDelayed
+ | _ ->
+ TcMethodApplicationThen cenv env overallTy None tpenv None [] mExprAndTypeArgs mItem methodName ad NeverMutates false [(minfoAfterStaticArguments, None)] afterResolution NormalValUse [] ExprAtomicFlag.Atomic otherDelayed
+
+ | None ->
+#endif
+
+ let tyargs, tpenv = TcTypesOrMeasures None cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tys mTypeArgs
+
+ // FUTURE: can we do better than emptyTyparInst here, in order to display instantiations
+ // of type variables in the quick info provided in the IDE? But note we haven't yet even checked if the
+ // number of type arguments is correct...
+ CallNameResolutionSink cenv.tcSink (mExprAndTypeArgs, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.eAccessRights)
+
+ match otherDelayed with
+ | DelayedApp(atomicFlag, arg, mExprAndArg) :: otherDelayed ->
+ TcMethodApplicationThen cenv env overallTy None tpenv (Some tyargs) [] mExprAndArg mItem methodName ad NeverMutates false meths afterResolution NormalValUse [arg] atomicFlag otherDelayed
+ | _ ->
+ TcMethodApplicationThen cenv env overallTy None tpenv (Some tyargs) [] mExprAndTypeArgs mItem methodName ad NeverMutates false meths afterResolution NormalValUse [] ExprAtomicFlag.Atomic otherDelayed
+
+ | _ ->
+#if !NO_EXTENSIONTYPING
+ if not minfos.IsEmpty && minfos.[0].ProvidedStaticParameterInfo.IsSome then
+ error(Error(FSComp.SR.etMissingStaticArgumentsToMethod(), mItem))
+#endif
+ TcMethodApplicationThen cenv env overallTy None tpenv None [] mItem mItem methodName ad NeverMutates false meths afterResolution NormalValUse [] ExprAtomicFlag.Atomic delayed
+
+ | Item.CtorGroup(nm, minfos) ->
+ let objTy =
+ match minfos with
+ | (minfo :: _) -> minfo.ApparentEnclosingType
+ | [] -> error(Error(FSComp.SR.tcTypeHasNoAccessibleConstructor(), mItem))
+ match delayed with
+ | ((DelayedApp (_, arg, mExprAndArg)) :: otherDelayed) ->
+
+ CallExprHasTypeSink cenv.tcSink (mExprAndArg, env.NameEnv, objTy, env.eAccessRights)
+ TcCtorCall true cenv env tpenv overallTy objTy (Some mItem) item false [arg] mExprAndArg otherDelayed (Some afterResolution)
+
+ | ((DelayedTypeApp(tyargs, _mTypeArgs, mExprAndTypeArgs)) :: (DelayedApp (_, arg, mExprAndArg)) :: otherDelayed) ->
+
+ let objTyAfterTyArgs, tpenv = TcNestedTypeApplication cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv mExprAndTypeArgs objTy tinstEnclosing tyargs
+ CallExprHasTypeSink cenv.tcSink (mExprAndArg, env.NameEnv, objTyAfterTyArgs, env.eAccessRights)
+ let itemAfterTyArgs, minfosAfterTyArgs =
+#if !NO_EXTENSIONTYPING
+ // If the type is provided and took static arguments then the constructor will have changed
+ // to a provided constructor on the statically instantiated type. Re-resolve that constructor.
+ match objTyAfterTyArgs with
+ | AppTy g (tcref, _) when tcref.Deref.IsProvided ->
+ let newItem = ForceRaise (ResolveObjectConstructor cenv.nameResolver env.DisplayEnv mExprAndArg ad objTyAfterTyArgs)
+ match newItem with
+ | Item.CtorGroup(_, newMinfos) -> newItem, newMinfos
+ | _ -> item, minfos
+ | _ ->
+#endif
+ item, minfos
+
+ minfosAfterTyArgs |> List.iter (fun minfo -> UnifyTypes cenv env mExprAndTypeArgs minfo.ApparentEnclosingType objTyAfterTyArgs)
+ TcCtorCall true cenv env tpenv overallTy objTyAfterTyArgs (Some mExprAndTypeArgs) itemAfterTyArgs false [arg] mExprAndArg otherDelayed (Some afterResolution)
+
+ | ((DelayedTypeApp(tyargs, _mTypeArgs, mExprAndTypeArgs)) :: otherDelayed) ->
+
+ let objTy, tpenv = TcNestedTypeApplication cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv mExprAndTypeArgs objTy tinstEnclosing tyargs
+
+ // A case where we have an incomplete name e.g. 'Foo.' - we still want to report it to VS!
+ let resolvedItem = Item.Types(nm, [objTy])
+ CallNameResolutionSink cenv.tcSink (mExprAndTypeArgs, env.NameEnv, resolvedItem, emptyTyparInst, ItemOccurence.Use, env.eAccessRights)
+
+ minfos |> List.iter (fun minfo -> UnifyTypes cenv env mExprAndTypeArgs minfo.ApparentEnclosingType objTy)
+ TcCtorCall true cenv env tpenv overallTy objTy (Some mExprAndTypeArgs) item false [] mExprAndTypeArgs otherDelayed (Some afterResolution)
+
+ | _ ->
+
+ TcCtorCall true cenv env tpenv overallTy objTy (Some mItem) item false [] mItem delayed (Some afterResolution)
+
+ | Item.FakeInterfaceCtor _ ->
+ error(Error(FSComp.SR.tcInvalidUseOfInterfaceType(), mItem))
+
+ | Item.ImplicitOp(id, sln) ->
+
+ let isPrefix = PrettyNaming.IsPrefixOperator id.idText
+ let isTernary = PrettyNaming.IsTernaryOperator id.idText
+
+ let argData =
+ if isPrefix then
+ [ Typar(mkSynId mItem (cenv.synArgNameGenerator.New()), HeadTypeStaticReq, true) ]
+ elif isTernary then
+ [ Typar(mkSynId mItem (cenv.synArgNameGenerator.New()), HeadTypeStaticReq, true)
+ Typar(mkSynId mItem (cenv.synArgNameGenerator.New()), HeadTypeStaticReq, true)
+ Typar(mkSynId mItem (cenv.synArgNameGenerator.New()), HeadTypeStaticReq, true) ]
+ else
+ [ Typar(mkSynId mItem (cenv.synArgNameGenerator.New()), HeadTypeStaticReq, true)
+ Typar(mkSynId mItem (cenv.synArgNameGenerator.New()), HeadTypeStaticReq, true) ]
+
+ let retTyData = Typar(mkSynId mItem (cenv.synArgNameGenerator.New()), HeadTypeStaticReq, true)
+ let argTypars = argData |> List.map (fun d -> Construct.NewTypar (TyparKind.Type, TyparRigidity.Flexible, d, false, TyparDynamicReq.Yes, [], false, false))
+ let retTypar = Construct.NewTypar (TyparKind.Type, TyparRigidity.Flexible, retTyData, false, TyparDynamicReq.Yes, [], false, false)
+ let argTys = argTypars |> List.map mkTyparTy
+ let retTy = mkTyparTy retTypar
+
+ let vs, ves = argTys |> List.mapi (fun i ty -> mkCompGenLocal mItem ("arg" + string i) ty) |> List.unzip
+
+ let memberFlags = StaticMemberFlags MemberKind.Member
+ let logicalCompiledName = ComputeLogicalName id memberFlags
+ let traitInfo = TTrait(argTys, logicalCompiledName, memberFlags, argTys, Some retTy, sln)
+
+ let expr = Expr.Op (TOp.TraitCall traitInfo, [], ves, mItem)
+ let expr = mkLambdas mItem [] vs (expr, retTy)
+
+ let rec isSimpleArgument e =
+ match e with
+ | SynExpr.New (_, _, synExpr, _)
+ | SynExpr.Paren (synExpr, _, _, _)
+ | SynExpr.Typed (synExpr, _, _)
+ | SynExpr.TypeApp (synExpr, _, _, _, _, _, _)
+ | SynExpr.TypeTest (synExpr, _, _)
+ | SynExpr.Upcast (synExpr, _, _)
+ | SynExpr.DotGet (synExpr, _, _, _)
+ | SynExpr.Downcast (synExpr, _, _)
+ | SynExpr.InferredUpcast (synExpr, _)
+ | SynExpr.InferredDowncast (synExpr, _)
+ | SynExpr.AddressOf (_, synExpr, _, _)
+ | SynExpr.Quote (_, _, synExpr, _, _) -> isSimpleArgument synExpr
+
+ | SynExpr.InterpolatedString _
+ | SynExpr.Null _
+ | SynExpr.Ident _
+ | SynExpr.Const _
+ | SynExpr.LongIdent _ -> true
+
+ | SynExpr.Tuple (_, synExprs, _, _)
+ | SynExpr.ArrayOrList (_, synExprs, _) -> synExprs |> List.forall isSimpleArgument
+ | SynExpr.Record (_, copyOpt, fields, _) -> copyOpt |> Option.forall (fst >> isSimpleArgument) && fields |> List.forall (p23 >> Option.forall isSimpleArgument)
+ | SynExpr.App (_, _, synExpr, synExpr2, _) -> isSimpleArgument synExpr && isSimpleArgument synExpr2
+ | SynExpr.IfThenElse (synExpr, synExpr2, synExprOpt, _, _, _, _) -> isSimpleArgument synExpr && isSimpleArgument synExpr2 && Option.forall isSimpleArgument synExprOpt
+ | SynExpr.DotIndexedGet (synExpr, _, _, _) -> isSimpleArgument synExpr
+ | SynExpr.ObjExpr _
+ | SynExpr.AnonRecd _
+ | SynExpr.While _
+ | SynExpr.For _
+ | SynExpr.ForEach _
+ | SynExpr.ArrayOrListOfSeqExpr _
+ | SynExpr.CompExpr _
+ | SynExpr.Lambda _
+ | SynExpr.MatchLambda _
+ | SynExpr.Match _
+ | SynExpr.Do _
+ | SynExpr.Assert _
+ | SynExpr.Fixed _
+ | SynExpr.TryWith _
+ | SynExpr.TryFinally _
+ | SynExpr.Lazy _
+ | SynExpr.Sequential _
+ | SynExpr.SequentialOrImplicitYield _
+ | SynExpr.LetOrUse _
+ | SynExpr.DotSet _
+ | SynExpr.DotIndexedSet _
+ | SynExpr.LongIdentSet _
+ | SynExpr.Set _
+ | SynExpr.JoinIn _
+ | SynExpr.NamedIndexedPropertySet _
+ | SynExpr.DotNamedIndexedPropertySet _
+ | SynExpr.LibraryOnlyILAssembly _
+ | SynExpr.LibraryOnlyStaticOptimization _
+ | SynExpr.LibraryOnlyUnionCaseFieldGet _
+ | SynExpr.LibraryOnlyUnionCaseFieldSet _
+ | SynExpr.ArbitraryAfterError (_, _)
+ | SynExpr.FromParseError (_, _)
+ | SynExpr.DiscardAfterMissingQualificationAfterDot (_, _)
+ | SynExpr.ImplicitZero _
+ | SynExpr.YieldOrReturn _
+ | SynExpr.YieldOrReturnFrom _
+ | SynExpr.MatchBang _
+ | SynExpr.LetOrUseBang _
+ | SynExpr.DoBang _
+ | SynExpr.TraitCall _
+ -> false
+
+
+ // Propagate the known application structure into function types
+ Propagate cenv overallTy env tpenv (MakeApplicableExprNoFlex cenv expr) (tyOfExpr g expr) delayed
+
+ // Take all simple arguments and process them before applying the constraint.
+ let delayed1, delayed2 =
+ let pred = (function (DelayedApp (_, arg, _)) -> isSimpleArgument arg | _ -> false)
+ List.takeWhile pred delayed, List.skipWhile pred delayed
+ let intermediateTy = if isNil delayed2 then overallTy else NewInferenceType ()
+
+ let resultExpr, tpenv = TcDelayed cenv intermediateTy env tpenv mItem (MakeApplicableExprNoFlex cenv expr) (tyOfExpr g expr) ExprAtomicFlag.NonAtomic delayed1
+
+ // Add the constraint after the application arguments have been checked to allow annotations to kick in on rigid type parameters
+ AddCxMethodConstraint env.DisplayEnv cenv.css mItem NoTrace traitInfo
+
+ // Process all remaining arguments after the constraint is asserted
+ let resultExpr2, tpenv2 = TcDelayed cenv overallTy env tpenv mItem (MakeApplicableExprNoFlex cenv resultExpr) intermediateTy ExprAtomicFlag.NonAtomic delayed2
+ resultExpr2, tpenv2
+
+
+ | Item.DelegateCtor ty ->
+ match delayed with
+ | ((DelayedApp (atomicFlag, arg, mItemAndArg)) :: otherDelayed) ->
+ TcNewDelegateThen cenv overallTy env tpenv mItem mItemAndArg ty arg atomicFlag otherDelayed
+ | ((DelayedTypeApp(tyargs, _mTypeArgs, mItemAndTypeArgs)) :: (DelayedApp (atomicFlag, arg, mItemAndArg)) :: otherDelayed) ->
+ let ty, tpenv = TcNestedTypeApplication cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv mItemAndTypeArgs ty tinstEnclosing tyargs
+
+ // Report information about the whole expression including type arguments to VS
+ let item = Item.DelegateCtor ty
+ CallNameResolutionSink cenv.tcSink (mItemAndTypeArgs, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.eAccessRights)
+ TcNewDelegateThen cenv overallTy env tpenv mItem mItemAndArg ty arg atomicFlag otherDelayed
+ | _ ->
+ error(Error(FSComp.SR.tcInvalidUseOfDelegate(), mItem))
+
+ | Item.Value vref ->
+
+ match delayed with
+ // Mutable value set: 'v <- e'
+ | DelayedSet(e2, mStmt) :: otherDelayed ->
+ if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mStmt))
+ UnifyTypes cenv env mStmt overallTy g.unit_ty
+ vref.Deref.SetHasBeenReferenced()
+ CheckValAccessible mItem env.AccessRights vref
+ CheckValAttributes g vref mItem |> CommitOperationResult
+ let vty = vref.Type
+ let vty2 =
+ if isByrefTy g vty then
+ destByrefTy g vty
+ else
+ if not vref.IsMutable then
+ errorR (ValNotMutable (env.DisplayEnv, vref, mStmt))
+ vty
+ // Always allow subsumption on assignment to fields
+ let e2', tpenv = TcExprFlex cenv true false vty2 env tpenv e2
+ let vexp =
+ if isInByrefTy g vty then
+ errorR(Error(FSComp.SR.writeToReadOnlyByref(), mStmt))
+ mkAddrSet mStmt vref e2'
+ elif isByrefTy g vty then
+ mkAddrSet mStmt vref e2'
+ else
+ mkValSet mStmt vref e2'
+
+ PropagateThenTcDelayed cenv overallTy env tpenv mStmt (MakeApplicableExprNoFlex cenv vexp) (tyOfExpr g vexp) ExprAtomicFlag.NonAtomic otherDelayed
+
+ // Value instantiation: v ...
+ | (DelayedTypeApp(tys, _mTypeArgs, mExprAndTypeArgs) :: otherDelayed) ->
+ // Note: we know this is a NormalValUse or PossibleConstrainedCall because:
+ // - it isn't a CtorValUsedAsSuperInit
+ // - it isn't a CtorValUsedAsSelfInit
+ // - it isn't a VSlotDirectCall (uses of base values do not take type arguments
+ // Allow `nameof<'T>` for a generic parameter
+ match vref with
+ | _ when isNameOfValRef cenv.g vref && cenv.g.langVersion.SupportsFeature LanguageFeature.NameOf ->
+ match tys with
+ | [SynType.Var((Typar(id, _, false) as tp), _m)] ->
+ let _tp', tpenv = TcTyparOrMeasurePar None cenv env ImplicitlyBoundTyparsAllowed.NoNewTypars tpenv tp
+ let vexp = TcNameOfExprResult cenv id mExprAndTypeArgs
+ let vexpFlex = MakeApplicableExprNoFlex cenv vexp
+ PropagateThenTcDelayed cenv overallTy env tpenv mExprAndTypeArgs vexpFlex cenv.g.string_ty ExprAtomicFlag.Atomic otherDelayed
+ | _ ->
+ error (Error(FSComp.SR.expressionHasNoName(), mExprAndTypeArgs))
+ | _ ->
+ let checkTys tpenv kinds = TcTypesOrMeasures (Some kinds) cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tys mItem
+ let _, vexp, isSpecial, _, _, tpenv = TcVal true cenv env tpenv vref (Some (NormalValUse, checkTys)) (Some afterResolution) mItem
+
+ let vexpFlex = (if isSpecial then MakeApplicableExprNoFlex cenv vexp else MakeApplicableExprWithFlex cenv env vexp)
+ // We need to eventually record the type resolution for an expression, but this is done
+ // inside PropagateThenTcDelayed, so we don't have to explicitly call 'CallExprHasTypeSink' here
+ PropagateThenTcDelayed cenv overallTy env tpenv mExprAndTypeArgs vexpFlex vexpFlex.Type ExprAtomicFlag.Atomic otherDelayed
+
+ // Value get
+ | _ ->
+ let _, vexp, isSpecial, _, _, tpenv = TcVal true cenv env tpenv vref None (Some afterResolution) mItem
+ let vexpFlex = (if isSpecial then MakeApplicableExprNoFlex cenv vexp else MakeApplicableExprWithFlex cenv env vexp)
+ PropagateThenTcDelayed cenv overallTy env tpenv mItem vexpFlex vexpFlex.Type ExprAtomicFlag.Atomic delayed
+
+ | Item.Property (nm, pinfos) ->
+ if isNil pinfos then error (InternalError ("Unexpected error: empty property list", mItem))
+ // if there are both intrinsics and extensions in pinfos, intrinsics will be listed first.
+ // by looking at List.Head we are letting the intrinsics determine indexed/non-indexed
+ let pinfo = List.head pinfos
+ let _, tyargsOpt, args, delayed, tpenv =
+ if pinfo.IsIndexer
+ then GetMemberApplicationArgs delayed cenv env tpenv
+ else ExprAtomicFlag.Atomic, None, [mkSynUnit mItem], delayed, tpenv
+ if not pinfo.IsStatic then error (Error (FSComp.SR.tcPropertyIsNotStatic nm, mItem))
+ match delayed with
+ | DelayedSet(e2, mStmt) :: otherDelayed ->
+ if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mStmt))
+ // Static Property Set (possibly indexer)
+ UnifyTypes cenv env mStmt overallTy g.unit_ty
+ let meths = pinfos |> SettersOfPropInfos
+ if meths.IsEmpty then
+ let meths = pinfos |> GettersOfPropInfos
+ let isByrefMethReturnSetter = meths |> List.exists (function (_,Some pinfo) -> isByrefTy g (pinfo.GetPropertyType(cenv.amap,mItem)) | _ -> false)
+ if not isByrefMethReturnSetter then
+ errorR (Error (FSComp.SR.tcPropertyCannotBeSet1 nm, mItem))
+ // x.P <- ... byref setter
+ if isNil meths then error (Error (FSComp.SR.tcPropertyIsNotReadable nm, mItem))
+ TcMethodApplicationThen cenv env overallTy None tpenv tyargsOpt [] mItem mItem nm ad NeverMutates true meths afterResolution NormalValUse args ExprAtomicFlag.Atomic delayed
+ else
+ let args = if pinfo.IsIndexer then args else []
+ if isNil meths then
+ errorR (Error (FSComp.SR.tcPropertyCannotBeSet1 nm, mItem))
+ // Note: static calls never mutate a struct object argument
+ TcMethodApplicationThen cenv env overallTy None tpenv tyargsOpt [] mStmt mItem nm ad NeverMutates true meths afterResolution NormalValUse (args@[e2]) ExprAtomicFlag.NonAtomic otherDelayed
+ | _ ->
+ // Static Property Get (possibly indexer)
+ let meths = pinfos |> GettersOfPropInfos
+ if isNil meths then error (Error (FSComp.SR.tcPropertyIsNotReadable nm, mItem))
+ // Note: static calls never mutate a struct object argument
+ TcMethodApplicationThen cenv env overallTy None tpenv tyargsOpt [] mItem mItem nm ad NeverMutates true meths afterResolution NormalValUse args ExprAtomicFlag.Atomic delayed
+
+ | Item.ILField finfo ->
+
+ ILFieldStaticChecks g cenv.amap cenv.infoReader ad mItem finfo
+ let fref = finfo.ILFieldRef
+ let exprty = finfo.FieldType(cenv.amap, mItem)
+ match delayed with
+ | DelayedSet(e2, mStmt) :: _delayed' ->
+ UnifyTypes cenv env mStmt overallTy g.unit_ty
+ // Always allow subsumption on assignment to fields
+ let e2', tpenv = TcExprFlex cenv true false exprty env tpenv e2
+ let expr = BuildILStaticFieldSet mStmt finfo e2'
+ expr, tpenv
+ | _ ->
+ // Get static IL field
+ let expr =
+ match finfo.LiteralValue with
+ | Some lit ->
+ Expr.Const (TcFieldInit mItem lit, mItem, exprty)
+ | None ->
+ let isValueType = finfo.IsValueType
+ let valu = if isValueType then AsValue else AsObject
+
+ // The empty instantiation on the fspec is OK, since we make the correct fspec in IlxGen.GenAsm
+ // This ensures we always get the type instantiation right when doing this from
+ // polymorphic code, after inlining etc.
+ let fspec = mkILFieldSpec(fref, mkILNamedTy valu fref.DeclaringTypeRef [])
+
+ // Add an I_nop if this is an initonly field to make sure we never recognize it as an lvalue. See mkExprAddrOfExpr.
+ mkAsmExpr ([ mkNormalLdsfld fspec ] @ (if finfo.IsInitOnly then [ AI_nop ] else []), finfo.TypeInst, [], [exprty], mItem)
+ PropagateThenTcDelayed cenv overallTy env tpenv mItem (MakeApplicableExprWithFlex cenv env expr) exprty ExprAtomicFlag.Atomic delayed
+
+ | Item.RecdField rfinfo ->
+ // Get static F# field or literal
+ CheckRecdFieldInfoAccessible cenv.amap mItem ad rfinfo
+ if not rfinfo.IsStatic then error (Error (FSComp.SR.tcFieldIsNotStatic(rfinfo.Name), mItem))
+ CheckRecdFieldInfoAttributes g rfinfo mItem |> CommitOperationResult
+ let fref = rfinfo.RecdFieldRef
+ let fieldTy = rfinfo.FieldType
+ match delayed with
+ | DelayedSet(e2, mStmt) :: otherDelayed ->
+ if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mStmt))
+
+ // Set static F# field
+ CheckRecdFieldMutation mItem env.DisplayEnv rfinfo
+ UnifyTypes cenv env mStmt overallTy g.unit_ty
+ let fieldTy = rfinfo.FieldType
+ // Always allow subsumption on assignment to fields
+ let e2', tpenv = TcExprFlex cenv true false fieldTy env tpenv e2
+ let expr = mkStaticRecdFieldSet (rfinfo.RecdFieldRef, rfinfo.TypeInst, e2', mStmt)
+ expr, tpenv
+ | _ ->
+ let exprty = fieldTy
+ let expr =
+ match rfinfo.LiteralValue with
+ // Get literal F# field
+ | Some lit -> Expr.Const (lit, mItem, exprty)
+ // Get static F# field
+ | None -> mkStaticRecdFieldGet (fref, rfinfo.TypeInst, mItem)
+ PropagateThenTcDelayed cenv overallTy env tpenv mItem (MakeApplicableExprWithFlex cenv env expr) exprty ExprAtomicFlag.Atomic delayed
+
+ | Item.Event einfo ->
+ // Instance IL event (fake up event-as-value)
+ TcEventValueThen cenv overallTy env tpenv mItem mItem None einfo delayed
+
+ | Item.CustomOperation (nm, usageTextOpt, _) ->
+ // 'delayed' is about to be dropped on the floor, first do rudimentary checking to get name resolutions in its body
+ RecordNameAndTypeResolutions_IdeallyWithoutHavingOtherEffects_Delayed cenv env tpenv delayed
+ match usageTextOpt() with
+ | None -> error(Error(FSComp.SR.tcCustomOperationNotUsedCorrectly nm, mItem))
+ | Some usageText -> error(Error(FSComp.SR.tcCustomOperationNotUsedCorrectly2(nm, usageText), mItem))
+ | _ -> error(Error(FSComp.SR.tcLookupMayNotBeUsedHere(), mItem))
+
+
+//-------------------------------------------------------------------------
+// Typecheck "expr.A.B.C ... " constructs
+//-------------------------------------------------------------------------
+
+and GetSynMemberApplicationArgs delayed tpenv =
+ match delayed with
+ | DelayedApp (atomicFlag, arg, _) :: otherDelayed ->
+ atomicFlag, None, [arg], otherDelayed, tpenv
+ | DelayedTypeApp(tyargs, mTypeArgs, _) :: DelayedApp (atomicFlag, arg, _mExprAndArg) :: otherDelayed ->
+ (atomicFlag, Some (tyargs, mTypeArgs), [arg], otherDelayed, tpenv)
+ | DelayedTypeApp(tyargs, mTypeArgs, _) :: otherDelayed ->
+ (ExprAtomicFlag.Atomic, Some (tyargs, mTypeArgs), [], otherDelayed, tpenv)
+ | otherDelayed ->
+ (ExprAtomicFlag.NonAtomic, None, [], otherDelayed, tpenv)
+
+
+and TcMemberTyArgsOpt cenv env tpenv tyargsOpt =
+ match tyargsOpt with
+ | None -> None, tpenv
+ | Some (tyargs, mTypeArgs) ->
+ let tyargsChecked, tpenv = TcTypesOrMeasures None cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tyargs mTypeArgs
+ Some tyargsChecked, tpenv
+
+and GetMemberApplicationArgs delayed cenv env tpenv =
+ let atomicFlag, tyargsOpt, args, delayed, tpenv = GetSynMemberApplicationArgs delayed tpenv
+ let tyArgsOptChecked, tpenv = TcMemberTyArgsOpt cenv env tpenv tyargsOpt
+ atomicFlag, tyArgsOptChecked, args, delayed, tpenv
+
+and TcLookupThen cenv overallTy env tpenv mObjExpr objExpr objExprTy longId delayed mExprAndLongId =
+ let objArgs = [objExpr]
+ let ad = env.eAccessRights
+
+ // 'base' calls use a different resolution strategy when finding methods.
+ let findFlag =
+ let baseCall = IsBaseCall objArgs
+ (if baseCall then PreferOverrides else IgnoreOverrides)
+
+ // Canonicalize inference problem prior to '.' lookup on variable types
+ if isTyparTy cenv.g objExprTy then
+ ConstraintSolver.CanonicalizePartialInferenceProblem cenv.css env.DisplayEnv mExprAndLongId (freeInTypeLeftToRight cenv.g false objExprTy)
+
+ let item, mItem, rest, afterResolution = ResolveExprDotLongIdentAndComputeRange cenv.tcSink cenv.nameResolver mExprAndLongId ad env.NameEnv objExprTy longId TypeNameResolutionInfo.Default findFlag false
+ let mExprAndItem = unionRanges mObjExpr mItem
+ let delayed = delayRest rest mExprAndItem delayed
+
+ match item with
+ | Item.MethodGroup (methodName, minfos, _) ->
+ let atomicFlag, tyargsOpt, args, delayed, tpenv = GetSynMemberApplicationArgs delayed tpenv
+ // We pass PossiblyMutates here because these may actually mutate a value type object
+ // To get better warnings we special case some of the few known mutate-a-struct method names
+ let mutates = (if methodName = "MoveNext" || methodName = "GetNextArg" then DefinitelyMutates else PossiblyMutates)
+
+#if !NO_EXTENSIONTYPING
+ match TryTcMethodAppToStaticConstantArgs cenv env tpenv (minfos, tyargsOpt, mExprAndItem, mItem) with
+ | Some minfoAfterStaticArguments ->
+ // Replace the resolution including the static parameters, plus the extra information about the original method info
+ let item = Item.MethodGroup(methodName, [minfoAfterStaticArguments], Some minfos.[0])
+ CallNameResolutionSinkReplacing cenv.tcSink (mExprAndItem, env.NameEnv, item, [], ItemOccurence.Use, env.eAccessRights)
+
+ TcMethodApplicationThen cenv env overallTy None tpenv None objArgs mExprAndItem mItem methodName ad mutates false [(minfoAfterStaticArguments, None)] afterResolution NormalValUse args atomicFlag delayed
+ | None ->
+ if not minfos.IsEmpty && minfos.[0].ProvidedStaticParameterInfo.IsSome then
+ error(Error(FSComp.SR.etMissingStaticArgumentsToMethod(), mItem))
+#endif
+
+ let tyargsOpt, tpenv = TcMemberTyArgsOpt cenv env tpenv tyargsOpt
+ let meths = minfos |> List.map (fun minfo -> minfo, None)
+
+ TcMethodApplicationThen cenv env overallTy None tpenv tyargsOpt objArgs mExprAndItem mItem methodName ad mutates false meths afterResolution NormalValUse args atomicFlag delayed
+
+ | Item.Property (nm, pinfos) ->
+ // Instance property
+ if isNil pinfos then error (InternalError ("Unexpected error: empty property list", mItem))
+ // if there are both intrinsics and extensions in pinfos, intrinsics will be listed first.
+ // by looking at List.Head we are letting the intrinsics determine indexed/non-indexed
+ let pinfo = List.head pinfos
+ let atomicFlag, tyargsOpt, args, delayed, tpenv =
+ if pinfo.IsIndexer
+ then GetMemberApplicationArgs delayed cenv env tpenv
+ else ExprAtomicFlag.Atomic, None, [mkSynUnit mItem], delayed, tpenv
+ if pinfo.IsStatic then error (Error (FSComp.SR.tcPropertyIsStatic nm, mItem))
+
+
+ match delayed with
+ | DelayedSet(e2, mStmt) :: otherDelayed ->
+ if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mStmt))
+ // Instance property setter
+ UnifyTypes cenv env mStmt overallTy cenv.g.unit_ty
+ let meths = SettersOfPropInfos pinfos
+ if meths.IsEmpty then
+ let meths = pinfos |> GettersOfPropInfos
+ let isByrefMethReturnSetter = meths |> List.exists (function (_,Some pinfo) -> isByrefTy cenv.g (pinfo.GetPropertyType(cenv.amap,mItem)) | _ -> false)
+ if not isByrefMethReturnSetter then
+ errorR (Error (FSComp.SR.tcPropertyCannotBeSet1 nm, mItem))
+ // x.P <- ... byref setter
+ if isNil meths then error (Error (FSComp.SR.tcPropertyIsNotReadable nm, mItem))
+ TcMethodApplicationThen cenv env overallTy None tpenv tyargsOpt objArgs mExprAndItem mItem nm ad PossiblyMutates true meths afterResolution NormalValUse args atomicFlag delayed
+ else
+ let args = if pinfo.IsIndexer then args else []
+ let mut = (if isStructTy cenv.g (tyOfExpr cenv.g objExpr) then DefinitelyMutates else PossiblyMutates)
+ TcMethodApplicationThen cenv env overallTy None tpenv tyargsOpt objArgs mStmt mItem nm ad mut true meths afterResolution NormalValUse (args @ [e2]) atomicFlag []
+ | _ ->
+ // Instance property getter
+ let meths = GettersOfPropInfos pinfos
+ if isNil meths then error (Error (FSComp.SR.tcPropertyIsNotReadable nm, mItem))
+ TcMethodApplicationThen cenv env overallTy None tpenv tyargsOpt objArgs mExprAndItem mItem nm ad PossiblyMutates true meths afterResolution NormalValUse args atomicFlag delayed
+
+ | Item.RecdField rfinfo ->
+ // Get or set instance F# field or literal
+ RecdFieldInstanceChecks cenv.g cenv.amap ad mItem rfinfo
+ let tgtTy = rfinfo.DeclaringType
+ let valu = isStructTy cenv.g tgtTy
+ AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css mItem NoTrace tgtTy objExprTy
+ let objExpr = if valu then objExpr else mkCoerceExpr(objExpr, tgtTy, mExprAndItem, objExprTy)
+ let fieldTy = rfinfo.FieldType
+ match delayed with
+ | DelayedSet(e2, mStmt) :: otherDelayed ->
+ // Mutable value set: 'v <- e'
+ if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mItem))
+ CheckRecdFieldMutation mItem env.DisplayEnv rfinfo
+ UnifyTypes cenv env mStmt overallTy cenv.g.unit_ty
+ // Always allow subsumption on assignment to fields
+ let e2', tpenv = TcExprFlex cenv true false fieldTy env tpenv e2
+ BuildRecdFieldSet cenv.g mStmt objExpr rfinfo e2', tpenv
+
+ | _ ->
+
+ // Instance F# Record or Class field
+ let objExpr' = mkRecdFieldGet cenv.g (objExpr, rfinfo.RecdFieldRef, rfinfo.TypeInst, mExprAndItem)
+ PropagateThenTcDelayed cenv overallTy env tpenv mExprAndItem (MakeApplicableExprWithFlex cenv env objExpr') fieldTy ExprAtomicFlag.Atomic delayed
+
+ | Item.AnonRecdField (anonInfo, tinst, n, _) ->
+ let tgty = TType_anon (anonInfo, tinst)
+ AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css mItem NoTrace tgty objExprTy
+ let fieldTy = List.item n tinst
+ match delayed with
+ | DelayedSet _ :: _otherDelayed ->
+ error(Error(FSComp.SR.tcInvalidAssignment(),mItem))
+ | _ ->
+ // Instance F# Anonymous Record
+ let objExpr' = mkAnonRecdFieldGet cenv.g (anonInfo,objExpr,tinst,n,mExprAndItem)
+ PropagateThenTcDelayed cenv overallTy env tpenv mExprAndItem (MakeApplicableExprWithFlex cenv env objExpr') fieldTy ExprAtomicFlag.Atomic delayed
+
+ | Item.ILField finfo ->
+ // Get or set instance IL field
+ ILFieldInstanceChecks cenv.g cenv.amap ad mItem finfo
+ let exprty = finfo.FieldType(cenv.amap, mItem)
+
+ match delayed with
+ // Set instance IL field
+ | DelayedSet(e2, mStmt) :: _delayed' ->
+ UnifyTypes cenv env mStmt overallTy cenv.g.unit_ty
+ // Always allow subsumption on assignment to fields
+ let e2', tpenv = TcExprFlex cenv true false exprty env tpenv e2
+ let expr = BuildILFieldSet cenv.g mStmt objExpr finfo e2'
+ expr, tpenv
+ | _ ->
+ let expr = BuildILFieldGet cenv.g cenv.amap mExprAndItem objExpr finfo
+ PropagateThenTcDelayed cenv overallTy env tpenv mExprAndItem (MakeApplicableExprWithFlex cenv env expr) exprty ExprAtomicFlag.Atomic delayed
+
+ | Item.Event einfo ->
+ // Instance IL event (fake up event-as-value)
+ TcEventValueThen cenv overallTy env tpenv mItem mExprAndItem (Some(objExpr, objExprTy)) einfo delayed
+
+ | (Item.FakeInterfaceCtor _ | Item.DelegateCtor _) -> error (Error (FSComp.SR.tcConstructorsCannotBeFirstClassValues(), mItem))
+ | _ -> error (Error (FSComp.SR.tcSyntaxFormUsedOnlyWithRecordLabelsPropertiesAndFields(), mItem))
+
+and TcEventValueThen cenv overallTy env tpenv mItem mExprAndItem objDetails (einfo: EventInfo) delayed =
+ // Instance IL event (fake up event-as-value)
+ let nm = einfo.EventName
+ let ad = env.eAccessRights
+ match objDetails, einfo.IsStatic with
+ | Some _, true -> error (Error (FSComp.SR.tcEventIsStatic nm, mItem))
+ | None, false -> error (Error (FSComp.SR.tcEventIsNotStatic nm, mItem))
+ | _ -> ()
+
+ let delegateType = einfo.GetDelegateType(cenv.amap, mItem)
+ let (SigOfFunctionForDelegate(invokeMethInfo, compiledViewOfDelArgTys, _, _)) = GetSigOfFunctionForDelegate cenv.infoReader delegateType mItem ad
+ let objArgs = Option.toList (Option.map fst objDetails)
+ MethInfoChecks cenv.g cenv.amap true None objArgs env.eAccessRights mItem invokeMethInfo
+
+ // This checks for and drops the 'object' sender
+ let argsTy = ArgsTypOfEventInfo cenv.infoReader mItem ad einfo
+ if not (slotSigHasVoidReturnTy (invokeMethInfo.GetSlotSig(cenv.amap, mItem))) then errorR (nonStandardEventError einfo.EventName mItem)
+ let delEventTy = mkIEventType cenv.g delegateType argsTy
+
+ let bindObjArgs f =
+ match objDetails with
+ | None -> f []
+ | Some (objExpr, objExprTy) -> mkCompGenLetIn mItem "eventTarget" objExprTy objExpr (fun (_, ve) -> f [ve])
+
+ // Bind the object target expression to make sure we only run its side effects once, and to make
+ // sure if it's a mutable reference then we dereference it - see FSharp 1.0 bug 942
+ let expr =
+ bindObjArgs (fun objVars ->
+ // EventHelper ((fun d -> e.add_X(d)), (fun d -> e.remove_X(d)), (fun f -> new 'Delegate(f)))
+ mkCallCreateEvent cenv.g mItem delegateType argsTy
+ (let dv, de = mkCompGenLocal mItem "eventDelegate" delegateType
+ let callExpr, _ = BuildPossiblyConditionalMethodCall cenv env PossiblyMutates mItem false einfo.AddMethod NormalValUse [] objVars [de]
+ mkLambda mItem dv (callExpr, cenv.g.unit_ty))
+ (let dv, de = mkCompGenLocal mItem "eventDelegate" delegateType
+ let callExpr, _ = BuildPossiblyConditionalMethodCall cenv env PossiblyMutates mItem false einfo.RemoveMethod NormalValUse [] objVars [de]
+ mkLambda mItem dv (callExpr, cenv.g.unit_ty))
+ (let fvty = (cenv.g.obj_ty --> (argsTy --> cenv.g.unit_ty))
+ let fv, fe = mkCompGenLocal mItem "callback" fvty
+ let createExpr = BuildNewDelegateExpr (Some einfo, cenv.g, cenv.amap, delegateType, invokeMethInfo, compiledViewOfDelArgTys, fe, fvty, mItem)
+ mkLambda mItem fv (createExpr, delegateType)))
+
+ let exprty = delEventTy
+ PropagateThenTcDelayed cenv overallTy env tpenv mExprAndItem (MakeApplicableExprNoFlex cenv expr) exprty ExprAtomicFlag.Atomic delayed
+
+
+//-------------------------------------------------------------------------
+// Method uses can calls
+//-------------------------------------------------------------------------
+
+/// Typecheck method/member calls and uses of members as first-class values.
+and TcMethodApplicationThen
+ cenv
+ env
+ overallTy // The type of the overall expression including "delayed". The method "application" may actually be a use of a member as
+ // a first-class function value, when this would be a function type.
+ objTyOpt // methodType
+ tpenv
+ callerTyArgs // The return type of the overall expression including "delayed"
+ objArgs // The 'obj' arguments in obj.M(...) and obj.M, if any
+ m // The range of the object argument or whole application. We immediately union this with the range of the arguments
+ mItem // The range of the item that resolved to the method name
+ methodName // string, name of the method
+ ad // accessibility rights of the caller
+ mut // what do we know/assume about whether this method will mutate or not?
+ isProp // is this a property call? Used for better error messages and passed to BuildMethodCall
+ meths // the set of methods we may be calling
+ afterResolution // do we need to notify sink after overload resolution
+ isSuperInit // is this a special invocation, e.g. a super-class constructor call. Passed through to BuildMethodCall
+ args // the _syntactic_ method arguments, not yet type checked.
+ atomicFlag // is the expression atomic or not?
+ delayed // further lookups and applications that follow this
+ =
+
+ // Nb. args is always of List.length <= 1 except for indexed setters, when it is 2
+ let mWholeExpr = (m, args) ||> List.fold (fun m arg -> unionRanges m arg.Range)
+
+ // Work out if we know anything about the return type of the overall expression. If there are any delayed
+ // lookups then we don't know anything.
+ let exprTy = if isNil delayed then overallTy else NewInferenceType ()
+
+ // Call the helper below to do the real checking
+ let (expr, attributeAssignedNamedItems, delayed), tpenv =
+ TcMethodApplication false cenv env tpenv callerTyArgs objArgs mWholeExpr mItem methodName objTyOpt ad mut isProp meths afterResolution isSuperInit args exprTy delayed
+
+ // Give errors if some things couldn't be assigned
+ if not (isNil attributeAssignedNamedItems) then
+ let (CallerNamedArg(id, _)) = List.head attributeAssignedNamedItems
+ errorR(Error(FSComp.SR.tcNamedArgumentDidNotMatch(id.idText), id.idRange))
+
+
+ // Resolve the "delayed" lookups
+ let exprty = (tyOfExpr cenv.g expr)
+
+ PropagateThenTcDelayed cenv overallTy env tpenv mWholeExpr (MakeApplicableExprNoFlex cenv expr) exprty atomicFlag delayed
+
+/// Infer initial type information at the callsite from the syntax of an argument, prior to overload resolution.
+and GetNewInferenceTypeForMethodArg cenv env tpenv x =
+ match x with
+ | SynExprParen(a, _, _, _) -> GetNewInferenceTypeForMethodArg cenv env tpenv a
+ | SynExpr.AddressOf (true, a, _, m) -> mkByrefTyWithInference cenv.g (GetNewInferenceTypeForMethodArg cenv env tpenv a) (NewByRefKindInferenceType cenv.g m)
+ | SynExpr.Lambda (_, _, _, a, _, _) -> mkFunTy (NewInferenceType ()) (GetNewInferenceTypeForMethodArg cenv env tpenv a)
+ | SynExpr.Quote (_, raw, a, _, _) ->
+ if raw then mkRawQuotedExprTy cenv.g
+ else mkQuotedExprTy cenv.g (GetNewInferenceTypeForMethodArg cenv env tpenv a)
+ | _ -> NewInferenceType ()
+
+/// Method calls, property lookups, attribute constructions etc. get checked through here
+and TcMethodApplication
+ isCheckingAttributeCall
+ cenv
+ env
+ tpenv
+ tyargsOpt
+ objArgs
+ mMethExpr // range of the entire method expression
+ mItem
+ methodName
+ (objTyOpt: TType option)
+ ad
+ mut
+ isProp
+ calledMethsAndProps
+ afterResolution
+ isSuperInit
+ curriedCallerArgs
+ exprTy
+ delayed
+ =
+
+ let denv = env.DisplayEnv
+
+ let isSimpleFormalArg (isParamArrayArg, _isInArg, isOutArg, optArgInfo: OptionalArgInfo, callerInfo: CallerInfo, _reflArgInfo: ReflectedArgInfo) =
+ not isParamArrayArg && not isOutArg && not optArgInfo.IsOptional && callerInfo = NoCallerInfo
+
+ let callerObjArgTys = objArgs |> List.map (tyOfExpr cenv.g)
+
+ let calledMeths = calledMethsAndProps |> List.map fst
+
+ // Uses of curried members are ALWAYS treated as if they are first class uses of members.
+ // Curried members may not be overloaded (checked at use-site for curried members brought into scope through extension members)
+ let curriedCallerArgs, exprTy, delayed =
+ match calledMeths with
+ | [calledMeth] when not isProp && calledMeth.NumArgs.Length > 1 ->
+ [], NewInferenceType (), [ for x in curriedCallerArgs -> DelayedApp(ExprAtomicFlag.NonAtomic, x, x.Range) ] @ delayed
+ | _ when not isProp && calledMeths |> List.exists (fun calledMeth -> calledMeth.NumArgs.Length > 1) ->
+ // This condition should only apply when multiple conflicting curried extension members are brought into scope
+ error(Error(FSComp.SR.tcOverloadsCannotHaveCurriedArguments(), mMethExpr))
+ | _ ->
+ curriedCallerArgs, exprTy, delayed
+
+ let candidateMethsAndProps =
+ match calledMethsAndProps |> List.filter (fun (meth, _prop) -> IsMethInfoAccessible cenv.amap mItem ad meth) with
+ | [] -> calledMethsAndProps
+ | accessibleMeths -> accessibleMeths
+
+ let candidates = candidateMethsAndProps |> List.map fst
+
+
+ // Split the syntactic arguments (if any) into named and unnamed parameters
+ //
+ // In one case (the second "single named item" rule) we delay the application of a
+ // argument until we've produced a lambda that detuples an input tuple
+ let curriedCallerArgsOpt, unnamedDelayedCallerArgExprOpt, exprTy =
+ match curriedCallerArgs with
+ | [] ->
+ None, None, exprTy
+ | _ ->
+ let unnamedCurriedCallerArgs, namedCurriedCallerArgs = curriedCallerArgs |> List.map GetMethodArgs |> List.unzip
+
+ // There is an mismatch when _uses_ of indexed property setters in the tc.fs code that calls this function.
+ // The arguments are passed as if they are curried with arity [numberOfIndexParameters;1], however in the TAST, indexed property setters
+ // are uncurried and have arity [numberOfIndexParameters+1].
+ //
+ // Here we work around this mismatch by crunching all property argument lists to uncurried form.
+ // Ideally the problem needs to be solved at its root cause at the callsites to this function
+ let unnamedCurriedCallerArgs, namedCurriedCallerArgs =
+ if isProp then
+ [List.concat unnamedCurriedCallerArgs], [List.concat namedCurriedCallerArgs]
+ else
+ unnamedCurriedCallerArgs, namedCurriedCallerArgs
+
+ let MakeUnnamedCallerArgInfo x = (x, GetNewInferenceTypeForMethodArg cenv env tpenv x, x.Range)
+
+ // "single named item" rule. This is where we have a single accessible method
+ // member x.M(arg1)
+ // being used with
+ // x.M (x, y)
+ // Without this rule this requires
+ // x.M ((x, y))
+ match candidates with
+ | [calledMeth]
+ when (namedCurriedCallerArgs |> List.forall isNil &&
+ let curriedCalledArgs = calledMeth.GetParamAttribs(cenv.amap, mItem)
+ curriedCalledArgs.Length = 1 &&
+ curriedCalledArgs.Head.Length = 1 &&
+ curriedCalledArgs.Head.Head |> isSimpleFormalArg) ->
+ let unnamedCurriedCallerArgs = curriedCallerArgs |> List.map (MakeUnnamedCallerArgInfo >> List.singleton)
+ let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.map (fun _ -> [])
+ (Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), None, exprTy)
+
+ // "single named item" rule. This is where we have a single accessible method
+ // member x.M(arg1, arg2)
+ // being used with
+ // x.M p
+ // We typecheck this as if it has been written "(fun (v1, v2) -> x.M(v1, v2)) p"
+ // Without this rule this requires
+ // x.M (fst p, snd p)
+ | [calledMeth]
+ when (namedCurriedCallerArgs |> List.forall isNil &&
+ unnamedCurriedCallerArgs.Length = 1 &&
+ unnamedCurriedCallerArgs.Head.Length = 1 &&
+ let curriedCalledArgs = calledMeth.GetParamAttribs(cenv.amap, mItem)
+ curriedCalledArgs.Length = 1 &&
+ curriedCalledArgs.Head.Length > 1 &&
+ curriedCalledArgs.Head |> List.forall isSimpleFormalArg) ->
+
+ // The call lambda has function type
+ let exprTy = mkFunTy (NewInferenceType ()) exprTy
+
+ (None, Some unnamedCurriedCallerArgs.Head.Head, exprTy)
+
+ | _ ->
+ let unnamedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.mapSquared MakeUnnamedCallerArgInfo
+ let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.mapSquared (fun (isOpt, nm, x) ->
+ let ty = GetNewInferenceTypeForMethodArg cenv env tpenv x
+ // #435263: compiler crash with .net optional parameters and F# optional syntax
+ // named optional arguments should always have option type
+ // STRUCT OPTIONS: if we allow struct options as optional arguments then we should relax this and rely
+ // on later inference to work out if this is a struct option or ref option
+ let ty = if isOpt then mkOptionTy denv.g ty else ty
+ nm, isOpt, x, ty, x.Range)
+
+ (Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), None, exprTy)
+
+ let CalledMethHasSingleArgumentGroupOfThisLength n (calledMeth: MethInfo) =
+ let curriedMethodArgAttribs = calledMeth.GetParamAttribs(cenv.amap, mItem)
+ curriedMethodArgAttribs.Length = 1 &&
+ curriedMethodArgAttribs.Head.Length = n
+
+ let GenerateMatchingSimpleArgumentTypes (calledMeth: MethInfo) =
+ let curriedMethodArgAttribs = calledMeth.GetParamAttribs(cenv.amap, mItem)
+ curriedMethodArgAttribs
+ |> List.map (List.filter isSimpleFormalArg >> NewInferenceTypes)
+
+ let UnifyMatchingSimpleArgumentTypes exprTy (calledMeth: MethInfo) =
+ let curriedArgTys = GenerateMatchingSimpleArgumentTypes calledMeth
+ let returnTy =
+ (exprTy, curriedArgTys) ||> List.fold (fun exprTy argTys ->
+ let domainTy, resultTy = UnifyFunctionType None cenv denv mMethExpr exprTy
+ UnifyTypes cenv env mMethExpr domainTy (mkRefTupledTy cenv.g argTys)
+ resultTy)
+ curriedArgTys, returnTy
+
+ if isProp && Option.isNone curriedCallerArgsOpt then
+ error(Error(FSComp.SR.parsIndexerPropertyRequiresAtLeastOneArgument(), mItem))
+
+ // STEP 1. UnifyUniqueOverloading. This happens BEFORE we type check the arguments.
+ // Extract what we know about the caller arguments, either type-directed if
+ // no arguments are given or else based on the syntax of the arguments.
+ let uniquelyResolved, preArgumentTypeCheckingCalledMethGroup =
+ let dummyExpr = mkSynUnit mItem
+
+ // Build the CallerArg values for the caller's arguments.
+ // Fake up some arguments if this is the use of a method as a first class function
+ let unnamedCurriedCallerArgs, namedCurriedCallerArgs, returnTy =
+
+ match curriedCallerArgsOpt, candidates with
+ // "single named item" rule. This is where we have a single accessible method
+ // member x.M(arg1, ..., argN)
+ // being used in a first-class way, i.e.
+ // x.M
+ // Because there is only one accessible method info available based on the name of the item
+ // being accessed we know the number of arguments the first class use of this
+ // method will take. Optional and out args are _not_ included, which means they will be resolved
+ // to their default values (for optionals) and be part of the return tuple (for out args).
+ | None, [calledMeth] ->
+ let curriedArgTys, returnTy = UnifyMatchingSimpleArgumentTypes exprTy calledMeth
+ let unnamedCurriedCallerArgs = curriedArgTys |> List.mapSquared (fun ty -> CallerArg(ty, mMethExpr, false, dummyExpr))
+ let namedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.map (fun _ -> [])
+ unnamedCurriedCallerArgs, namedCurriedCallerArgs, returnTy
+
+ // "type directed" rule for first-class uses of ambiguous methods.
+ // By context we know a type for the input argument. If it's a tuple
+ // this gives us the a potential number of arguments expected. Indeed even if it's a variable
+ // type we assume the number of arguments is just "1".
+ | None, _ ->
+
+ let domainTy, returnTy = UnifyFunctionType None cenv denv mMethExpr exprTy
+ let argTys = if isUnitTy cenv.g domainTy then [] else tryDestRefTupleTy cenv.g domainTy
+ // Only apply this rule if a candidate method exists with this number of arguments
+ let argTys =
+ if candidates |> List.exists (CalledMethHasSingleArgumentGroupOfThisLength argTys.Length) then
+ argTys
+ else
+ [domainTy]
+ let unnamedCurriedCallerArgs = [argTys |> List.map (fun ty -> CallerArg(ty, mMethExpr, false, dummyExpr)) ]
+ let namedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.map (fun _ -> [])
+ unnamedCurriedCallerArgs, namedCurriedCallerArgs, returnTy
+
+ | Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), _ ->
+ let unnamedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.mapSquared (fun (argExpr, argTy, mArg) -> CallerArg(argTy, mArg, false, argExpr))
+ let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.mapSquared (fun (id, isOpt, argExpr, argTy, mArg) -> CallerNamedArg(id, CallerArg(argTy, mArg, isOpt, argExpr)))
+ unnamedCurriedCallerArgs, namedCurriedCallerArgs, exprTy
+
+ let callerArgCounts = (List.sumBy List.length unnamedCurriedCallerArgs, List.sumBy List.length namedCurriedCallerArgs)
+
+ let callerArgs = { Unnamed = unnamedCurriedCallerArgs; Named = namedCurriedCallerArgs }
+
+ let makeOneCalledMeth (minfo, pinfoOpt, usesParamArrayConversion) =
+ let minst = FreshenMethInfo mItem minfo
+ let callerTyArgs =
+ match tyargsOpt with
+ | Some tyargs -> minfo.AdjustUserTypeInstForFSharpStyleIndexedExtensionMembers tyargs
+ | None -> minst
+ CalledMeth(cenv.infoReader, Some(env.NameEnv), isCheckingAttributeCall, FreshenMethInfo, mMethExpr, ad, minfo, minst, callerTyArgs, pinfoOpt, callerObjArgTys, callerArgs, usesParamArrayConversion, true, objTyOpt)
+
+ let preArgumentTypeCheckingCalledMethGroup =
+ [ for (minfo, pinfoOpt) in candidateMethsAndProps do
+ let meth = makeOneCalledMeth (minfo, pinfoOpt, true)
+ yield meth
+ if meth.UsesParamArrayConversion then
+ yield makeOneCalledMeth (minfo, pinfoOpt, false) ]
+
+ let uniquelyResolved =
+ UnifyUniqueOverloading denv cenv.css mMethExpr callerArgCounts methodName ad preArgumentTypeCheckingCalledMethGroup returnTy
+
+ uniquelyResolved, preArgumentTypeCheckingCalledMethGroup
+
+ // STEP 2. Type check arguments
+ let unnamedCurriedCallerArgs, namedCurriedCallerArgs, lambdaVars, returnTy, tpenv =
+
+ // STEP 2a. First extract what we know about the caller arguments, either type-directed if
+ // no arguments are given or else based on the syntax of the arguments.
+ match curriedCallerArgsOpt with
+ | None ->
+ let curriedArgTys, returnTy =
+ match candidates with
+ // "single named item" rule. This is where we have a single accessible method
+ // member x.M(arg1, ..., argN)
+ // being used in a first-class way, i.e.
+ // x.M
+ // Because there is only one accessible method info available based on the name of the item
+ // being accessed we know the number of arguments the first class use of this
+ // method will take. Optional and out args are _not_ included, which means they will be resolved
+ // to their default values (for optionals) and be part of the return tuple (for out args).
+ | [calledMeth] ->
+ UnifyMatchingSimpleArgumentTypes exprTy calledMeth
+ | _ ->
+ let domainTy, returnTy = UnifyFunctionType None cenv denv mMethExpr exprTy
+ let argTys = if isUnitTy cenv.g domainTy then [] else tryDestRefTupleTy cenv.g domainTy
+ // Only apply this rule if a candidate method exists with this number of arguments
+ let argTys =
+ if candidates |> List.exists (CalledMethHasSingleArgumentGroupOfThisLength argTys.Length) then
+ argTys
+ else
+ [domainTy]
+ [argTys], returnTy
+
+ let lambdaVarsAndExprs = curriedArgTys |> List.mapiSquared (fun i j ty -> mkCompGenLocal mMethExpr ("arg"+string i+string j) ty)
+ let unnamedCurriedCallerArgs = lambdaVarsAndExprs |> List.mapSquared (fun (_, e) -> CallerArg(tyOfExpr cenv.g e, e.Range, false, e))
+ let namedCurriedCallerArgs = lambdaVarsAndExprs |> List.map (fun _ -> [])
+ let lambdaVars = List.mapSquared fst lambdaVarsAndExprs
+ unnamedCurriedCallerArgs, namedCurriedCallerArgs, Some lambdaVars, returnTy, tpenv
+
+ | Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs) ->
+ // This is the case where some explicit arguments have been given.
+
+ let unnamedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.mapSquared (fun (argExpr, argTy, mArg) -> CallerArg(argTy, mArg, false, argExpr))
+ let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.mapSquared (fun (id, isOpt, argExpr, argTy, mArg) -> CallerNamedArg(id, CallerArg(argTy, mArg, isOpt, argExpr)))
+
+ // Collect the information for F# 3.1 lambda propagation rule, and apply the caller's object type to the method's object type if the rule is relevant.
+ let lambdaPropagationInfo =
+ if preArgumentTypeCheckingCalledMethGroup.Length > 1 then
+ [| for meth in preArgumentTypeCheckingCalledMethGroup do
+ match ExamineMethodForLambdaPropagation meth with
+ | Some (unnamedInfo, namedInfo) ->
+ let calledObjArgTys = meth.CalledObjArgTys mMethExpr
+ if (calledObjArgTys, callerObjArgTys) ||> Seq.forall2 (fun calledTy callerTy -> AddCxTypeMustSubsumeTypeMatchingOnlyUndoIfFailed denv cenv.css mMethExpr calledTy callerTy) then
+ yield (List.toArraySquared unnamedInfo, List.toArraySquared namedInfo)
+ | None -> () |]
+ else
+ [| |]
+
+ // Now typecheck the argument expressions
+ let unnamedCurriedCallerArgs, (lambdaPropagationInfo, tpenv) = TcUnnamedMethodArgs cenv env lambdaPropagationInfo tpenv unnamedCurriedCallerArgs
+ let namedCurriedCallerArgs, (_, tpenv) = TcMethodNamedArgs cenv env lambdaPropagationInfo tpenv namedCurriedCallerArgs
+ unnamedCurriedCallerArgs, namedCurriedCallerArgs, None, exprTy, tpenv
+
+ let preArgumentTypeCheckingCalledMethGroup =
+ preArgumentTypeCheckingCalledMethGroup |> List.map (fun cmeth -> (cmeth.Method, cmeth.CalledTyArgs, cmeth.AssociatedPropertyInfo, cmeth.UsesParamArrayConversion))
+
+ let uniquelyResolved =
+ match uniquelyResolved with
+ | ErrorResult _ ->
+ match afterResolution with
+ | AfterResolution.DoNothing -> ()
+ | AfterResolution.RecordResolution(_, _, _, onFailure) -> onFailure()
+ | _ -> ()
+
+ uniquelyResolved |> CommitOperationResult
+
+ // STEP 3. Resolve overloading
+ /// Select the called method that's the result of overload resolution
+ let finalCalledMeth =
+
+ let callerArgs = { Unnamed = unnamedCurriedCallerArgs ; Named = namedCurriedCallerArgs }
+
+ let postArgumentTypeCheckingCalledMethGroup =
+ preArgumentTypeCheckingCalledMethGroup |> List.map (fun (minfo: MethInfo, minst, pinfoOpt, usesParamArrayConversion) ->
+ let callerTyArgs =
+ match tyargsOpt with
+ | Some tyargs -> minfo.AdjustUserTypeInstForFSharpStyleIndexedExtensionMembers tyargs
+ | None -> minst
+ CalledMeth(cenv.infoReader, Some(env.NameEnv), isCheckingAttributeCall, FreshenMethInfo, mMethExpr, ad, minfo, minst, callerTyArgs, pinfoOpt, callerObjArgTys, callerArgs, usesParamArrayConversion, true, objTyOpt))
+
+ // Commit unassociated constraints prior to member overload resolution where there is ambiguity
+ // about the possible target of the call.
+ if not uniquelyResolved then
+ ConstraintSolver.CanonicalizePartialInferenceProblem cenv.css denv mItem
+ (//freeInTypeLeftToRight cenv.g false returnTy @
+ (unnamedCurriedCallerArgs |> List.collectSquared (fun callerArg -> freeInTypeLeftToRight cenv.g false callerArg.CallerArgumentType)))
+
+ let result, errors = ResolveOverloadingForCall denv cenv.css mMethExpr methodName 0 None callerArgs ad postArgumentTypeCheckingCalledMethGroup true (Some returnTy)
+
+ match afterResolution, result with
+ | AfterResolution.DoNothing, _ -> ()
+
+ // Record the precise override resolution
+ | AfterResolution.RecordResolution(Some unrefinedItem, _, callSink, _), Some result
+ when result.Method.IsVirtual ->
+
+ let overriding =
+ match unrefinedItem with
+ | Item.MethodGroup(_, overridenMeths, _) -> overridenMeths |> List.map (fun minfo -> minfo, None)
+ | Item.Property(_, pinfos) ->
+ if result.Method.LogicalName.StartsWithOrdinal("set_") then
+ SettersOfPropInfos pinfos
+ else
+ GettersOfPropInfos pinfos
+ | _ -> []
+
+ let overridingInfo =
+ overriding
+ |> List.tryFind (fun (minfo, _) -> minfo.IsVirtual && MethInfosEquivByNameAndSig EraseNone true cenv.g cenv.amap range0 result.Method minfo)
+
+ match overridingInfo with
+ | Some (minfo, pinfoOpt) ->
+ let tps = minfo.FormalMethodTypars
+ let tyargs = result.CalledTyArgs
+ let tpinst = if tps.Length = tyargs.Length then mkTyparInst tps tyargs else []
+ (minfo, pinfoOpt, tpinst) |> callSink
+ | None ->
+ (result.Method, result.AssociatedPropertyInfo, result.CalledTyparInst) |> callSink
+
+ // Record the precise overload resolution and the type instantiation
+ | AfterResolution.RecordResolution(_, _, callSink, _), Some result ->
+ (result.Method, result.AssociatedPropertyInfo, result.CalledTyparInst) |> callSink
+
+ | AfterResolution.RecordResolution(_, _, _, onFailure), None ->
+ onFailure()
+
+
+ // Raise the errors from the constraint solving
+ RaiseOperationResult errors
+ match result with
+ | None -> error(InternalError("at least one error should be returned by failed method overloading", mItem))
+ | Some res -> res
+
+ let finalCalledMethInfo = finalCalledMeth.Method
+ let finalCalledMethInst = finalCalledMeth.CalledTyArgs
+ let finalAssignedItemSetters = finalCalledMeth.AssignedItemSetters
+ let finalAttributeAssignedNamedItems = finalCalledMeth.AttributeAssignedNamedArgs
+
+ // STEP 4. Check the attributes on the method and the corresponding event/property, if any
+
+ finalCalledMeth.AssociatedPropertyInfo |> Option.iter (fun pinfo -> CheckPropInfoAttributes pinfo mItem |> CommitOperationResult)
+
+ let isInstance = not (isNil objArgs)
+ MethInfoChecks cenv.g cenv.amap isInstance tyargsOpt objArgs ad mItem finalCalledMethInfo
+
+ // Adhoc constraints on use of .NET methods
+ begin
+ // Uses of Object.GetHashCode and Object.Equals imply an equality constraint on the object argument
+ //
+ if (isInstance &&
+ finalCalledMethInfo.IsInstance &&
+ typeEquiv cenv.g finalCalledMethInfo.ApparentEnclosingType cenv.g.obj_ty &&
+ (finalCalledMethInfo.LogicalName = "GetHashCode" || finalCalledMethInfo.LogicalName = "Equals")) then
+
+ objArgs |> List.iter (fun expr -> ConstraintSolver.AddCxTypeMustSupportEquality env.DisplayEnv cenv.css mMethExpr NoTrace (tyOfExpr cenv.g expr))
+
+ // Uses of a Dictionary() constructor without an IEqualityComparer argument imply an equality constraint
+ // on the first type argument.
+ if HasHeadType cenv.g cenv.g.tcref_System_Collections_Generic_Dictionary finalCalledMethInfo.ApparentEnclosingType &&
+ finalCalledMethInfo.IsConstructor &&
+ not (finalCalledMethInfo.GetParamDatas(cenv.amap, mItem, finalCalledMeth.CalledTyArgs)
+ |> List.existsSquared (fun (ParamData(_, _, _, _, _, _, _, ty)) ->
+ HasHeadType cenv.g cenv.g.tcref_System_Collections_Generic_IEqualityComparer ty)) then
+
+ match argsOfAppTy cenv.g finalCalledMethInfo.ApparentEnclosingType with
+ | [dty; _] -> ConstraintSolver.AddCxTypeMustSupportEquality env.DisplayEnv cenv.css mMethExpr NoTrace dty
+ | _ -> ()
+ end
+
+ if (finalCalledMeth.ArgSets |> List.existsi (fun i argSet -> argSet.UnnamedCalledArgs |> List.existsi (fun j ca -> ca.Position <> (i, j)))) then
+ errorR(Deprecated(FSComp.SR.tcUnnamedArgumentsDoNotFormPrefix(), mMethExpr))
+
+ /// STEP 5. Build the argument list. Adjust for optional arguments, byref arguments and coercions.
+
+ let objArgPreBinder, objArgs, allArgsPreBinders, allArgs, allArgsCoerced, optArgPreBinder, paramArrayPreBinders, outArgExprs, outArgTmpBinds =
+ AdjustCallerArgs TcFieldInit env.eCallerMemberName cenv.infoReader ad finalCalledMeth objArgs lambdaVars mItem mMethExpr
+
+ // Record the resolution of the named argument for the Language Service
+ allArgs |> List.iter (fun assignedArg ->
+ match assignedArg.NamedArgIdOpt with
+ | None -> ()
+ | Some id ->
+ let item = Item.ArgName (defaultArg assignedArg.CalledArg.NameOpt id, assignedArg.CalledArg.CalledArgumentType, Some(ArgumentContainer.Method finalCalledMethInfo))
+ CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, ad))
+
+
+ /// STEP 6. Build the call expression, then adjust for byref-returns, out-parameters-as-tuples, post-hoc property assignments, methods-as-first-class-value,
+ ///
+
+ let callExpr0, exprty =
+ BuildPossiblyConditionalMethodCall cenv env mut mMethExpr isProp finalCalledMethInfo isSuperInit finalCalledMethInst objArgs allArgsCoerced
+
+ // Handle byref returns
+ let callExpr1 =
+ // byref-typed returns get implicitly dereferenced
+ let vty = tyOfExpr cenv.g callExpr0
+ if isByrefTy cenv.g vty then
+ mkDerefAddrExpr mMethExpr callExpr0 mMethExpr vty
+ else
+ callExpr0
+
+ // Bind "out" parameters as part of the result tuple
+ let callExpr2, exprty =
+ let expr = callExpr1
+ if isNil outArgTmpBinds then expr, exprty
+ else
+ let outArgTys = outArgExprs |> List.map (tyOfExpr cenv.g)
+ let expr =
+ if isUnitTy cenv.g exprty then
+ mkCompGenSequential mMethExpr expr (mkRefTupled cenv.g mMethExpr outArgExprs outArgTys)
+ else
+ mkRefTupled cenv.g mMethExpr (expr :: outArgExprs) (exprty :: outArgTys)
+ let expr = mkLetsBind mMethExpr outArgTmpBinds expr
+ expr, tyOfExpr cenv.g expr
+
+ // Handle post-hoc property assignments
+ let setterExprPrebinders, callExpr3 =
+ let expr = callExpr2
+ if isCheckingAttributeCall then
+ [], expr
+ elif isNil finalAssignedItemSetters then
+ [], expr
+ else
+ // This holds the result of the call
+ let objv, objExpr = mkMutableCompGenLocal mMethExpr "returnVal" exprty // mutable in case it's a struct
+
+ // Build the expression that mutates the properties on the result of the call
+ let setterExprPrebinders, propSetExpr =
+ (mkUnit cenv.g mMethExpr, finalAssignedItemSetters) ||> List.mapFold (fun acc assignedItemSetter ->
+ let argExprPrebinder, action, m = TcSetterArgExpr cenv env denv objExpr ad assignedItemSetter
+ argExprPrebinder, mkCompGenSequential m acc action)
+
+ // now put them together
+ let expr = mkCompGenLet mMethExpr objv expr (mkCompGenSequential mMethExpr propSetExpr objExpr)
+ setterExprPrebinders, expr
+
+ // Build the lambda expression if any, if the method is used as a first-class value
+ let callExpr4 =
+ let expr = callExpr3
+ match lambdaVars with
+ | None -> expr
+ | Some curriedLambdaVars ->
+ let mkLambda vs expr =
+ match vs with
+ | [] -> mkUnitDelayLambda cenv.g mMethExpr expr
+ | _ -> mkMultiLambda mMethExpr vs (expr, tyOfExpr cenv.g expr)
+ List.foldBack mkLambda curriedLambdaVars expr
+
+ let callExpr5, tpenv =
+ let expr = callExpr4
+ match unnamedDelayedCallerArgExprOpt with
+ | Some synArgExpr ->
+ match lambdaVars with
+ | Some [lambdaVars] ->
+ let argExpr, tpenv = TcExpr cenv (mkRefTupledVarsTy cenv.g lambdaVars) env tpenv synArgExpr
+ mkApps cenv.g ((expr, tyOfExpr cenv.g expr), [], [argExpr], mMethExpr), tpenv
+ | _ ->
+ error(InternalError("unreachable - expected some lambda vars for a tuple mismatch", mItem))
+ | None ->
+ expr, tpenv
+
+ // Apply the PreBinders, if any
+ let callExpr6 =
+ let expr = callExpr5
+ let expr = (expr, setterExprPrebinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr)
+ let expr = (expr, paramArrayPreBinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr)
+ let expr = (expr, allArgsPreBinders) ||> List.fold (fun expr argPreBinder -> match argPreBinder with None -> expr | Some f -> f expr)
+
+ let expr = optArgPreBinder expr
+ let expr = objArgPreBinder expr
+ expr
+
+ (callExpr6, finalAttributeAssignedNamedItems, delayed), tpenv
+
+and TcSetterArgExpr cenv env denv objExpr ad (AssignedItemSetter(id, setter, CallerArg(callerArgTy, m, isOptCallerArg, argExpr))) =
+ if isOptCallerArg then error(Error(FSComp.SR.tcInvalidOptionalAssignmentToPropertyOrField(), m))
+
+ let argExprPrebinder, action, defnItem =
+ match setter with
+ | AssignedPropSetter (pinfo, pminfo, pminst) ->
+ MethInfoChecks cenv.g cenv.amap true None [objExpr] ad m pminfo
+ let calledArgTy = List.head (List.head (pminfo.GetParamTypes(cenv.amap, m, pminst)))
+ let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr
+ let mut = (if isStructTy cenv.g (tyOfExpr cenv.g objExpr) then DefinitelyMutates else PossiblyMutates)
+ let action = BuildPossiblyConditionalMethodCall cenv env mut m true pminfo NormalValUse pminst [objExpr] [argExpr] |> fst
+ argExprPrebinder, action, Item.Property (pinfo.PropertyName, [pinfo])
+
+ | AssignedILFieldSetter finfo ->
+ // Get or set instance IL field
+ ILFieldInstanceChecks cenv.g cenv.amap ad m finfo
+ let calledArgTy = finfo.FieldType (cenv.amap, m)
+ let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr
+ let action = BuildILFieldSet cenv.g m objExpr finfo argExpr
+ argExprPrebinder, action, Item.ILField finfo
+
+ | AssignedRecdFieldSetter rfinfo ->
+ RecdFieldInstanceChecks cenv.g cenv.amap ad m rfinfo
+ let calledArgTy = rfinfo.FieldType
+ CheckRecdFieldMutation m denv rfinfo
+ let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr
+ let action = BuildRecdFieldSet cenv.g m objExpr rfinfo argExpr
+ argExprPrebinder, action, Item.RecdField rfinfo
+
+ // Record the resolution for the Language Service
+ let item = Item.SetterArg (id, defnItem)
+ CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, ad)
+
+ argExprPrebinder, action, m
+
+and TcUnnamedMethodArgs cenv env lambdaPropagationInfo tpenv args =
+ List.mapiFoldSquared (TcUnnamedMethodArg cenv env) (lambdaPropagationInfo, tpenv) args
+
+and TcUnnamedMethodArg cenv env (lambdaPropagationInfo, tpenv) (i, j, CallerArg(argTy, mArg, isOpt, argExpr)) =
+ // Try to find the lambda propagation info for the corresponding unnamed argument at this position
+ let lambdaPropagationInfoForArg =
+ [| for (unnamedInfo, _) in lambdaPropagationInfo ->
+ if i < unnamedInfo.Length && j < unnamedInfo.[i].Length then unnamedInfo.[i].[j] else NoInfo |]
+ TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoForArg, CallerArg(argTy, mArg, isOpt, argExpr))
+
+and TcMethodNamedArgs cenv env lambdaPropagationInfo tpenv args =
+ List.mapFoldSquared (TcMethodNamedArg cenv env) (lambdaPropagationInfo, tpenv) args
+
+and TcMethodNamedArg cenv env (lambdaPropagationInfo, tpenv) (CallerNamedArg(id, arg)) =
+ // Try to find the lambda propagation info for the corresponding named argument
+ let lambdaPropagationInfoForArg =
+ [| for (_, namedInfo) in lambdaPropagationInfo ->
+ namedInfo |> Array.tryPick (fun namedInfoForArgSet ->
+ namedInfoForArgSet |> Array.tryPick (fun (nm, info) ->
+ if nm.idText = id.idText then Some info else None)) |]
+ |> Array.map (fun x -> defaultArg x NoInfo)
+
+ let arg', (lambdaPropagationInfo, tpenv) = TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoForArg, arg)
+ CallerNamedArg(id, arg'), (lambdaPropagationInfo, tpenv)
+
+and TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoForArg, CallerArg(argTy, mArg, isOpt, argExpr)) =
+
+ // Apply the F# 3.1 rule for extracting information for lambdas
+ //
+ // Before we check the argument, check to see if we can propagate info from a called lambda expression into the arguments of a received lambda
+ if lambdaPropagationInfoForArg.Length > 0 then
+ let allOverloadsAreNotCalledArgMatchesForThisArg =
+ lambdaPropagationInfoForArg
+ |> Array.forall (function ArgDoesNotMatch | CallerLambdaHasArgTypes _ | NoInfo -> true | CalledArgMatchesType _ -> false)
+
+ if allOverloadsAreNotCalledArgMatchesForThisArg then
+ let overloadsWhichAreFuncAtThisPosition = lambdaPropagationInfoForArg |> Array.choose (function CallerLambdaHasArgTypes r -> Some (List.toArray r) | _ -> None)
+ if overloadsWhichAreFuncAtThisPosition.Length > 0 then
+ let minFuncArity = overloadsWhichAreFuncAtThisPosition |> Array.minBy Array.length |> Array.length
+ let prefixOfLambdaArgsForEachOverload = overloadsWhichAreFuncAtThisPosition |> Array.map (Array.take minFuncArity)
+
+ if prefixOfLambdaArgsForEachOverload.Length > 0 then
+ let numLambdaVars = prefixOfLambdaArgsForEachOverload.[0].Length
+ // Fold across the lambda var positions checking if all method overloads imply the same argument type for a lambda variable.
+ // If so, force the caller to have a function type that looks like the calledLambdaArgTy.
+ // The loop variable callerLambdaTyOpt becomes None if something failed.
+ let rec loop callerLambdaTy lambdaVarNum =
+ if lambdaVarNum < numLambdaVars then
+ let calledLambdaArgTy = prefixOfLambdaArgsForEachOverload.[0].[lambdaVarNum]
+ let allRowsGiveSameArgumentType =
+ prefixOfLambdaArgsForEachOverload
+ |> Array.forall (fun row -> typeEquiv cenv.g calledLambdaArgTy row.[lambdaVarNum])
+
+ if allRowsGiveSameArgumentType then
+ // Force the caller to be a function type.
+ match UnifyFunctionTypeUndoIfFailed cenv env.DisplayEnv mArg callerLambdaTy with
+ | ValueSome (callerLambdaDomainTy, callerLambdaRangeTy) ->
+ if AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css mArg calledLambdaArgTy callerLambdaDomainTy then
+ loop callerLambdaRangeTy (lambdaVarNum + 1)
+ | _ -> ()
+ loop argTy 0
+
+ let e', tpenv = TcExpr cenv argTy env tpenv argExpr
+
+ // After we have checked, propagate the info from argument into the overloads that receive it.
+ //
+ // Filter out methods where an argument doesn't match. This just filters them from lambda propagation but not from
+ // later method overload resolution.
+ let lambdaPropagationInfo =
+ [| for (info, argInfo) in Array.zip lambdaPropagationInfo lambdaPropagationInfoForArg do
+ match argInfo with
+ | ArgDoesNotMatch _ -> ()
+ | NoInfo | CallerLambdaHasArgTypes _ ->
+ yield info
+ | CalledArgMatchesType adjustedCalledTy ->
+ if AddCxTypeMustSubsumeTypeMatchingOnlyUndoIfFailed env.DisplayEnv cenv.css mArg adjustedCalledTy argTy then
+ yield info |]
+
+ CallerArg(argTy, mArg, isOpt, e'), (lambdaPropagationInfo, tpenv)
+
+/// Typecheck "new Delegate(fun x y z -> ...)" constructs
+and TcNewDelegateThen cenv overallTy env tpenv mDelTy mExprAndArg delegateTy arg atomicFlag delayed =
+ let ad = env.eAccessRights
+ UnifyTypes cenv env mExprAndArg overallTy delegateTy
+ let (SigOfFunctionForDelegate(invokeMethInfo, delArgTys, _, fty)) = GetSigOfFunctionForDelegate cenv.infoReader delegateTy mDelTy ad
+ // We pass isInstance = true here because we're checking the rights to access the "Invoke" method
+ MethInfoChecks cenv.g cenv.amap true None [] env.eAccessRights mExprAndArg invokeMethInfo
+ let args = GetMethodArgs arg
+ match args with
+ | [farg], [] ->
+ let m = arg.Range
+ let callerArg, (_, tpenv) = TcMethodArg cenv env (Array.empty, tpenv) (Array.empty, CallerArg(fty, m, false, farg))
+ let expr = BuildNewDelegateExpr (None, cenv.g, cenv.amap, delegateTy, invokeMethInfo, delArgTys, callerArg.Expr, fty, m)
+ PropagateThenTcDelayed cenv overallTy env tpenv m (MakeApplicableExprNoFlex cenv expr) delegateTy atomicFlag delayed
+ | _ ->
+ error(Error(FSComp.SR.tcDelegateConstructorMustBePassed(), mExprAndArg))
+
+
+and bindLetRec (binds: Bindings) m e =
+ if isNil binds then
+ e
+ else
+ Expr.LetRec (binds, e, m, Construct.NewFreeVarsCache())
+
+/// Check for duplicate bindings in simple recursive patterns
+and CheckRecursiveBindingIds binds =
+ let hashOfBinds = new HashSet()
+
+ for (SynBinding.Binding(_, _, _, _, _, _, _, b, _, _, m, _)) in binds do
+ let nm =
+ match b with
+ | SynPat.Named(_, id, _, _, _) -> id.idText
+ | SynPat.LongIdent(LongIdentWithDots([id], _), _, _, _, _, _) -> id.idText
+ | _ -> ""
+ if nm <> "" && not (hashOfBinds.Add nm) then
+ error(Duplicate("value", nm, m))
+
+/// Process a sequence of sequentials mixed with iterated lets "let ... in let ... in ..." in a tail recursive way
+/// This avoids stack overflow on really large "let" and "letrec" lists
+and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr expr cont =
+ match expr with
+ | SynExpr.Sequential (sp, true, e1, e2, m) when not isCompExpr ->
+ let e1', _ = TcStmtThatCantBeCtorBody cenv env tpenv e1
+ // tailcall
+ let env = ShrinkContext env m e2.Range
+ // tailcall
+ TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr e2 (fun (e2', tpenv) ->
+ cont (Expr.Sequential (e1', e2', NormalSeq, sp, m), tpenv))
+
+ | SynExpr.LetOrUse (isRec, isUse, binds, body, m) when not (isUse && isCompExpr) ->
+ if isRec then
+ // TcLinearExprs processes at most one recursive binding, this is not tailcalling
+ CheckRecursiveBindingIds binds
+ let binds = List.map (fun x -> RecDefnBindingInfo(ExprContainerInfo, NoNewSlots, ExpressionBinding, x)) binds
+ if isUse then errorR(Error(FSComp.SR.tcBindingCannotBeUseAndRec(), m))
+ let binds, envinner, tpenv = TcLetrec ErrorOnOverrides cenv env tpenv (binds, m, m)
+ let bodyExpr, tpenv = bodyChecker overallTy envinner tpenv body
+ let bodyExpr = bindLetRec binds m bodyExpr
+ cont (bodyExpr, tpenv)
+ else
+ // TcLinearExprs processes multiple 'let' bindings in a tail recursive way
+ let mkf, envinner, tpenv = TcLetBinding cenv isUse env ExprContainerInfo ExpressionBinding tpenv (binds, m, body.Range)
+ let envinner = ShrinkContext envinner m body.Range
+ // tailcall
+ TcLinearExprs bodyChecker cenv envinner overallTy tpenv isCompExpr body (fun (x, tpenv) ->
+ cont (fst (mkf (x, overallTy)), tpenv))
+
+ | SynExpr.IfThenElse (synBoolExpr, synThenExpr, synElseExprOpt, spIfToThen, isRecovery, mIfToThen, m) when not isCompExpr ->
+ let boolExpr, tpenv = TcExprThatCantBeCtorBody cenv cenv.g.bool_ty env tpenv synBoolExpr
+ let thenExpr, tpenv =
+ let env =
+ match env.eContextInfo with
+ | ContextInfo.ElseBranchResult _ -> { env with eContextInfo = ContextInfo.ElseBranchResult synThenExpr.Range }
+ | _ ->
+ match synElseExprOpt with
+ | None -> { env with eContextInfo = ContextInfo.OmittedElseBranch synThenExpr.Range }
+ | _ -> { env with eContextInfo = ContextInfo.IfExpression synThenExpr.Range }
+
+ if not isRecovery && Option.isNone synElseExprOpt then
+ UnifyTypes cenv env m cenv.g.unit_ty overallTy
+
+ TcExprThatCanBeCtorBody cenv overallTy env tpenv synThenExpr
+
+ match synElseExprOpt with
+ | None ->
+ let elseExpr = mkUnit cenv.g mIfToThen
+ let spElse = DebugPointForTarget.No // the fake 'unit' value gets exactly the same range as spIfToThen
+ let overallExpr = primMkCond spIfToThen DebugPointForTarget.Yes spElse m overallTy boolExpr thenExpr elseExpr
+ cont (overallExpr, tpenv)
+
+ | Some synElseExpr ->
+ let env = { env with eContextInfo = ContextInfo.ElseBranchResult synElseExpr.Range }
+ // tailcall
+ TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr synElseExpr (fun (elseExpr, tpenv) ->
+ let resExpr = primMkCond spIfToThen DebugPointForTarget.Yes DebugPointForTarget.Yes m overallTy boolExpr thenExpr elseExpr
+ cont (resExpr, tpenv))
+
+ | _ ->
+ cont (bodyChecker overallTy env tpenv expr)
+
+/// Typecheck and compile pattern-matching constructs
+and TcAndPatternCompileMatchClauses mExpr matchm actionOnFailure cenv inputExprOpt inputTy resultTy env tpenv synClauses =
+ let clauses, tpenv = TcMatchClauses cenv inputTy resultTy env tpenv synClauses
+ let matchVal, expr = CompilePatternForMatchClauses cenv env mExpr matchm true actionOnFailure inputExprOpt inputTy resultTy clauses
+ matchVal, expr, tpenv
+
+and TcMatchPattern cenv inputTy env tpenv (pat: SynPat, optWhenExpr: SynExpr option) =
+ let m = pat.Range
+ let patf', (tpenv, names, _) = TcPat WarnOnUpperCase cenv env None (ValInline.Optional, permitInferTypars, noArgOrRetAttribs, false, None, false) (tpenv, Map.empty, Set.empty) inputTy pat
+ let envinner, values, vspecMap = MakeAndPublishSimpleValsForMergedScope cenv env m names
+ let optWhenExpr', tpenv =
+ match optWhenExpr with
+ | Some whenExpr ->
+ let guardEnv = { envinner with eContextInfo = ContextInfo.PatternMatchGuard whenExpr.Range }
+ let whenExpr', tpenv = TcExpr cenv cenv.g.bool_ty guardEnv tpenv whenExpr
+ Some whenExpr', tpenv
+ | None -> None, tpenv
+ patf' (TcPatPhase2Input (values, true)), optWhenExpr', NameMap.range vspecMap, envinner, tpenv
+
+and TcMatchClauses cenv inputTy resultTy env tpenv clauses =
+ let mutable first = true
+ let isFirst() = if first then first <- false; true else false
+ List.mapFold (fun clause -> TcMatchClause cenv inputTy resultTy env (isFirst()) clause) tpenv clauses
+
+and TcMatchClause cenv inputTy resultTy env isFirst tpenv (Clause(pat, optWhenExpr, e, patm, spTgt)) =
+ let pat', optWhenExpr', vspecs, envinner, tpenv = TcMatchPattern cenv inputTy env tpenv (pat, optWhenExpr)
+ let resultEnv = if isFirst then envinner else { envinner with eContextInfo = ContextInfo.FollowingPatternMatchClause e.Range }
+ let e', tpenv = TcExprThatCanBeCtorBody cenv resultTy resultEnv tpenv e
+ TClause(pat', optWhenExpr', TTarget(vspecs, e', spTgt), patm), tpenv
+
+and TcStaticOptimizationConstraint cenv env tpenv c =
+ match c with
+ | WhenTyparTyconEqualsTycon(tp, ty, m) ->
+ if not cenv.g.compilingFslib then
+ errorR(Error(FSComp.SR.tcStaticOptimizationConditionalsOnlyForFSharpLibrary(), m))
+ let ty', tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv ty
+ let tp', tpenv = TcTypar cenv env NewTyparsOK tpenv tp
+ TTyconEqualsTycon(mkTyparTy tp', ty'), tpenv
+ | WhenTyparIsStruct(tp, m) ->
+ if not cenv.g.compilingFslib then
+ errorR(Error(FSComp.SR.tcStaticOptimizationConditionalsOnlyForFSharpLibrary(), m))
+ let tp', tpenv = TcTypar cenv env NewTyparsOK tpenv tp
+ TTyconIsStruct(mkTyparTy tp'), tpenv
+
+/// Emit a conv.i instruction
+and mkConvToNativeInt (g: TcGlobals) e m = Expr.Op (TOp.ILAsm ([ AI_conv ILBasicType.DT_I], [ g.nativeint_ty ]), [], [e], m)
+
+/// Fix up the r.h.s. of a 'use x = fixed expr'
+and TcAndBuildFixedExpr cenv env (overallPatTy, fixedExpr, overallExprTy, mBinding) =
+ warning(PossibleUnverifiableCode mBinding)
+ match overallExprTy with
+ | ty when isByrefTy cenv.g ty ->
+ let okByRef =
+ match stripExpr fixedExpr with
+ | Expr.Op (op, tyargs, args, _) ->
+ match op, tyargs, args with
+ | TOp.ValFieldGetAddr (rfref, _), _, [_] -> not rfref.Tycon.IsStructOrEnumTycon
+ | TOp.ILAsm ([ I_ldflda fspec], _), _, _ -> fspec.DeclaringType.Boxity = ILBoxity.AsObject
+ | TOp.ILAsm ([ I_ldelema _], _), _, _ -> true
+ | TOp.RefAddrGet _, _, _ -> true
+ | _ -> false
+ | _ -> false
+ if not okByRef then
+ error(Error(FSComp.SR.tcFixedNotAllowed(), mBinding))
+
+ let elemTy = destByrefTy cenv.g overallExprTy
+ UnifyTypes cenv env mBinding (mkNativePtrTy cenv.g elemTy) overallPatTy
+ mkCompGenLetIn mBinding "pinnedByref" ty fixedExpr (fun (v, ve) ->
+ v.SetIsFixed()
+ mkConvToNativeInt cenv.g ve mBinding)
+
+ | ty when isStringTy cenv.g ty ->
+ let charPtrTy = mkNativePtrTy cenv.g cenv.g.char_ty
+ UnifyTypes cenv env mBinding charPtrTy overallPatTy
+ //
+ // let ptr: nativeptr =
+ // let pinned s = str
+ // (nativeptr)s + get_OffsettoStringData()
+
+ mkCompGenLetIn mBinding "pinnedString" cenv.g.string_ty fixedExpr (fun (v, ve) ->
+ v.SetIsFixed()
+ let addrOffset = BuildOffsetToStringData cenv env mBinding
+ let stringAsNativeInt = mkConvToNativeInt cenv.g ve mBinding
+ let plusOffset = Expr.Op (TOp.ILAsm ([ AI_add ], [ cenv.g.nativeint_ty ]), [], [stringAsNativeInt; addrOffset], mBinding)
+ // check for non-null
+ mkNullTest cenv.g mBinding ve plusOffset ve)
+
+ | ty when isArray1DTy cenv.g ty ->
+ let elemTy = destArrayTy cenv.g overallExprTy
+ let elemPtrTy = mkNativePtrTy cenv.g elemTy
+ UnifyTypes cenv env mBinding elemPtrTy overallPatTy
+
+ // let ptr: nativeptr =
+ // let tmpArray: elem[] = arr
+ // if nonNull tmpArray then
+ // if tmpArray.Length <> 0 then
+ // let pinned tmpArrayByref: byref = &arr.[0]
+ // (nativeint) tmpArrayByref
+ // else
+ // (nativeint) 0
+ // else
+ // (nativeint) 0
+ //
+ mkCompGenLetIn mBinding "tmpArray" overallExprTy fixedExpr (fun (_, ve) ->
+ // This is &arr.[0]
+ let elemZeroAddress = mkArrayElemAddress cenv.g (false, ILReadonly.NormalAddress, false, ILArrayShape.SingleDimensional, elemTy, [ve; mkInt32 cenv.g mBinding 0], mBinding)
+ // check for non-null and non-empty
+ let zero = mkConvToNativeInt cenv.g (mkInt32 cenv.g mBinding 0) mBinding
+ // This is arr.Length
+ let arrayLengthExpr = mkCallArrayLength cenv.g mBinding elemTy ve
+ mkNullTest cenv.g mBinding ve
+ (mkNullTest cenv.g mBinding arrayLengthExpr
+ (mkCompGenLetIn mBinding "pinnedByref" (mkByrefTy cenv.g elemTy) elemZeroAddress (fun (v, ve) ->
+ v.SetIsFixed()
+ (mkConvToNativeInt cenv.g ve mBinding)))
+ zero)
+ zero)
+
+ | _ -> error(Error(FSComp.SR.tcFixedNotAllowed(), mBinding))
+
+
+/// Binding checking code, for all bindings including let bindings, let-rec bindings, member bindings and object-expression bindings and
+and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt safeInitInfo (enclosingDeclaredTypars, (ExplicitTyparInfo(_, declaredTypars, _) as explicitTyparInfo)) bind =
+ let envinner = AddDeclaredTypars NoCheckForDuplicateTypars (enclosingDeclaredTypars@declaredTypars) env
+
+ match bind with
+
+ | NormalizedBinding(vis, bkind, isInline, isMutable, attrs, doc, _, valSynData, pat, NormalizedBindingRhs(spatsL, rtyOpt, rhsExpr), mBinding, spBind) ->
+ let (SynValData(memberFlagsOpt, valSynInfo, _)) = valSynData
+
+ let callerName =
+ match declKind, bkind, pat with
+ | ExpressionBinding, _, _ -> envinner.eCallerMemberName
+ | _, _, SynPat.Named(_, name, _, _, _) ->
+ match memberFlagsOpt with
+ | Some memberFlags ->
+ match memberFlags.MemberKind with
+ | MemberKind.PropertyGet | MemberKind.PropertySet | MemberKind.PropertyGetSet -> Some(name.idText.Substring 4)
+ | MemberKind.ClassConstructor -> Some(".ctor")
+ | MemberKind.Constructor -> Some(".ctor")
+ | _ -> Some(name.idText)
+ | _ -> Some(name.idText)
+ | ClassLetBinding false, DoBinding, _ -> Some(".ctor")
+ | ClassLetBinding true, DoBinding, _ -> Some(".cctor")
+ | ModuleOrMemberBinding, StandaloneExpression, _ -> Some(".cctor")
+ | _, _, _ -> envinner.eCallerMemberName
+
+ let envinner = {envinner with eCallerMemberName = callerName }
+
+ let attrTgt = DeclKind.AllowedAttribTargets memberFlagsOpt declKind
+
+ let isFixed, rhsExpr, overallPatTy, overallExprTy =
+ match rhsExpr with
+ | SynExpr.Fixed (e, _) -> true, e, NewInferenceType(), overallTy
+ | e -> false, e, overallTy, overallTy
+
+ // Check the attributes of the binding, parameters or return value
+ let TcAttrs tgt attrs =
+ let attrs = TcAttributes cenv envinner tgt attrs
+ if attrTgt = enum 0 && not (isNil attrs) then
+ errorR(Error(FSComp.SR.tcAttributesAreNotPermittedOnLetBindings(), mBinding))
+ attrs
+
+ let valAttribs = TcAttrs attrTgt attrs
+ let isVolatile = HasFSharpAttribute cenv.g cenv.g.attrib_VolatileFieldAttribute valAttribs
+
+ let inlineFlag = ComputeInlineFlag memberFlagsOpt isInline isMutable mBinding
+
+ let argAttribs =
+ spatsL |> List.map (SynInfo.InferSynArgInfoFromSimplePats >> List.map (SynInfo.AttribsOfArgData >> TcAttrs AttributeTargets.Parameter))
+ let retAttribs =
+ match rtyOpt with
+ | Some (SynBindingReturnInfo(_, _, Attributes retAttrs)) -> TcAttrs AttributeTargets.ReturnValue retAttrs
+ | None -> []
+
+ let argAndRetAttribs = ArgAndRetAttribs(argAttribs, retAttribs)
+
+ if HasFSharpAttribute cenv.g cenv.g.attrib_DefaultValueAttribute valAttribs then
+ errorR(Error(FSComp.SR.tcDefaultValueAttributeRequiresVal(), mBinding))
+
+ let isThreadStatic = isThreadOrContextStatic cenv.g valAttribs
+ if isThreadStatic then errorR(DeprecatedThreadStaticBindingWarning mBinding)
+
+ if isVolatile then
+ match declKind with
+ | ClassLetBinding(_) -> ()
+ | _ -> errorR(Error(FSComp.SR.tcVolatileOnlyOnClassLetBindings(), mBinding))
+
+ if (not isMutable || isThreadStatic) then
+ errorR(Error(FSComp.SR.tcVolatileFieldsMustBeMutable(), mBinding))
+
+ if isFixed && (declKind <> ExpressionBinding || isInline || isMutable) then
+ errorR(Error(FSComp.SR.tcFixedNotAllowed(), mBinding))
+
+ if (not declKind.CanBeDllImport || (match memberFlagsOpt with Some memberFlags -> memberFlags.IsInstance | _ -> false)) &&
+ HasFSharpAttributeOpt cenv.g cenv.g.attrib_DllImportAttribute valAttribs
+ then
+ errorR(Error(FSComp.SR.tcDllImportNotAllowed(), mBinding))
+
+ if Option.isNone memberFlagsOpt && HasFSharpAttribute cenv.g cenv.g.attrib_ConditionalAttribute valAttribs then
+ errorR(Error(FSComp.SR.tcConditionalAttributeRequiresMembers(), mBinding))
+
+ if HasFSharpAttribute cenv.g cenv.g.attrib_EntryPointAttribute valAttribs then
+ if Option.isSome memberFlagsOpt then
+ errorR(Error(FSComp.SR.tcEntryPointAttributeRequiresFunctionInModule(), mBinding))
+ else
+ UnifyTypes cenv env mBinding overallPatTy (mkArrayType cenv.g cenv.g.string_ty --> cenv.g.int_ty)
+
+ if isMutable && isInline then errorR(Error(FSComp.SR.tcMutableValuesCannotBeInline(), mBinding))
+
+ if isMutable && not (isNil declaredTypars) then errorR(Error(FSComp.SR.tcMutableValuesMayNotHaveGenericParameters(), mBinding))
+
+ let explicitTyparInfo = if isMutable then dontInferTypars else explicitTyparInfo
+
+ if isMutable && not (isNil spatsL) then errorR(Error(FSComp.SR.tcMutableValuesSyntax(), mBinding))
+
+ let isInline =
+ if isInline && isNil spatsL && isNil declaredTypars then
+ errorR(Error(FSComp.SR.tcOnlyFunctionsCanBeInline(), mBinding))
+ false
+ else
+ isInline
+
+ let compgen = false
+
+ // Use the syntactic arity if we're defining a function
+ let partialValReprInfo = TranslateTopValSynInfo mBinding (TcAttributes cenv env) valSynInfo
+
+ // Check the pattern of the l.h.s. of the binding
+ let tcPatPhase2, (tpenv, nameToPrelimValSchemeMap, _) =
+ TcPat AllIdsOK cenv envinner (Some partialValReprInfo) (inlineFlag, explicitTyparInfo, argAndRetAttribs, isMutable, vis, compgen) (tpenv, NameMap.empty, Set.empty) overallPatTy pat
+
+ // Add active pattern result names to the environment
+ let apinfoOpt =
+ match NameMap.range nameToPrelimValSchemeMap with
+ | [PrelimValScheme1(id, _, ty, _, _, _, _, _, _, _, _) ] ->
+ match ActivePatternInfoOfValName id.idText id.idRange with
+ | Some apinfo -> Some (apinfo, ty, id.idRange)
+ | None -> None
+ | _ -> None
+
+ // Add active pattern result names to the environment
+ let envinner =
+ match apinfoOpt with
+ | Some (apinfo, ty, m) ->
+ if Option.isSome memberFlagsOpt || (not apinfo.IsTotal && apinfo.ActiveTags.Length > 1) then
+ error(Error(FSComp.SR.tcInvalidActivePatternName(), mBinding))
+
+ apinfo.ActiveTagsWithRanges |> List.iteri (fun i (_tag, tagRange) ->
+ let item = Item.ActivePatternResult(apinfo, cenv.g.unit_ty, i, tagRange)
+ CallNameResolutionSink cenv.tcSink (tagRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Binding, env.AccessRights))
+
+ { envinner with eNameResEnv = AddActivePatternResultTagsToNameEnv apinfo envinner.eNameResEnv ty m }
+ | None ->
+ envinner
+
+ // Now tc the r.h.s.
+ // If binding a ctor then set the ugly counter that permits us to write ctor expressions on the r.h.s.
+ let isCtor = (match memberFlagsOpt with Some memberFlags -> memberFlags.MemberKind = MemberKind.Constructor | _ -> false)
+
+ // At each module binding, dive into the expression to check for syntax errors and suppress them if they show.
+ // Don't do this for lambdas, because we always check for suppression for all lambda bodies in TcIteratedLambdas
+ let rhsExprChecked, tpenv =
+ let atTopNonLambdaDefn =
+ DeclKind.IsModuleOrMemberOrExtensionBinding declKind &&
+ (match rhsExpr with SynExpr.Lambda _ -> false | _ -> true) &&
+ synExprContainsError rhsExpr
+
+ conditionallySuppressErrorReporting atTopNonLambdaDefn (fun () ->
+
+ if isCtor then TcExprThatIsCtorBody (safeThisValOpt, safeInitInfo) cenv overallExprTy envinner tpenv rhsExpr
+ else TcExprThatCantBeCtorBody cenv overallExprTy envinner tpenv rhsExpr)
+
+ if bkind = StandaloneExpression && not cenv.isScript then
+ UnifyUnitType cenv env mBinding overallPatTy rhsExprChecked |> ignore
+
+ // Fix up the r.h.s. expression for 'fixed'
+ let rhsExprChecked =
+ if isFixed then TcAndBuildFixedExpr cenv env (overallPatTy, rhsExprChecked, overallExprTy, mBinding)
+ else rhsExprChecked
+
+ // Assert the return type of an active pattern
+ match apinfoOpt with
+ | Some (apinfo, ty, _) ->
+ let activePatResTys = NewInferenceTypes apinfo.ActiveTags
+ let _, rty = stripFunTy cenv.g ty
+ UnifyTypes cenv env mBinding (apinfo.ResultType cenv.g rhsExpr.Range activePatResTys) rty
+ | None ->
+ ()
+
+ // Check other attributes
+ let hasLiteralAttr, literalValue = TcLiteral cenv overallExprTy env tpenv (valAttribs, rhsExpr)
+
+ if hasLiteralAttr then
+ if isThreadStatic then
+ errorR(Error(FSComp.SR.tcIllegalAttributesForLiteral(), mBinding))
+ if isMutable then
+ errorR(Error(FSComp.SR.tcLiteralCannotBeMutable(), mBinding))
+ if isInline then
+ errorR(Error(FSComp.SR.tcLiteralCannotBeInline(), mBinding))
+ if not (isNil declaredTypars) then
+ errorR(Error(FSComp.SR.tcLiteralCannotHaveGenericParameters(), mBinding))
+
+ CheckedBindingInfo(inlineFlag, valAttribs, doc, tcPatPhase2, explicitTyparInfo, nameToPrelimValSchemeMap, rhsExprChecked, argAndRetAttribs, overallPatTy, mBinding, spBind, compgen, literalValue, isFixed), tpenv
+
+and TcLiteral cenv overallTy env tpenv (attrs, synLiteralValExpr) =
+ let hasLiteralAttr = HasFSharpAttribute cenv.g cenv.g.attrib_LiteralAttribute attrs
+ if hasLiteralAttr then
+ let literalValExpr, _ = TcExpr cenv overallTy env tpenv synLiteralValExpr
+ match EvalLiteralExprOrAttribArg cenv.g literalValExpr with
+ | Expr.Const (c, _, ty) ->
+ if c = Const.Zero && isStructTy cenv.g ty then
+ warning(Error(FSComp.SR.tcIllegalStructTypeForConstantExpression(), synLiteralValExpr.Range))
+ false, None
+ else
+ true, Some c
+ | _ ->
+ errorR(Error(FSComp.SR.tcInvalidConstantExpression(), synLiteralValExpr.Range))
+ true, Some Const.Unit
+
+ else hasLiteralAttr, None
+
+and TcBindingTyparDecls alwaysRigid cenv env tpenv (SynValTyparDecls(synTypars, infer, synTyparConstraints)) =
+ let declaredTypars = TcTyparDecls cenv env synTypars
+ let envinner = AddDeclaredTypars CheckForDuplicateTypars declaredTypars env
+ let tpenv = TcTyparConstraints cenv NoNewTypars CheckCxs ItemOccurence.UseInType envinner tpenv synTyparConstraints
+
+ let rigidCopyOfDeclaredTypars =
+ if alwaysRigid then
+ declaredTypars |> List.iter (fun tp -> SetTyparRigid env.DisplayEnv tp.Range tp)
+ declaredTypars
+ else
+ let rigidCopyOfDeclaredTypars = copyTypars declaredTypars
+ // The type parameters used to check rigidity after inference are marked rigid straight away
+ rigidCopyOfDeclaredTypars |> List.iter (fun tp -> SetTyparRigid env.DisplayEnv tp.Range tp)
+ // The type parameters using during inference will be marked rigid after inference
+ declaredTypars |> List.iter (fun tp -> tp.SetRigidity TyparRigidity.WillBeRigid)
+ rigidCopyOfDeclaredTypars
+
+ ExplicitTyparInfo(rigidCopyOfDeclaredTypars, declaredTypars, infer), tpenv
+
+and TcNonrecBindingTyparDecls cenv env tpenv bind =
+ let (NormalizedBinding(_, _, _, _, _, _, synTyparDecls, _, _, _, _, _)) = bind
+ TcBindingTyparDecls true cenv env tpenv synTyparDecls
+
+and TcNonRecursiveBinding declKind cenv env tpenv ty b =
+ let b = BindingNormalization.NormalizeBinding ValOrMemberBinding cenv env b
+ let explicitTyparInfo, tpenv = TcNonrecBindingTyparDecls cenv env tpenv b
+ TcNormalizedBinding declKind cenv env tpenv ty None NoSafeInitInfo ([], explicitTyparInfo) b
+
+//-------------------------------------------------------------------------
+// TcAttribute*
+//------------------------------------------------------------------------
+
+and TcAttribute canFail cenv (env: TcEnv) attrTgt (synAttr: SynAttribute) =
+ let (LongIdentWithDots(tycon, _)) = synAttr.TypeName
+ let arg = synAttr.ArgExpr
+ let targetIndicator = synAttr.Target
+ let isAppliedToGetterOrSetter = synAttr.AppliesToGetterAndSetter
+ let mAttr = synAttr.Range
+ let (typath, tyid) = List.frontAndBack tycon
+ let tpenv = emptyUnscopedTyparEnv
+
+ // if we're checking an attribute that was applied directly to a getter or a setter, then
+ // what we're really checking against is a method, not a property
+ let attrTgt = if isAppliedToGetterOrSetter then ((attrTgt ^^^ AttributeTargets.Property) ||| AttributeTargets.Method) else attrTgt
+ let ty, tpenv =
+ let try1 n =
+ let tyid = mkSynId tyid.idRange n
+ let tycon = (typath @ [tyid])
+ let ad = env.eAccessRights
+ match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.UseInAttribute OpenQualified env.eNameResEnv ad tycon TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.No with
+ | Exception err -> raze err
+ | _ -> success(TcTypeAndRecover cenv NoNewTypars CheckCxs ItemOccurence.UseInAttribute env tpenv (SynType.App(SynType.LongIdent(LongIdentWithDots(tycon, [])), None, [], [], None, false, mAttr)) )
+ ForceRaise ((try1 (tyid.idText + "Attribute")) |> ResultOrException.otherwise (fun () -> (try1 tyid.idText)))
+
+ let ad = env.eAccessRights
+
+ if not (IsTypeAccessible cenv.g cenv.amap mAttr ad ty) then errorR(Error(FSComp.SR.tcTypeIsInaccessible(), mAttr))
+
+ let tcref = tcrefOfAppTy cenv.g ty
+
+ let conditionalCallDefineOpt = TryFindTyconRefStringAttribute cenv.g mAttr cenv.g.attrib_ConditionalAttribute tcref
+
+ match conditionalCallDefineOpt, cenv.conditionalDefines with
+ | Some d, Some defines when not (List.contains d defines) ->
+ [], false
+ | _ ->
+ // REVIEW: take notice of inherited?
+ let validOn, _inherited =
+ let validOnDefault = 0x7fff
+ let inheritedDefault = true
+ if tcref.IsILTycon then
+ let tdef = tcref.ILTyconRawMetadata
+ let tref = cenv.g.attrib_AttributeUsageAttribute.TypeRef
+
+ match TryDecodeILAttribute cenv.g tref tdef.CustomAttrs with
+ | Some ([ILAttribElem.Int32 validOn ], named) ->
+ let inherited =
+ match List.tryPick (function ("Inherited", _, _, ILAttribElem.Bool res) -> Some res | _ -> None) named with
+ | None -> inheritedDefault
+ | Some x -> x
+ (validOn, inherited)
+ | Some ([ILAttribElem.Int32 validOn; ILAttribElem.Bool _allowMultiple; ILAttribElem.Bool inherited ], _) ->
+ (validOn, inherited)
+ | _ ->
+ (validOnDefault, inheritedDefault)
+ else
+ match (TryFindFSharpAttribute cenv.g cenv.g.attrib_AttributeUsageAttribute tcref.Attribs) with
+ | Some(Attrib(_, _, [ AttribInt32Arg validOn ], _, _, _, _)) ->
+ (validOn, inheritedDefault)
+ | Some(Attrib(_, _, [ AttribInt32Arg validOn
+ AttribBoolArg(_allowMultiple)
+ AttribBoolArg inherited], _, _, _, _)) ->
+ (validOn, inherited)
+ | Some _ ->
+ warning(Error(FSComp.SR.tcUnexpectedConditionInImportedAssembly(), mAttr))
+ (validOnDefault, inheritedDefault)
+ | _ ->
+ (validOnDefault, inheritedDefault)
+ let possibleTgts = enum validOn &&& attrTgt
+ let directedTgts =
+ 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
+ | _ -> possibleTgts
+ let constrainedTgts = possibleTgts &&& directedTgts
+ if constrainedTgts = enum 0 then
+ if (directedTgts = AttributeTargets.Assembly || directedTgts = AttributeTargets.Module) then
+ error(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElementUseDo(), mAttr))
+ else
+ error(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElement(), mAttr))
+
+ match ResolveObjectConstructor cenv.nameResolver env.DisplayEnv mAttr ad ty with
+ | Exception _ when canFail -> [ ], true
+ | res ->
+ let item = ForceRaise res
+ if not (ExistsHeadTypeInEntireHierarchy cenv.g cenv.amap mAttr ty cenv.g.tcref_System_Attribute) then warning(Error(FSComp.SR.tcTypeDoesNotInheritAttribute(), mAttr))
+ let attrib =
+ match item with
+ | Item.CtorGroup(methodName, minfos) ->
+ let meths = minfos |> List.map (fun minfo -> minfo, None)
+ let afterResolution = ForNewConstructors cenv.tcSink env tyid.idRange methodName minfos
+ let (expr, attributeAssignedNamedItems, _), _ =
+ TcMethodApplication true cenv env tpenv None [] mAttr mAttr methodName None ad PossiblyMutates false meths afterResolution NormalValUse [arg] (NewInferenceType ()) []
+
+ UnifyTypes cenv env mAttr ty (tyOfExpr cenv.g expr)
+
+ let mkAttribExpr e =
+ AttribExpr(e, EvalLiteralExprOrAttribArg cenv.g e)
+
+ let namedAttribArgMap =
+ attributeAssignedNamedItems |> List.map (fun (CallerNamedArg(id, CallerArg(argtyv, m, isOpt, callerArgExpr))) ->
+ if isOpt then error(Error(FSComp.SR.tcOptionalArgumentsCannotBeUsedInCustomAttribute(), m))
+ let m = callerArgExpr.Range
+ let setterItem, _ = ResolveLongIdentInType cenv.tcSink cenv.nameResolver env.NameEnv LookupKind.Expr m ad id IgnoreOverrides TypeNameResolutionInfo.Default ty
+ let nm, isProp, argty =
+ match setterItem with
+ | Item.Property (_, [pinfo]) ->
+ if not pinfo.HasSetter then
+ errorR(Error(FSComp.SR.tcPropertyCannotBeSet0(), m))
+ id.idText, true, pinfo.GetPropertyType(cenv.amap, m)
+ | Item.ILField finfo ->
+ CheckILFieldInfoAccessible cenv.g cenv.amap m ad finfo
+ CheckILFieldAttributes cenv.g finfo m
+ id.idText, false, finfo.FieldType(cenv.amap, m)
+ | Item.RecdField rfinfo when not rfinfo.IsStatic ->
+ CheckRecdFieldInfoAttributes cenv.g rfinfo m |> CommitOperationResult
+ CheckRecdFieldInfoAccessible cenv.amap m ad rfinfo
+ // This uses the F# backend name mangling of fields....
+ let nm = ComputeFieldName rfinfo.Tycon rfinfo.RecdField
+ nm, false, rfinfo.FieldType
+ | _ ->
+ errorR(Error(FSComp.SR.tcPropertyOrFieldNotFoundInAttribute(), m))
+ id.idText, false, cenv.g.unit_ty
+ let propNameItem = Item.SetterArg(id, setterItem)
+ CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, propNameItem, emptyTyparInst, ItemOccurence.Use, ad)
+
+ AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace argty argtyv
+
+ AttribNamedArg(nm, argty, isProp, mkAttribExpr callerArgExpr))
+
+ match expr with
+ | Expr.Op (TOp.ILCall (_, _, isStruct, _, _, _, _, ilMethRef, [], [], _), [], args, m) ->
+ 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)
+
+ | 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)
+
+ | _ ->
+ error (Error(FSComp.SR.tcCustomAttributeMustInvokeConstructor(), mAttr))
+
+ | _ ->
+ error(Error(FSComp.SR.tcAttributeExpressionsMustBeConstructorCalls(), mAttr))
+
+ [ (constrainedTgts, attrib) ], false
+
+and TcAttributesWithPossibleTargets canFail cenv env attrTgt synAttribs =
+
+ (false, synAttribs) ||> List.collectFold (fun didFail synAttrib ->
+ try
+ let attribsAndTargets, didFail2 = TcAttribute canFail cenv env attrTgt synAttrib
+
+ // This is where we place any checks that completely exclude the use of some particular
+ // attributes from F#.
+ let attribs = List.map snd attribsAndTargets
+ if HasFSharpAttribute cenv.g cenv.g.attrib_TypeForwardedToAttribute attribs ||
+ HasFSharpAttribute cenv.g cenv.g.attrib_CompilationArgumentCountsAttribute attribs ||
+ HasFSharpAttribute cenv.g cenv.g.attrib_CompilationMappingAttribute attribs then
+ errorR(Error(FSComp.SR.tcUnsupportedAttribute(), synAttrib.Range))
+
+ attribsAndTargets, didFail || didFail2
+
+ with e ->
+ errorRecovery e synAttrib.Range
+ [], false)
+
+and TcAttributesMaybeFail canFail cenv env attrTgt synAttribs =
+ let attribsAndTargets, didFail = TcAttributesWithPossibleTargets canFail cenv env attrTgt synAttribs
+ attribsAndTargets |> List.map snd, didFail
+
+and TcAttributesCanFail cenv env attrTgt synAttribs =
+ let attrs, didFail = TcAttributesMaybeFail true cenv env attrTgt synAttribs
+ attrs, (fun () -> if didFail then TcAttributes cenv env attrTgt synAttribs else attrs)
+
+and TcAttributes cenv env attrTgt synAttribs =
+ TcAttributesMaybeFail false cenv env attrTgt synAttribs |> fst
+
+//-------------------------------------------------------------------------
+// TcLetBinding
+//------------------------------------------------------------------------
+
+and TcLetBinding cenv isUse env containerInfo declKind tpenv (synBinds, synBindsRange, scopem) =
+
+ // Typecheck all the bindings...
+ let checkedBinds, tpenv = List.mapFold (fun tpenv b -> TcNonRecursiveBinding declKind cenv env tpenv (NewInferenceType ()) b) tpenv synBinds
+ let (ContainerInfo(altActualParent, _)) = containerInfo
+
+ // Canonicalize constraints prior to generalization
+ let denv = env.DisplayEnv
+ ConstraintSolver.CanonicalizePartialInferenceProblem cenv.css denv synBindsRange
+ (checkedBinds |> List.collect (fun tbinfo ->
+ let (CheckedBindingInfo(_, _, _, _, explicitTyparInfo, _, _, _, tauTy, _, _, _, _, _)) = tbinfo
+ let (ExplicitTyparInfo(_, declaredTypars, _)) = explicitTyparInfo
+ let maxInferredTypars = (freeInTypeLeftToRight cenv.g false tauTy)
+ declaredTypars @ maxInferredTypars))
+
+ let lazyFreeInEnv = lazy (GeneralizationHelpers.ComputeUngeneralizableTypars env)
+
+ // Generalize the bindings...
+ (((fun x -> x), env, tpenv), checkedBinds) ||> List.fold (fun (buildExpr, env, tpenv) tbinfo ->
+ let (CheckedBindingInfo(inlineFlag, attrs, doc, tcPatPhase2, explicitTyparInfo, nameToPrelimValSchemeMap, rhsExpr, _, tauTy, m, spBind, _, literalValue, isFixed)) = tbinfo
+ let enclosingDeclaredTypars = []
+ let (ExplicitTyparInfo(_, declaredTypars, canInferTypars)) = explicitTyparInfo
+ let allDeclaredTypars = enclosingDeclaredTypars @ declaredTypars
+ let generalizedTypars, prelimValSchemes2 =
+ let canInferTypars = GeneralizationHelpers. ComputeCanInferExtraGeneralizableTypars (containerInfo.ParentRef, canInferTypars, None)
+
+ let maxInferredTypars = freeInTypeLeftToRight cenv.g false tauTy
+
+ let generalizedTypars =
+ if isNil maxInferredTypars && isNil allDeclaredTypars then
+ []
+ else
+ let freeInEnv = lazyFreeInEnv.Force()
+ let canConstrain = GeneralizationHelpers.CanGeneralizeConstrainedTyparsForDecl declKind
+ GeneralizationHelpers.ComputeAndGeneralizeGenericTypars
+ (cenv, denv, m, freeInEnv, canInferTypars, canConstrain, inlineFlag, Some rhsExpr, allDeclaredTypars, maxInferredTypars, tauTy, false)
+
+ let prelimValSchemes2 = GeneralizeVals cenv denv enclosingDeclaredTypars generalizedTypars nameToPrelimValSchemeMap
+
+ generalizedTypars, prelimValSchemes2
+
+ // REVIEW: this scopes generalized type variables. Ensure this is handled properly
+ // on all other paths.
+ let tpenv = HideUnscopedTypars generalizedTypars tpenv
+ let valSchemes = NameMap.map (UseCombinedArity cenv.g declKind rhsExpr) prelimValSchemes2
+ let values = MakeAndPublishVals cenv env (altActualParent, false, declKind, ValNotInRecScope, valSchemes, attrs, doc, literalValue)
+ let checkedPat = tcPatPhase2 (TcPatPhase2Input (values, true))
+ let prelimRecValues = NameMap.map fst values
+
+ // Now bind the r.h.s. to the l.h.s.
+ let rhsExpr = mkTypeLambda m generalizedTypars (rhsExpr, tauTy)
+
+ match checkedPat with
+ // Don't introduce temporary or 'let' for 'match against wild' or 'match against unit'
+
+ | (TPat_wild _ | TPat_const (Const.Unit, _)) when not isUse && not isFixed && isNil generalizedTypars ->
+ let mkSequentialBind (tm, tmty) = (mkSequential DebugPointAtSequential.Both m rhsExpr tm, tmty)
+ (buildExpr >> mkSequentialBind, env, tpenv)
+ | _ ->
+
+ // nice: don't introduce awful temporary for r.h.s. in the 99% case where we know what we're binding it to
+ let patternInputTmp, checkedPat2 =
+ match checkedPat with
+ // nice: don't introduce awful temporary for r.h.s. in the 99% case where we know what we're binding it to
+ | TPat_as (pat, PBind(v, TypeScheme(generalizedTypars', _)), _)
+ when List.lengthsEqAndForall2 typarRefEq generalizedTypars generalizedTypars' ->
+
+ v, pat
+ //Op (LValueOp (LByrefGet,x),[],[],C:\GitHub\dsyme\visualfsharp\a.fs (15,42--15,43) IsSynthetic=false)
+
+ | _ when inlineFlag.MustInline ->
+ error(Error(FSComp.SR.tcInvalidInlineSpecification(), m))
+
+ | TPat_query _ when HasFSharpAttribute cenv.g cenv.g.attrib_LiteralAttribute attrs ->
+ error(Error(FSComp.SR.tcLiteralAttributeCannotUseActivePattern(), m))
+
+ | _ ->
+
+ let tmp, _ = mkCompGenLocal m "patternInput" (generalizedTypars +-> tauTy)
+
+ if isUse || isFixed then
+ errorR(Error(FSComp.SR.tcInvalidUseBinding(), m))
+
+ // If the overall declaration is declaring statics or a module value, then force the patternInputTmp to also
+ // have representation as module value.
+ if (DeclKind.MustHaveArity declKind) then
+ AdjustValToTopVal tmp altActualParent (InferArityOfExprBinding cenv.g AllowTypeDirectedDetupling.Yes tmp rhsExpr)
+
+ tmp, checkedPat
+
+ // Add the bind "let patternInputTmp = rhsExpr" to the bodyExpr we get from mkPatBind
+ let mkRhsBind (bodyExpr, bodyExprTy) =
+ let letExpr = mkLet spBind m patternInputTmp rhsExpr bodyExpr
+ letExpr, bodyExprTy
+
+ let allValsDefinedByPattern = NameMap.range prelimRecValues
+
+ // Add the compilation of the pattern to the bodyExpr we get from mkCleanup
+ let mkPatBind (bodyExpr, bodyExprTy) =
+ let valsDefinedByMatching = ListSet.remove valEq patternInputTmp allValsDefinedByPattern
+ let clauses = [TClause(checkedPat2, None, TTarget(valsDefinedByMatching, bodyExpr, DebugPointForTarget.No), m)]
+ let matchx = CompilePatternForMatch cenv env m m true ThrowIncompleteMatchException (patternInputTmp, generalizedTypars, Some rhsExpr) clauses tauTy bodyExprTy
+ let matchx = if (DeclKind.ConvertToLinearBindings declKind) then LinearizeTopMatch cenv.g altActualParent matchx else matchx
+ matchx, bodyExprTy
+
+ // Add the dispose of any "use x = ..." to bodyExpr
+ let mkCleanup (bodyExpr, bodyExprTy) =
+ if isUse && not isFixed then
+ (allValsDefinedByPattern, (bodyExpr, bodyExprTy)) ||> List.foldBack (fun v (bodyExpr, bodyExprTy) ->
+ AddCxTypeMustSubsumeType ContextInfo.NoContext denv cenv.css v.Range NoTrace cenv.g.system_IDisposable_ty v.Type
+ let cleanupE = BuildDisposableCleanup cenv env m v
+ mkTryFinally cenv.g (bodyExpr, cleanupE, m, bodyExprTy, DebugPointAtTry.Body, DebugPointAtFinally.No), bodyExprTy)
+ else
+ (bodyExpr, bodyExprTy)
+
+ let envInner = AddLocalValMap cenv.tcSink scopem prelimRecValues env
+
+ ((buildExpr >> mkCleanup >> mkPatBind >> mkRhsBind), envInner, tpenv))
+
+/// Return binds corresponding to the linearised let-bindings.
+/// This reveals the bound items, e.g. when the lets occur in incremental object defns.
+/// RECAP:
+/// The LHS of let-bindings are patterns.
+/// These patterns could fail, e.g. "let Some x = ...".
+/// So let bindings could contain a fork at a match construct, with one branch being the match failure.
+/// If bindings are linearised, then this fork is pushed to the RHS.
+/// In this case, the let bindings type check to a sequence of bindings.
+and TcLetBindings cenv env containerInfo declKind tpenv (binds, bindsm, scopem) =
+ assert(DeclKind.ConvertToLinearBindings declKind)
+ let mkf, env, tpenv = TcLetBinding cenv false env containerInfo declKind tpenv (binds, bindsm, scopem)
+ let unite = mkUnit cenv.g bindsm
+ let expr, _ = mkf (unite, cenv.g.unit_ty)
+ let rec stripLets acc = function
+ | Expr.Let (bind, body, m, _) -> stripLets (TMDefLet(bind, m) :: acc) body
+ | Expr.Sequential (e1, e2, NormalSeq, _, m) -> stripLets (TMDefDo(e1, m) :: acc) e2
+ | Expr.Const (Const.Unit, _, _) -> List.rev acc
+ | _ -> failwith "TcLetBindings: let sequence is non linear. Maybe a LHS pattern was not linearised?"
+ let binds = stripLets [] expr
+ binds, env, tpenv
+
+and CheckMemberFlags optIntfSlotTy newslotsOK overridesOK memberFlags m =
+ if newslotsOK = NoNewSlots && memberFlags.IsDispatchSlot then
+ errorR(Error(FSComp.SR.tcAbstractMembersIllegalInAugmentation(), m))
+ if overridesOK = ErrorOnOverrides && memberFlags.MemberKind = MemberKind.Constructor then
+ errorR(Error(FSComp.SR.tcConstructorsIllegalInAugmentation(), m))
+ if overridesOK = WarnOnOverrides && memberFlags.IsOverrideOrExplicitImpl && Option.isNone optIntfSlotTy then
+ warning(OverrideInIntrinsicAugmentation m)
+ if overridesOK = ErrorOnOverrides && memberFlags.IsOverrideOrExplicitImpl then
+ error(Error(FSComp.SR.tcMethodOverridesIllegalHere(), m))
+
+/// Apply the pre-assumed knowledge available to type inference prior to looking at
+/// the _body_ of the binding. For example, in a letrec we may assume this knowledge
+/// for each binding in the letrec prior to any type inference. This might, for example,
+/// tell us the type of the arguments to a recursive function.
+and ApplyTypesFromArgumentPatterns (cenv, env, optArgsOK, ty, m, tpenv, NormalizedBindingRhs (pushedPats, retInfoOpt, e), memberFlagsOpt: MemberFlags option) =
+ match pushedPats with
+ | [] ->
+ match retInfoOpt with
+ | None -> ()
+ | Some (SynBindingReturnInfo (retInfoTy, m, _)) ->
+ let retInfoTy, _ = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv retInfoTy
+ UnifyTypes cenv env m ty retInfoTy
+ // Property setters always have "unit" return type
+ match memberFlagsOpt with
+ | Some memFlags when memFlags.MemberKind = MemberKind.PropertySet ->
+ UnifyTypes cenv env m ty cenv.g.unit_ty
+ | _ -> ()
+
+ | pushedPat :: morePushedPats ->
+ let domainTy, resultTy = UnifyFunctionType None cenv env.DisplayEnv m ty
+ // We apply the type information from the patterns by type checking the
+ // "simple" patterns against 'domainTy'. They get re-typechecked later.
+ ignore (TcSimplePats cenv optArgsOK CheckCxs domainTy env (tpenv, Map.empty, Set.empty) pushedPat)
+ ApplyTypesFromArgumentPatterns (cenv, env, optArgsOK, resultTy, m, tpenv, NormalizedBindingRhs (morePushedPats, retInfoOpt, e), memberFlagsOpt)
+
+
+/// Check if the type annotations and inferred type information in a value give a
+/// full and complete generic type for a value. If so, enable generic recursion.
+and ComputeIsComplete enclosingDeclaredTypars declaredTypars ty =
+ Zset.isEmpty (List.fold (fun acc v -> Zset.remove v acc)
+ (freeInType CollectAllNoCaching ty).FreeTypars
+ (enclosingDeclaredTypars@declaredTypars))
+
+/// Determine if a uniquely-identified-abstract-slot exists for an override member (or interface member implementation) based on the information available
+/// at the syntactic definition of the member (i.e. prior to type inference). If so, we know the expected signature of the override, and the full slotsig
+/// it implements. Apply the inferred slotsig.
+and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (bindingTy, m, synTyparDecls, declaredTypars, memberId, tcrefObjTy, renaming, _objTy, optIntfSlotTy, valSynData, memberFlags, attribs) =
+
+ let ad = envinner.eAccessRights
+ let typToSearchForAbstractMembers =
+ match optIntfSlotTy with
+ | Some (ty, abstractSlots) ->
+ // The interface type is in terms of the type's type parameters.
+ // We need a signature in terms of the values' type parameters.
+ ty, Some abstractSlots
+ | None ->
+ tcrefObjTy, None
+
+ // Determine if a uniquely-identified-override exists based on the information
+ // at the member signature. If so, we know the type of this member, and the full slotsig
+ // it implements. Apply the inferred slotsig.
+ if memberFlags.IsOverrideOrExplicitImpl then
+
+ // for error detection, we want to compare finality when testing for equivalence
+ let methInfosEquivByNameAndSig meths =
+ match meths with
+ | [] -> false
+ | head :: tail ->
+ tail |> List.forall (MethInfosEquivByNameAndSig EraseNone false cenv.g cenv.amap m head)
+
+ match memberFlags.MemberKind with
+ | MemberKind.Member ->
+ let dispatchSlots, dispatchSlotsArityMatch =
+ GetAbstractMethInfosForSynMethodDecl(cenv.infoReader, ad, memberId, m, typToSearchForAbstractMembers, valSynData)
+
+ let uniqueAbstractMethSigs =
+ match dispatchSlots with
+ | [] ->
+ errorR(Error(FSComp.SR.tcNoMemberFoundForOverride(), memberId.idRange))
+ []
+
+ | slots ->
+ match dispatchSlotsArityMatch with
+ | meths when methInfosEquivByNameAndSig meths -> meths
+ | [] ->
+ let details =
+ slots
+ |> Seq.map (NicePrint.stringOfMethInfo cenv.amap m envinner.DisplayEnv)
+ |> Seq.map (sprintf "%s %s" System.Environment.NewLine)
+ |> String.concat ""
+
+ errorR(Error(FSComp.SR.tcOverrideArityMismatch details, memberId.idRange))
+ []
+ | _ -> [] // check that method to override is sealed is located at CheckOverridesAreAllUsedOnce (typrelns.fs)
+ // We hit this case when it is ambiguous which abstract method is being implemented.
+
+
+
+ // If we determined a unique member then utilize the type information from the slotsig
+ let declaredTypars =
+ match uniqueAbstractMethSigs with
+ | uniqueAbstractMeth :: _ ->
+
+ let uniqueAbstractMeth = uniqueAbstractMeth.Instantiate(cenv.amap, m, renaming)
+
+ let typarsFromAbsSlotAreRigid, typarsFromAbsSlot, argTysFromAbsSlot, retTyFromAbsSlot =
+ FreshenAbstractSlot cenv.g cenv.amap m synTyparDecls uniqueAbstractMeth
+
+ let declaredTypars = (if typarsFromAbsSlotAreRigid then typarsFromAbsSlot else declaredTypars)
+
+ let absSlotTy = mkMethodTy cenv.g argTysFromAbsSlot retTyFromAbsSlot
+
+ UnifyTypes cenv envinner m bindingTy absSlotTy
+ declaredTypars
+ | _ -> declaredTypars
+
+ // Retained to ensure use of an FSComp.txt entry, can be removed at a later date: errorR(Error(FSComp.SR.tcDefaultAmbiguous(), memberId.idRange))
+
+ // What's the type containing the abstract slot we're implementing? Used later on in MakeMemberDataAndMangledNameForMemberVal.
+ // This type must be in terms of the enclosing type's formal type parameters, hence the application of revRenaming
+
+ let optInferredImplSlotTys =
+ match optIntfSlotTy with
+ | Some (x, _) -> [x]
+ | None -> uniqueAbstractMethSigs |> List.map (fun x -> x.ApparentEnclosingType)
+
+ optInferredImplSlotTys, declaredTypars
+
+ | MemberKind.PropertyGet
+ | MemberKind.PropertySet as k ->
+ let dispatchSlots = GetAbstractPropInfosForSynPropertyDecl(cenv.infoReader, ad, memberId, m, typToSearchForAbstractMembers, k, valSynData)
+
+ // Only consider those abstract slots where the get/set flags match the value we're defining
+ let dispatchSlots =
+ dispatchSlots
+ |> List.filter (fun pinfo ->
+ (pinfo.HasGetter && k=MemberKind.PropertyGet) ||
+ (pinfo.HasSetter && k=MemberKind.PropertySet))
+
+ // Find the unique abstract slot if it exists
+ let uniqueAbstractPropSigs =
+ match dispatchSlots with
+ | [] when not (CompileAsEvent cenv.g attribs) ->
+ errorR(Error(FSComp.SR.tcNoPropertyFoundForOverride(), memberId.idRange))
+ []
+ | [uniqueAbstractProp] -> [uniqueAbstractProp]
+ | _ ->
+ // We hit this case when it is ambiguous which abstract property is being implemented.
+ []
+
+ // If we determined a unique member then utilize the type information from the slotsig
+ uniqueAbstractPropSigs |> List.iter (fun uniqueAbstractProp ->
+
+ let kIsGet = (k = MemberKind.PropertyGet)
+
+ if not (if kIsGet then uniqueAbstractProp.HasGetter else uniqueAbstractProp.HasSetter) then
+ error(Error(FSComp.SR.tcAbstractPropertyMissingGetOrSet(if kIsGet then "getter" else "setter"), memberId.idRange))
+
+ let uniqueAbstractMeth = if kIsGet then uniqueAbstractProp.GetterMethod else uniqueAbstractProp.SetterMethod
+
+ let uniqueAbstractMeth = uniqueAbstractMeth.Instantiate(cenv.amap, m, renaming)
+
+ let _, typarsFromAbsSlot, argTysFromAbsSlot, retTyFromAbsSlot =
+ FreshenAbstractSlot cenv.g cenv.amap m synTyparDecls uniqueAbstractMeth
+
+ if not (isNil typarsFromAbsSlot) then
+ errorR(InternalError("Unexpected generic property", memberId.idRange))
+
+ let absSlotTy =
+ if (memberFlags.MemberKind = MemberKind.PropertyGet)
+ then mkMethodTy cenv.g argTysFromAbsSlot retTyFromAbsSlot
+ else
+ match argTysFromAbsSlot with
+ | [argTysFromAbsSlot] -> mkRefTupledTy cenv.g argTysFromAbsSlot --> cenv.g.unit_ty
+ | _ ->
+ error(Error(FSComp.SR.tcInvalidSignatureForSet(), memberId.idRange))
+ retTyFromAbsSlot --> cenv.g.unit_ty
+
+ UnifyTypes cenv envinner m bindingTy absSlotTy)
+
+ // What's the type containing the abstract slot we're implementing? Used later on in MakeMemberDataAndMangledNameForMemberVal.
+ // This type must be in terms of the enclosing type's formal type parameters, hence the application of revRenaming.
+
+ let optInferredImplSlotTys =
+ match optIntfSlotTy with
+ | Some (x, _) -> [ x ]
+ | None -> uniqueAbstractPropSigs |> List.map (fun pinfo -> pinfo.ApparentEnclosingType)
+
+ optInferredImplSlotTys, declaredTypars
+
+ | _ ->
+ match optIntfSlotTy with
+ | Some (x, _) -> [x], declaredTypars
+ | None -> [], declaredTypars
+
+ else
+
+ [], declaredTypars
+
+and CheckForNonAbstractInterface declKind tcref memberFlags m =
+ if isInterfaceTyconRef tcref then
+ if memberFlags.MemberKind = MemberKind.ClassConstructor then
+ error(Error(FSComp.SR.tcStaticInitializersIllegalInInterface(), m))
+ elif memberFlags.MemberKind = MemberKind.Constructor then
+ error(Error(FSComp.SR.tcObjectConstructorsIllegalInInterface(), m))
+ elif memberFlags.IsOverrideOrExplicitImpl then
+ error(Error(FSComp.SR.tcMemberOverridesIllegalInInterface(), m))
+ elif not (declKind=ExtrinsicExtensionBinding || memberFlags.IsDispatchSlot ) then
+ error(Error(FSComp.SR.tcConcreteMembersIllegalInInterface(), m))
+
+//-------------------------------------------------------------------------
+// TcLetrec - AnalyzeAndMakeAndPublishRecursiveValue s
+//------------------------------------------------------------------------
+
+and AnalyzeRecursiveStaticMemberOrValDecl
+ (cenv,
+ envinner: TcEnv,
+ tpenv,
+ declKind,
+ newslotsOK,
+ overridesOK,
+ tcrefContainerInfo,
+ vis1,
+ id: Ident,
+ vis2,
+ declaredTypars,
+ memberFlagsOpt,
+ thisIdOpt,
+ bindingAttribs,
+ valSynInfo,
+ ty,
+ bindingRhs,
+ mBinding,
+ explicitTyparInfo) =
+
+ let vis = CombineVisibilityAttribs vis1 vis2 mBinding
+
+ // Check if we're defining a member, in which case generate the internal unique
+ // name for the member and the information about which type it is augmenting
+
+ match tcrefContainerInfo, memberFlagsOpt with
+ | (Some(MemberOrValContainerInfo(tcref, optIntfSlotTy, baseValOpt, _safeInitInfo, declaredTyconTypars)), Some memberFlags) ->
+ assert (Option.isNone optIntfSlotTy)
+
+ CheckMemberFlags None newslotsOK overridesOK memberFlags id.idRange
+ CheckForNonAbstractInterface declKind tcref memberFlags id.idRange
+
+ if memberFlags.MemberKind = MemberKind.Constructor && tcref.Deref.IsExceptionDecl then
+ error(Error(FSComp.SR.tcConstructorsDisallowedInExceptionAugmentation(), id.idRange))
+
+ let isExtrinsic = (declKind = ExtrinsicExtensionBinding)
+ let _, enclosingDeclaredTypars, _, objTy, thisTy = FreshenObjectArgType cenv mBinding TyparRigidity.WillBeRigid tcref isExtrinsic declaredTyconTypars
+ let envinner = AddDeclaredTypars CheckForDuplicateTypars enclosingDeclaredTypars envinner
+ let envinner = MakeInnerEnvForTyconRef envinner tcref isExtrinsic
+
+ let safeThisValOpt, baseValOpt =
+ match memberFlags.MemberKind with
+
+ // Explicit struct or class constructor
+ | MemberKind.Constructor ->
+ // A fairly adhoc place to put this check
+ if tcref.IsStructOrEnumTycon && (match valSynInfo with SynValInfo([[]], _) -> true | _ -> false) then
+ errorR(Error(FSComp.SR.tcStructsCannotHaveConstructorWithNoArguments(), mBinding))
+
+ if not tcref.IsFSharpObjectModelTycon then
+ errorR(Error(FSComp.SR.tcConstructorsIllegalForThisType(), id.idRange))
+
+ let safeThisValOpt = MakeAndPublishSafeThisVal cenv envinner thisIdOpt thisTy
+
+ // baseValOpt is the 'base' variable associated with the inherited portion of a class
+ // It is declared once on the 'inheritedTys clause, but a fresh binding is made for
+ // each member that may use it.
+ let baseValOpt =
+ match GetSuperTypeOfType cenv.g cenv.amap mBinding objTy with
+ | Some superTy -> MakeAndPublishBaseVal cenv envinner (match baseValOpt with None -> None | Some v -> Some v.Id) superTy
+ | None -> None
+
+ let domainTy = NewInferenceType ()
+
+ // This is the type we pretend a constructor has, because its implementation must ultimately appear to return a value of the given type
+ // This is somewhat awkward later in codegen etc.
+ UnifyTypes cenv envinner mBinding ty (domainTy --> objTy)
+
+ safeThisValOpt, baseValOpt
+
+ | _ ->
+ None, None
+
+ let memberInfo =
+ let isExtrinsic = (declKind = ExtrinsicExtensionBinding)
+ MakeMemberDataAndMangledNameForMemberVal(cenv.g, tcref, isExtrinsic, bindingAttribs, [], memberFlags, valSynInfo, id, false)
+
+ envinner, tpenv, id, None, Some memberInfo, vis, vis2, safeThisValOpt, enclosingDeclaredTypars, baseValOpt, explicitTyparInfo, bindingRhs, declaredTypars
+
+ // non-member bindings. How easy.
+ | _ ->
+ envinner, tpenv, id, None, None, vis, vis2, None, [], None, explicitTyparInfo, bindingRhs, declaredTypars
+
+
+and AnalyzeRecursiveInstanceMemberDecl
+ (cenv,
+ envinner: TcEnv,
+ tpenv,
+ declKind,
+ synTyparDecls,
+ valSynInfo,
+ explicitTyparInfo: ExplicitTyparInfo,
+ newslotsOK,
+ overridesOK,
+ vis1,
+ thisId,
+ memberId: Ident,
+ toolId: Ident option,
+ bindingAttribs,
+ vis2,
+ tcrefContainerInfo,
+ memberFlagsOpt,
+ ty,
+ bindingRhs,
+ mBinding) =
+
+ let vis = CombineVisibilityAttribs vis1 vis2 mBinding
+ let (ExplicitTyparInfo(_, declaredTypars, infer)) = explicitTyparInfo
+ match tcrefContainerInfo, memberFlagsOpt with
+ // Normal instance members.
+ | Some(MemberOrValContainerInfo(tcref, optIntfSlotTy, baseValOpt, _safeInitInfo, declaredTyconTypars)), Some memberFlags ->
+
+ CheckMemberFlags optIntfSlotTy newslotsOK overridesOK memberFlags mBinding
+
+ if Option.isSome vis && memberFlags.IsOverrideOrExplicitImpl then
+ errorR(Error(FSComp.SR.tcOverridesCannotHaveVisibilityDeclarations(), memberId.idRange))
+
+ // Syntactically push the "this" variable across to be a lambda on the right
+ let bindingRhs = PushOnePatternToRhs cenv true (mkSynThisPatVar thisId) bindingRhs
+
+ // The type being augmented tells us the type of 'this'
+ let isExtrinsic = (declKind = ExtrinsicExtensionBinding)
+ let tcrefObjTy, enclosingDeclaredTypars, renaming, objTy, thisTy = FreshenObjectArgType cenv mBinding TyparRigidity.WillBeRigid tcref isExtrinsic declaredTyconTypars
+
+ let envinner = AddDeclaredTypars CheckForDuplicateTypars enclosingDeclaredTypars envinner
+
+ // If private, the member's accessibility is related to 'tcref'
+ let envinner = MakeInnerEnvForTyconRef envinner tcref isExtrinsic
+
+ let baseValOpt = if tcref.IsFSharpObjectModelTycon then baseValOpt else None
+
+ // Apply the known type of 'this'
+ let bindingTy = NewInferenceType ()
+ UnifyTypes cenv envinner mBinding ty (thisTy --> bindingTy)
+
+ CheckForNonAbstractInterface declKind tcref memberFlags memberId.idRange
+
+ // Determine if a uniquely-identified-override List.exists based on the information
+ // at the member signature. If so, we know the type of this member, and the full slotsig
+ // it implements. Apply the inferred slotsig.
+ let optInferredImplSlotTys, declaredTypars =
+ ApplyAbstractSlotInference cenv envinner (bindingTy, mBinding, synTyparDecls, declaredTypars, memberId, tcrefObjTy, renaming, objTy, optIntfSlotTy, valSynInfo, memberFlags, bindingAttribs)
+
+ // Update the ExplicitTyparInfo to reflect the declaredTypars inferred from the abstract slot
+ let explicitTyparInfo = ExplicitTyparInfo(declaredTypars, declaredTypars, infer)
+
+ // baseValOpt is the 'base' variable associated with the inherited portion of a class
+ // It is declared once on the 'inheritedTys clause, but a fresh binding is made for
+ // each member that may use it.
+ let baseValOpt =
+ match GetSuperTypeOfType cenv.g cenv.amap mBinding objTy with
+ | Some superTy -> MakeAndPublishBaseVal cenv envinner (match baseValOpt with None -> None | Some v -> Some v.Id) superTy
+ | None -> None
+
+ let memberInfo = MakeMemberDataAndMangledNameForMemberVal(cenv.g, tcref, isExtrinsic, bindingAttribs, optInferredImplSlotTys, memberFlags, valSynInfo, memberId, false)
+ // This line factored in the 'get' or 'set' as the identifier for a property declaration using "with get () = ... and set v = ..."
+ // It has been removed from FSharp.Compiler.Service because we want the property name to be the location of
+ // the definition of these symbols.
+ //
+ // See https://github.com/fsharp/FSharp.Compiler.Service/issues/79.
+ //let memberId = match toolId with Some tid -> ident(memberId.idText, tid.idRange) | None -> memberId
+ //ignore toolId
+
+ envinner, tpenv, memberId, toolId, Some memberInfo, vis, vis2, None, enclosingDeclaredTypars, baseValOpt, explicitTyparInfo, bindingRhs, declaredTypars
+ | _ ->
+ error(Error(FSComp.SR.tcRecursiveBindingsWithMembersMustBeDirectAugmentation(), mBinding))
+
+and AnalyzeRecursiveDecl
+ (cenv,
+ envinner,
+ tpenv,
+ declKind,
+ synTyparDecls,
+ declaredTypars,
+ thisIdOpt,
+ valSynInfo,
+ explicitTyparInfo,
+ newslotsOK,
+ overridesOK,
+ vis1,
+ declPattern,
+ bindingAttribs,
+ tcrefContainerInfo,
+ memberFlagsOpt,
+ ty,
+ bindingRhs,
+ mBinding) =
+
+ let rec analyzeRecursiveDeclPat tpenv p =
+ match p with
+ | SynPat.FromParseError(pat', _) -> analyzeRecursiveDeclPat tpenv pat'
+ | SynPat.Typed(pat', cty, _) ->
+ let cty', tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType envinner tpenv cty
+ UnifyTypes cenv envinner mBinding ty cty'
+ analyzeRecursiveDeclPat tpenv pat'
+ | SynPat.Attrib(_pat', _attribs, m) ->
+ error(Error(FSComp.SR.tcAttributesInvalidInPatterns(), m))
+ //analyzeRecursiveDeclPat pat'
+
+ // This is for the construct 'let rec x = ... and do ... and y = ...' (DEPRECATED IN pars.mly )
+ //
+ // Also for
+ // module rec M =
+ // printfn "hello" // side effects in recursive modules
+ // let x = 1
+ | SynPat.Const (SynConst.Unit, m) | SynPat.Wild m ->
+ let id = ident (cenv.niceNameGen.FreshCompilerGeneratedName("doval", m), m)
+ analyzeRecursiveDeclPat tpenv (SynPat.Named (SynPat.Wild m, id, false, None, m))
+
+ | SynPat.Named (SynPat.Wild _, id, _, vis2, _) ->
+ AnalyzeRecursiveStaticMemberOrValDecl
+ (cenv, envinner, tpenv, declKind,
+ newslotsOK, overridesOK, tcrefContainerInfo,
+ vis1, id, vis2, declaredTypars,
+ memberFlagsOpt, thisIdOpt, bindingAttribs,
+ valSynInfo, ty, bindingRhs, mBinding, explicitTyparInfo)
+
+ | SynPat.InstanceMember(thisId, memberId, toolId, vis2, _) ->
+ AnalyzeRecursiveInstanceMemberDecl
+ (cenv, envinner, tpenv, declKind,
+ synTyparDecls, valSynInfo, explicitTyparInfo, newslotsOK,
+ overridesOK, vis1, thisId, memberId, toolId,
+ bindingAttribs, vis2, tcrefContainerInfo,
+ memberFlagsOpt, ty, bindingRhs, mBinding)
+
+ | _ -> error(Error(FSComp.SR.tcOnlySimplePatternsInLetRec(), mBinding))
+
+ analyzeRecursiveDeclPat tpenv declPattern
+
+
+/// This is a major routine that generates the Val for a recursive binding
+/// prior to the analysis of the definition of the binding. This includes
+/// members of all flavours (including properties, implicit class constructors
+/// and overrides). At this point we perform override inference, to infer
+/// which method we are overriding, in order to add constraints to the
+/// implementation of the method.
+and AnalyzeAndMakeAndPublishRecursiveValue
+ overridesOK
+ isGeneratedEventVal
+ cenv
+ (env: TcEnv)
+ (tpenv, recBindIdx)
+ (NormalizedRecBindingDefn(containerInfo, newslotsOK, declKind, binding)) =
+
+ // Pull apart the inputs
+ let (NormalizedBinding(vis1, bindingKind, isInline, isMutable, bindingSynAttribs, bindingXmlDoc, synTyparDecls, valSynData, declPattern, bindingRhs, mBinding, spBind)) = binding
+ let (NormalizedBindingRhs(_, _, bindingExpr)) = bindingRhs
+ let (SynValData(memberFlagsOpt, valSynInfo, thisIdOpt)) = valSynData
+ let (ContainerInfo(altActualParent, tcrefContainerInfo)) = containerInfo
+
+ let attrTgt = DeclKind.AllowedAttribTargets memberFlagsOpt declKind
+
+ // Check the attributes on the declaration
+ let bindingAttribs = TcAttributes cenv env attrTgt bindingSynAttribs
+
+ // Allocate the type inference variable for the inferred type
+ let ty = NewInferenceType ()
+
+
+ let inlineFlag = ComputeInlineFlag memberFlagsOpt isInline isMutable mBinding
+ if isMutable then errorR(Error(FSComp.SR.tcOnlyRecordFieldsAndSimpleLetCanBeMutable(), mBinding))
+
+
+ // Typecheck the typar decls, if any
+ let explicitTyparInfo, tpenv = TcBindingTyparDecls false cenv env tpenv synTyparDecls
+ let (ExplicitTyparInfo(_, declaredTypars, _)) = explicitTyparInfo
+ let envinner = AddDeclaredTypars CheckForDuplicateTypars declaredTypars env
+
+ // OK, analyze the declaration and return lots of information about it
+ let envinner, tpenv, bindingId, toolIdOpt, memberInfoOpt, vis, vis2, safeThisValOpt, enclosingDeclaredTypars, baseValOpt, explicitTyparInfo, bindingRhs, declaredTypars =
+
+ AnalyzeRecursiveDecl (cenv, envinner, tpenv, declKind, synTyparDecls, declaredTypars, thisIdOpt, valSynInfo, explicitTyparInfo,
+ newslotsOK, overridesOK, vis1, declPattern, bindingAttribs, tcrefContainerInfo,
+ memberFlagsOpt, ty, bindingRhs, mBinding)
+
+ let optArgsOK = Option.isSome memberFlagsOpt
+
+ // Assert the types given in the argument patterns
+ ApplyTypesFromArgumentPatterns(cenv, envinner, optArgsOK, ty, mBinding, tpenv, bindingRhs, memberFlagsOpt)
+
+ // Do the type annotations give the full and complete generic type?
+ // If so, generic recursion can be used when using this type.
+ let isComplete = ComputeIsComplete enclosingDeclaredTypars declaredTypars ty
+
+ // NOTE: The type scheme here is normally not 'complete'!!!! The type is more or less just a type variable at this point.
+ // NOTE: top arity, type and typars get fixed-up after inference
+ let prelimTyscheme = TypeScheme(enclosingDeclaredTypars@declaredTypars, ty)
+ let partialValReprInfo = TranslateTopValSynInfo mBinding (TcAttributes cenv envinner) valSynInfo
+ let topValInfo = UseSyntacticArity declKind prelimTyscheme partialValReprInfo
+ let hasDeclaredTypars = not (List.isEmpty declaredTypars)
+ let prelimValScheme = ValScheme(bindingId, prelimTyscheme, topValInfo, memberInfoOpt, false, inlineFlag, NormalVal, vis, false, false, false, hasDeclaredTypars)
+
+ // Check the literal r.h.s., if any
+ let _, literalValue = TcLiteral cenv ty envinner tpenv (bindingAttribs, bindingExpr)
+
+ let extraBindings, extraValues, tpenv, recBindIdx =
+ let extraBindings =
+ [ for extraBinding in EventDeclarationNormalization.GenerateExtraBindings cenv (bindingAttribs, binding) do
+ yield (NormalizedRecBindingDefn(containerInfo, newslotsOK, declKind, extraBinding)) ]
+ let res, (tpenv, recBindIdx) = List.mapFold (AnalyzeAndMakeAndPublishRecursiveValue overridesOK true cenv env) (tpenv, recBindIdx) extraBindings
+ let extraBindings, extraValues = List.unzip res
+ List.concat extraBindings, List.concat extraValues, tpenv, recBindIdx
+
+ // Create the value
+ let vspec = MakeAndPublishVal cenv envinner (altActualParent, false, declKind, ValInRecScope isComplete, prelimValScheme, bindingAttribs, bindingXmlDoc, literalValue, isGeneratedEventVal)
+
+ // Suppress hover tip for "get" and "set" at property definitions, where toolId <> bindingId
+ match toolIdOpt with
+ | Some tid when not tid.idRange.IsSynthetic && not (Range.equals tid.idRange bindingId.idRange) ->
+ let item = Item.Value (mkLocalValRef vspec)
+ CallNameResolutionSink cenv.tcSink (tid.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.RelatedText, env.eAccessRights)
+ | _ -> ()
+
+ let mangledId = ident(vspec.LogicalName, vspec.Range)
+ // Reconstitute the binding with the unique name
+ let revisedBinding = NormalizedBinding (vis1, bindingKind, isInline, isMutable, bindingSynAttribs, bindingXmlDoc, synTyparDecls, valSynData, mkSynPatVar vis2 mangledId, bindingRhs, mBinding, spBind)
+
+ // Create the RecursiveBindingInfo to use in later phases
+ let rbinfo =
+ let safeInitInfo =
+ match tcrefContainerInfo with
+ | Some(MemberOrValContainerInfo(_, _, _, safeInitInfo, _)) -> safeInitInfo
+ | _ -> NoSafeInitInfo
+
+ RecursiveBindingInfo(recBindIdx, containerInfo, enclosingDeclaredTypars, inlineFlag, vspec, explicitTyparInfo, partialValReprInfo, memberInfoOpt, baseValOpt, safeThisValOpt, safeInitInfo, vis, ty, declKind)
+
+ let recBindIdx = recBindIdx + 1
+
+ // Done - add the declared name to the List.map and return the bundle for use by TcLetrec
+ let primaryBinding: PreCheckingRecursiveBinding =
+ { SyntacticBinding = revisedBinding
+ RecBindingInfo = rbinfo }
+
+ ((primaryBinding :: extraBindings), (vspec :: extraValues)), (tpenv, recBindIdx)
+
+and AnalyzeAndMakeAndPublishRecursiveValues overridesOK cenv env tpenv binds =
+ let recBindIdx = 0
+ let res, tpenv = List.mapFold (AnalyzeAndMakeAndPublishRecursiveValue overridesOK false cenv env) (tpenv, recBindIdx) binds
+ let bindings, values = List.unzip res
+ List.concat bindings, List.concat values, tpenv
+
+
+//-------------------------------------------------------------------------
+// TcLetrecBinding
+//-------------------------------------------------------------------------
+
+and TcLetrecBinding
+ (cenv, envRec: TcEnv, scopem, extraGeneralizableTypars: Typars, reqdThisValTyOpt: TType option)
+
+ // The state of the left-to-right iteration through the bindings
+ (envNonRec: TcEnv,
+ generalizedRecBinds: PostGeneralizationRecursiveBinding list,
+ preGeneralizationRecBinds: PreGeneralizationRecursiveBinding list,
+ tpenv,
+ uncheckedRecBindsTable: Map)
+
+ // This is the actual binding to check
+ (rbind: PreCheckingRecursiveBinding) =
+
+ let (RecursiveBindingInfo(_, _, enclosingDeclaredTypars, _, vspec, explicitTyparInfo, _, _, baseValOpt, safeThisValOpt, safeInitInfo, _, tau, declKind)) = rbind.RecBindingInfo
+
+ let allDeclaredTypars = enclosingDeclaredTypars @ rbind.RecBindingInfo.DeclaredTypars
+
+ // Notes on FSharp 1.0, 3187:
+ // - Progressively collect the "eligible for early generalization" set of bindings -- DONE
+ // - After checking each binding, check this set to find generalizable bindings
+ // - The only reason we can't generalize is if a binding refers to type variables to which
+ // additional constraints may be applied as part of checking a later binding
+ // - Compute the set by iteratively knocking out bindings that refer to type variables free in later bindings
+ // - Implementation notes:
+ // - Generalize by remap/substitution
+ // - Pass in "free in later bindings" by passing in the set of inference variables for the bindings, i.e. the binding types
+ // - For classes the bindings will include all members in a recursive group of types
+ //
+
+ // Example 1:
+ // let f() = g() f: unit -> ?b
+ // and g() = 1 f: unit -> int, can generalize (though now monomorphic)
+
+ // Example 2:
+ // let f() = g() f: unit -> ?b
+ // and g() = [] f: unit -> ?c list, can generalize
+
+ // Example 3:
+ // let f() = [] f: unit -> ?b, can generalize immediately
+ // and g() = []
+ let envRec = Option.foldBack (AddLocalVal cenv.tcSink scopem) baseValOpt envRec
+ let envRec = Option.foldBack (AddLocalVal cenv.tcSink scopem) safeThisValOpt envRec
+
+ // Members can access protected members of parents of the type, and private members in the type
+ let envRec = MakeInnerEnvForMember envRec vspec
+
+ let checkedBind, tpenv =
+ TcNormalizedBinding declKind cenv envRec tpenv tau safeThisValOpt safeInitInfo (enclosingDeclaredTypars, explicitTyparInfo) rbind.SyntacticBinding
+
+ (try UnifyTypes cenv envRec vspec.Range (allDeclaredTypars +-> tau) vspec.Type
+ with e -> error (Recursion(envRec.DisplayEnv, vspec.Id, tau, vspec.Type, vspec.Range)))
+
+ // Inside the incremental class syntax we assert the type of the 'this' variable to be precisely the same type as the
+ // this variable for the implicit class constructor. For static members, we assert the type variables associated
+ // for the class to be identical to those used for the implicit class constructor and the static class constructor.
+ match reqdThisValTyOpt with
+ | None -> ()
+ | Some reqdThisValTy ->
+ let reqdThisValTy, actualThisValTy, rangeForCheck =
+ match GetInstanceMemberThisVariable (vspec, checkedBind.Expr) with
+ | None ->
+ let reqdThisValTy = if isByrefTy cenv.g reqdThisValTy then destByrefTy cenv.g reqdThisValTy else reqdThisValTy
+ let enclosingTyconRef = tcrefOfAppTy cenv.g reqdThisValTy
+ reqdThisValTy, (mkAppTy enclosingTyconRef (List.map mkTyparTy enclosingDeclaredTypars)), vspec.Range
+ | Some thisVal ->
+ reqdThisValTy, thisVal.Type, thisVal.Range
+ if not (AddCxTypeEqualsTypeUndoIfFailed envRec.DisplayEnv cenv.css rangeForCheck actualThisValTy reqdThisValTy) then
+ errorR (Error(FSComp.SR.tcNonUniformMemberUse vspec.DisplayName, vspec.Range))
+
+ let preGeneralizationRecBind =
+ { RecBindingInfo = rbind.RecBindingInfo
+ CheckedBinding= checkedBind
+ ExtraGeneralizableTypars= extraGeneralizableTypars }
+
+ // Remove one binding from the unchecked list
+ let uncheckedRecBindsTable =
+ assert (uncheckedRecBindsTable.ContainsKey rbind.RecBindingInfo.Val.Stamp)
+ uncheckedRecBindsTable.Remove rbind.RecBindingInfo.Val.Stamp
+
+ // Add one binding to the candidates eligible for generalization
+ let preGeneralizationRecBinds = (preGeneralizationRecBind :: preGeneralizationRecBinds)
+
+ // Incrementally generalize as many bindings as we can
+ TcIncrementalLetRecGeneralization cenv scopem (envNonRec, generalizedRecBinds, preGeneralizationRecBinds, tpenv, uncheckedRecBindsTable)
+
+and TcIncrementalLetRecGeneralization cenv scopem
+ // The state of the left-to-right iteration through the bindings
+ (envNonRec: TcEnv,
+ generalizedRecBinds: PostGeneralizationRecursiveBinding list,
+ preGeneralizationRecBinds: PreGeneralizationRecursiveBinding list,
+ tpenv,
+ uncheckedRecBindsTable: Map) =
+
+ let denv = envNonRec.DisplayEnv
+ // recompute the free-in-environment in case any type variables have been instantiated
+ let freeInEnv = GeneralizationHelpers.ComputeUngeneralizableTypars envNonRec
+
+ // Attempt to actually generalize some of the candidates eligible for generalization.
+ // Compute which bindings are now eligible for early generalization.
+ // Do this by computing a greatest fixed point by iteratively knocking out bindings that refer
+ // to type variables free in later bindings. Look for ones whose type doesn't involve any of the other types
+ let newGeneralizedRecBinds, preGeneralizationRecBinds, tpenv =
+
+ //printfn "\n---------------------\nConsidering early generalization after type checking binding %s" vspec.DisplayName
+
+ // Get the type variables free in bindings that have not yet been checked.
+ //
+ // The naive implementation of this is to iterate all the forward bindings, but this is quadratic.
+ //
+ // It turns out we can remove the quadratic behaviour as follows.
+ // - During type checking we already keep a table of recursive uses of values, indexed by target value.
+ // - This table is usually much smaller than the number of remaining forward declarations ? e.g. in the pathological case you mentioned below this table is size 1.
+ // - If a forward declaration does not have an entry in this table then its type can't involve any inference variables from the declarations we have already checked.
+ // - So by scanning the domain of this table we can reduce the complexity down to something like O(n * average-number-of-forward-calls).
+ // - For a fully connected programs or programs where every forward declaration is subject to a forward call, this would be quadratic. However we do not expect call graphs to be like this in practice
+ //
+ // Hence we use the recursive-uses table to guide the process of scraping forward references for frozen types
+ // If the is no entry in the recursive use table then a forward binding has never been used and
+ // the type of a binding will not contain any inference variables.
+ //
+ // We do this lazily in case it is "obvious" that a binding can be generalized (e.g. its type doesn't
+ // involve any type inference variables)
+ //
+ // The forward uses table will always be smaller than the number of potential forward bindings except in extremely
+ // pathological situations
+ let freeInUncheckedRecBinds =
+ lazy ((emptyFreeTyvars, cenv.recUses.Contents) ||> Map.fold (fun acc vStamp _ ->
+ match uncheckedRecBindsTable.TryGetValue vStamp with
+ | true, fwdBind ->
+ accFreeInType CollectAllNoCaching fwdBind.RecBindingInfo.Val.Type acc
+ | _ ->
+ acc))
+
+ let rec loop (preGeneralizationRecBinds: PreGeneralizationRecursiveBinding list,
+ frozenBindings: PreGeneralizationRecursiveBinding list) =
+
+ let frozenBindingTypes = frozenBindings |> List.map (fun pgrbind -> pgrbind.RecBindingInfo.Val.Type)
+
+ let freeInFrozenAndLaterBindings =
+ if frozenBindingTypes.IsEmpty then
+ freeInUncheckedRecBinds
+ else
+ lazy (accFreeInTypes CollectAllNoCaching frozenBindingTypes (freeInUncheckedRecBinds.Force()))
+
+ let preGeneralizationRecBinds, newFrozenBindings =
+
+ preGeneralizationRecBinds |> List.partition (fun pgrbind ->
+
+ //printfn "(testing binding %s)" pgrbind.RecBindingInfo.Val.DisplayName
+
+ // Get the free type variables in the binding
+ //
+ // We use the TauType here because the binding may already have been pre-generalized because it has
+ // a fully type-annotated type signature. We effectively want to generalize the binding
+ // again here, properly - for example this means adjusting the expression for the binding to include
+ // a Expr_tlambda. If we use Val.Type then the type will appear closed.
+ let freeInBinding = (freeInType CollectAllNoCaching pgrbind.RecBindingInfo.Val.TauType).FreeTypars
+
+ // Is the binding free of type inference variables? If so, it can be generalized immediately
+ if freeInBinding.IsEmpty then true else
+
+ //printfn "(failed generalization test 1 for binding for %s)" pgrbind.RecBindingInfo.Val.DisplayName
+ // Any declared type parameters in an type are always generalizable
+ let freeInBinding = Zset.diff freeInBinding (Zset.ofList typarOrder (NormalizeDeclaredTyparsForEquiRecursiveInference cenv.g pgrbind.ExtraGeneralizableTypars))
+
+ if freeInBinding.IsEmpty then true else
+
+ //printfn "(failed generalization test 2 for binding for %s)" pgrbind.RecBindingInfo.Val.DisplayName
+
+ // Any declared method parameters can always be generalized
+ let freeInBinding = Zset.diff freeInBinding (Zset.ofList typarOrder (NormalizeDeclaredTyparsForEquiRecursiveInference cenv.g pgrbind.RecBindingInfo.DeclaredTypars))
+
+ if freeInBinding.IsEmpty then true else
+
+ //printfn "(failed generalization test 3 for binding for %s)" pgrbind.RecBindingInfo.Val.DisplayName
+
+ // Type variables free in the non-recursive environment do not stop us generalizing the binding,
+ // since they can't be generalized anyway
+ let freeInBinding = Zset.diff freeInBinding freeInEnv
+
+ if freeInBinding.IsEmpty then true else
+
+ //printfn "(failed generalization test 4 for binding for %s)" pgrbind.RecBindingInfo.Val.DisplayName
+
+ // Type variables free in unchecked bindings do stop us generalizing
+ let freeInBinding = Zset.inter (freeInFrozenAndLaterBindings.Force().FreeTypars) freeInBinding
+
+ if freeInBinding.IsEmpty then true else
+
+ //printfn "(failed generalization test 5 for binding for %s)" pgrbind.RecBindingInfo.Val.DisplayName
+
+ false)
+ //if canGeneralize then
+ // printfn "YES: binding for %s can be generalized early" pgrbind.RecBindingInfo.Val.DisplayName
+ //else
+ // printfn "NO: binding for %s can't be generalized early" pgrbind.RecBindingInfo.Val.DisplayName
+
+ // Have we reached a fixed point?
+ if newFrozenBindings.IsEmpty then
+ preGeneralizationRecBinds, frozenBindings
+ else
+ // if not, then repeat
+ loop(preGeneralizationRecBinds, newFrozenBindings@frozenBindings)
+
+ // start with no frozen bindings
+ let newGeneralizableBindings, preGeneralizationRecBinds = loop(preGeneralizationRecBinds, [])
+
+ // Some of the bindings may now have been marked as 'generalizable' (which means they now transition
+ // from PreGeneralization --> PostGeneralization, since we won't get any more information on
+ // these bindings by processing later bindings). But this doesn't mean we
+ // actually generalize all the individual type variables occuring in these bindings - for example, some
+ // type variables may be free in the environment, and some definitions
+ // may be value definitions which can't be generalized, e.g.
+ // let rec f x = g x
+ // and g = id f
+ // Here the type variables in 'g' can't be generalized because it's a computation on the right.
+ //
+ // Note that in the normal case each binding passes IsGeneralizableValue. Properties and
+ // constructors do not pass CanInferExtraGeneralizedTyparsForRecBinding.
+
+ let freeInEnv =
+ (freeInEnv, newGeneralizableBindings) ||> List.fold (fun freeInEnv pgrbind ->
+ if GeneralizationHelpers.IsGeneralizableValue cenv.g pgrbind.CheckedBinding.Expr then
+ freeInEnv
+ else
+ let freeInBinding = (freeInType CollectAllNoCaching pgrbind.RecBindingInfo.Val.TauType).FreeTypars
+ let freeInBinding = Zset.diff freeInBinding (Zset.ofList typarOrder (NormalizeDeclaredTyparsForEquiRecursiveInference cenv.g pgrbind.ExtraGeneralizableTypars))
+ let freeInBinding = Zset.diff freeInBinding (Zset.ofList typarOrder (NormalizeDeclaredTyparsForEquiRecursiveInference cenv.g pgrbind.RecBindingInfo.DeclaredTypars))
+ Zset.union freeInBinding freeInEnv)
+
+ // Process the bindings marked for transition from PreGeneralization --> PostGeneralization
+ let newGeneralizedRecBinds, tpenv =
+ if newGeneralizableBindings.IsEmpty then
+ [], tpenv
+ else
+
+ let supportForBindings = newGeneralizableBindings |> List.collect (TcLetrecComputeSupportForBinding cenv)
+ ConstraintSolver.CanonicalizePartialInferenceProblem cenv.css denv scopem supportForBindings
+
+ let generalizedTyparsL = newGeneralizableBindings |> List.map (TcLetrecComputeAndGeneralizeGenericTyparsForBinding cenv denv freeInEnv)
+
+ // Generalize the bindings.
+ let newGeneralizedRecBinds = (generalizedTyparsL, newGeneralizableBindings) ||> List.map2 (TcLetrecGeneralizeBinding cenv denv )
+ let tpenv = HideUnscopedTypars (List.concat generalizedTyparsL) tpenv
+ newGeneralizedRecBinds, tpenv
+
+
+ newGeneralizedRecBinds, preGeneralizationRecBinds, tpenv
+
+ let envNonRec = envNonRec |> AddLocalVals cenv.tcSink scopem (newGeneralizedRecBinds |> List.map (fun b -> b.RecBindingInfo.Val))
+ let generalizedRecBinds = newGeneralizedRecBinds @ generalizedRecBinds
+
+ (envNonRec, generalizedRecBinds, preGeneralizationRecBinds, tpenv, uncheckedRecBindsTable)
+
+//-------------------------------------------------------------------------
+// TcLetrecComputeAndGeneralizeGenericTyparsForBinding
+//-------------------------------------------------------------------------
+
+/// Compute the type variables which may be generalized and perform the generalization
+and TcLetrecComputeAndGeneralizeGenericTyparsForBinding cenv denv freeInEnv (pgrbind: PreGeneralizationRecursiveBinding) =
+
+ let freeInEnv = Zset.diff freeInEnv (Zset.ofList typarOrder (NormalizeDeclaredTyparsForEquiRecursiveInference cenv.g pgrbind.ExtraGeneralizableTypars))
+
+ let rbinfo = pgrbind.RecBindingInfo
+ let vspec = rbinfo.Val
+ let (CheckedBindingInfo(inlineFlag, _, _, _, _, _, expr, _, _, m, _, _, _, _)) = pgrbind.CheckedBinding
+ let (ExplicitTyparInfo(rigidCopyOfDeclaredTypars, declaredTypars, _)) = rbinfo.ExplicitTyparInfo
+ let allDeclaredTypars = rbinfo.EnclosingDeclaredTypars @ declaredTypars
+
+ // The declared typars were not marked rigid to allow equi-recursive type inference to unify
+ // two declared type variables. So we now check that, for each binding, the declared
+ // type variables can be unified with a rigid version of the same and undo the results
+ // of this unification.
+ ConstraintSolver.CheckDeclaredTypars denv cenv.css m rigidCopyOfDeclaredTypars declaredTypars
+
+ let memFlagsOpt = vspec.MemberInfo |> Option.map (fun memInfo -> memInfo.MemberFlags)
+ let isCtor = (match memFlagsOpt with None -> false | Some memberFlags -> memberFlags.MemberKind = MemberKind.Constructor)
+
+ GeneralizationHelpers.CheckDeclaredTyparsPermitted(memFlagsOpt, declaredTypars, m)
+ let canInferTypars = CanInferExtraGeneralizedTyparsForRecBinding pgrbind
+
+ let tau = vspec.TauType
+ let maxInferredTypars = freeInTypeLeftToRight cenv.g false tau
+
+ let canGeneralizeConstrained = GeneralizationHelpers.CanGeneralizeConstrainedTyparsForDecl rbinfo.DeclKind
+ let generalizedTypars = GeneralizationHelpers.ComputeAndGeneralizeGenericTypars (cenv, denv, m, freeInEnv, canInferTypars, canGeneralizeConstrained, inlineFlag, Some expr, allDeclaredTypars, maxInferredTypars, tau, isCtor)
+ generalizedTypars
+
+/// Compute the type variables which may have member constraints that need to be canonicalized prior to generalization
+and TcLetrecComputeSupportForBinding cenv (pgrbind: PreGeneralizationRecursiveBinding) =
+ let rbinfo = pgrbind.RecBindingInfo
+ let allDeclaredTypars = rbinfo.EnclosingDeclaredTypars @ rbinfo.DeclaredTypars
+ let maxInferredTypars = freeInTypeLeftToRight cenv.g false rbinfo.Val.TauType
+ allDeclaredTypars @ maxInferredTypars
+
+//-------------------------------------------------------------------------
+// TcLetrecGeneralizeBinding
+//------------------------------------------------------------------------
+
+// Generalise generalizedTypars from checkedBind.
+and TcLetrecGeneralizeBinding cenv denv generalizedTypars (pgrbind: PreGeneralizationRecursiveBinding) : PostGeneralizationRecursiveBinding =
+
+ let (RecursiveBindingInfo(_, _, enclosingDeclaredTypars, _, vspec, explicitTyparInfo, partialValReprInfo, memberInfoOpt, _, _, _, vis, _, declKind)) = pgrbind.RecBindingInfo
+ let (CheckedBindingInfo(inlineFlag, _, _, _, _, _, expr, argAttribs, _, _, _, compgen, _, isFixed)) = pgrbind.CheckedBinding
+
+ if isFixed then
+ errorR(Error(FSComp.SR.tcFixedNotAllowed(), expr.Range))
+
+ let _, tau = vspec.TypeScheme
+
+ let pvalscheme1 = PrelimValScheme1(vspec.Id, explicitTyparInfo, tau, Some partialValReprInfo, memberInfoOpt, false, inlineFlag, NormalVal, argAttribs, vis, compgen)
+ let pvalscheme2 = GeneralizeVal cenv denv enclosingDeclaredTypars generalizedTypars pvalscheme1
+
+ let valscheme = UseCombinedArity cenv.g declKind expr pvalscheme2
+ AdjustRecType vspec valscheme
+
+ { ValScheme = valscheme
+ CheckedBinding = pgrbind.CheckedBinding
+ RecBindingInfo = pgrbind.RecBindingInfo }
+
+
+and TcLetrecComputeCtorSafeThisValBind cenv safeThisValOpt =
+ match safeThisValOpt with
+ | None -> None
+ | Some (v: Val) ->
+ let m = v.Range
+ let ty = destRefCellTy cenv.g v.Type
+ Some (mkCompGenBind v (mkRefCell cenv.g m ty (mkNull m ty)))
+
+and MakeCheckSafeInitField g tinst thisValOpt rfref reqExpr (expr: Expr) =
+ let m = expr.Range
+ let availExpr =
+ match thisValOpt with
+ | None -> mkStaticRecdFieldGet (rfref, tinst, m)
+ | Some thisVar ->
+ // This is an instance method, it must have a 'this' var
+ mkRecdFieldGetViaExprAddr (exprForVal m thisVar, rfref, tinst, m)
+ let failureExpr = match thisValOpt with None -> mkCallFailStaticInit g m | Some _ -> mkCallFailInit g m
+ mkCompGenSequential m (mkIfThen g m (mkILAsmClt g m availExpr reqExpr) failureExpr) expr
+
+and MakeCheckSafeInit g tinst safeInitInfo reqExpr expr =
+ match safeInitInfo with
+ | SafeInitField (rfref, _) -> MakeCheckSafeInitField g tinst None rfref reqExpr expr
+ | NoSafeInitInfo -> expr
+
+// Given a method binding (after generalization)
+//
+// method M = (fun -> )
+//
+// wrap the following around it if needed
+//
+// method M = (fun baseVal ->
+// check ctorSafeInitInfo
+// let ctorSafeThisVal = ref null
+// )
+//
+// The "check ctorSafeInitInfo" is only added for non-constructor instance members in a class where at least one type in the
+// hierarchy has HasSelfReferentialConstructor
+//
+// The "let ctorSafeThisVal = ref null" is only added for explicit constructors with a self-reference parameter (Note: check later code for exact conditions)
+// For implicit constructors the binding is added to the bindings of the implicit constructor
+
+and TcLetrecAdjustMemberForSpecialVals cenv (pgrbind: PostGeneralizationRecursiveBinding) : PostSpecialValsRecursiveBinding =
+
+ let (RecursiveBindingInfo(_, _, _, _, vspec, _, _, _, baseValOpt, safeThisValOpt, safeInitInfo, _, _, _)) = pgrbind.RecBindingInfo
+ let expr = pgrbind.CheckedBinding.Expr
+ let spBind = pgrbind.CheckedBinding.SeqPoint
+
+ let expr =
+ match TcLetrecComputeCtorSafeThisValBind cenv safeThisValOpt with
+ | None -> expr
+ | Some bind ->
+ let m = expr.Range
+ let tps, vsl, body, returnTy = stripTopLambda (expr, vspec.Type)
+ mkMultiLambdas m tps vsl (mkLetBind m bind body, returnTy)
+
+ // Add a call to CheckInit if necessary for instance members
+ let expr =
+ if vspec.IsInstanceMember && not vspec.IsExtensionMember && not vspec.IsConstructor then
+ match safeInitInfo with
+ | SafeInitField (rfref, _) ->
+ let m = expr.Range
+ let tps, vsl, body, returnTy = stripTopLambda (expr, vspec.Type)
+ // This is an instance member, it must have a 'this'
+ let thisVar = vsl.Head.Head
+ let thisTypeInst = argsOfAppTy cenv.g thisVar.Type
+ let newBody = MakeCheckSafeInitField cenv.g thisTypeInst (Some thisVar) rfref (mkOne cenv.g m) body
+ mkMultiLambdas m tps vsl (newBody, returnTy)
+ | NoSafeInitInfo ->
+ expr
+
+ else
+ expr
+
+ let expr =
+ match baseValOpt with
+ | None -> expr
+ | _ ->
+ let m = expr.Range
+ let tps, vsl, body, returnTy = stripTopLambda (expr, vspec.Type)
+ mkMemberLambdas m tps None baseValOpt vsl (body, returnTy)
+
+ { ValScheme = pgrbind.ValScheme
+ Binding = TBind(vspec, expr, spBind) }
+
+and FixupLetrecBind cenv denv generalizedTyparsForRecursiveBlock (bind: PostSpecialValsRecursiveBinding) =
+ let (TBind(vspec, expr, spBind)) = bind.Binding
+
+ // Check coherence of generalization of variables for memberInfo members in generic classes
+ match vspec.MemberInfo with
+#if EXTENDED_EXTENSION_MEMBERS // indicates if extension members can add additional constraints to type parameters
+ | Some _ when not vspec.IsExtensionMember ->
+#else
+ | Some _ ->
+#endif
+ match PartitionValTyparsForApparentEnclosingType cenv.g vspec with
+ | Some(parentTypars, memberParentTypars, _, _, _) ->
+ ignore(SignatureConformance.Checker(cenv.g, cenv.amap, denv, SignatureRepackageInfo.Empty, false).CheckTypars vspec.Range TypeEquivEnv.Empty memberParentTypars parentTypars)
+ | None ->
+ errorR(Error(FSComp.SR.tcMemberIsNotSufficientlyGeneric(), vspec.Range))
+ | _ -> ()
+
+ // Fixup recursive references...
+ let fixupPoints = GetAllUsesOfRecValue cenv vspec
+
+ AdjustAndForgetUsesOfRecValue cenv (mkLocalValRef vspec) bind.ValScheme
+
+ let expr = mkGenericBindRhs cenv.g vspec.Range generalizedTyparsForRecursiveBlock bind.ValScheme.TypeScheme expr
+
+ { FixupPoints = fixupPoints
+ Binding = TBind(vspec, expr, spBind) }
+
+//-------------------------------------------------------------------------
+// TcLetrec - for both expressions and class-let-rec-declarations
+//------------------------------------------------------------------------
+
+and unionGeneralizedTypars typarSets = List.foldBack (ListSet.unionFavourRight typarEq) typarSets []
+
+and TcLetrec overridesOK cenv env tpenv (binds, bindsm, scopem) =
+
+ // Create prelimRecValues for the recursive items (includes type info from LHS of bindings) *)
+ let binds = binds |> List.map (fun (RecDefnBindingInfo(a, b, c, bind)) -> NormalizedRecBindingDefn(a, b, c, BindingNormalization.NormalizeBinding ValOrMemberBinding cenv env bind))
+ let uncheckedRecBinds, prelimRecValues, (tpenv, _) = AnalyzeAndMakeAndPublishRecursiveValues overridesOK cenv env tpenv binds
+
+ let envRec = AddLocalVals cenv.tcSink scopem prelimRecValues env
+
+ // Typecheck bindings
+ let uncheckedRecBindsTable = uncheckedRecBinds |> List.map (fun rbind -> rbind.RecBindingInfo.Val.Stamp, rbind) |> Map.ofList
+
+ let (_, generalizedRecBinds, preGeneralizationRecBinds, tpenv, _) =
+ ((env, [], [], tpenv, uncheckedRecBindsTable), uncheckedRecBinds) ||> List.fold (TcLetrecBinding (cenv, envRec, scopem, [], None))
+
+ // There should be no bindings that have not been generalized since checking the vary last binding always
+ // results in the generalization of all remaining ungeneralized bindings, since there are no remaining unchecked bindings
+ // to prevent the generalization
+ assert preGeneralizationRecBinds.IsEmpty
+
+ let generalizedRecBinds = generalizedRecBinds |> List.sortBy (fun pgrbind -> pgrbind.RecBindingInfo.Index)
+ let generalizedTyparsForRecursiveBlock =
+ generalizedRecBinds
+ |> List.map (fun pgrbind -> pgrbind.GeneralizedTypars)
+ |> unionGeneralizedTypars
+
+
+ let vxbinds = generalizedRecBinds |> List.map (TcLetrecAdjustMemberForSpecialVals cenv)
+
+ // Now that we know what we've generalized we can adjust the recursive references
+ let vxbinds = vxbinds |> List.map (FixupLetrecBind cenv env.DisplayEnv generalizedTyparsForRecursiveBlock)
+
+ // Now eliminate any initialization graphs
+ let binds =
+ let bindsWithoutLaziness = vxbinds
+ let mustHaveArity =
+ match uncheckedRecBinds with
+ | [] -> false
+ | (rbind :: _) -> DeclKind.MustHaveArity rbind.RecBindingInfo.DeclKind
+
+ let results =
+ EliminateInitializationGraphs
+ cenv.g mustHaveArity env.DisplayEnv
+ bindsWithoutLaziness
+ //(fun
+ (fun doBindings bindings -> doBindings bindings)
+ (fun bindings -> bindings)
+ (fun doBindings bindings -> [doBindings bindings])
+ bindsm
+ List.concat results
+
+ // Post letrec env
+ let envbody = AddLocalVals cenv.tcSink scopem prelimRecValues env
+ binds, envbody, tpenv
+
+//-------------------------------------------------------------------------
+// Bind specifications of values
+//-------------------------------------------------------------------------
+
+let TcAndPublishValSpec (cenv, env, containerInfo: ContainerInfo, declKind, memFlagsOpt, tpenv, valSpfn) =
+
+ let (ValSpfn (Attributes synAttrs, _, SynValTyparDecls (synTypars, synCanInferTypars, _), _, _, isInline, mutableFlag, doc, vis, literalExprOpt, m)) = valSpfn
+
+ GeneralizationHelpers.CheckDeclaredTyparsPermitted(memFlagsOpt, synTypars, m)
+ let canInferTypars = GeneralizationHelpers.ComputeCanInferExtraGeneralizableTypars (containerInfo.ParentRef, synCanInferTypars, memFlagsOpt)
+
+ let attrTgt = DeclKind.AllowedAttribTargets memFlagsOpt declKind
+
+ let attrs = TcAttributes cenv env attrTgt synAttrs
+ let newOk = if canInferTypars then NewTyparsOK else NoNewTypars
+
+ let valinfos, tpenv = TcValSpec cenv env declKind newOk containerInfo memFlagsOpt None tpenv valSpfn attrs
+ let denv = env.DisplayEnv
+
+ (tpenv, valinfos) ||> List.mapFold (fun tpenv valSpecResult ->
+
+ let (ValSpecResult (altActualParent, memberInfoOpt, id, enclosingDeclaredTypars, declaredTypars, ty, partialValReprInfo, declKind)) = valSpecResult
+
+ let inlineFlag = ComputeInlineFlag (memberInfoOpt |> Option.map (fun (PreValMemberInfo(memberInfo, _, _)) -> memberInfo.MemberFlags)) isInline mutableFlag m
+
+ let freeInType = freeInTypeLeftToRight cenv.g false ty
+
+ let allDeclaredTypars = enclosingDeclaredTypars @ declaredTypars
+
+ let explicitTyparInfo = ExplicitTyparInfo(declaredTypars, declaredTypars, synCanInferTypars)
+
+ let generalizedTypars =
+ GeneralizationHelpers.ComputeAndGeneralizeGenericTypars(cenv, denv, id.idRange,
+ emptyFreeTypars, canInferTypars, CanGeneralizeConstrainedTypars, inlineFlag,
+ None, allDeclaredTypars, freeInType, ty, false)
+
+ let valscheme1 = PrelimValScheme1(id, explicitTyparInfo, ty, Some partialValReprInfo, memberInfoOpt, mutableFlag, inlineFlag, NormalVal, noArgOrRetAttribs, vis, false)
+
+ let valscheme2 = GeneralizeVal cenv denv enclosingDeclaredTypars generalizedTypars valscheme1
+
+ let tpenv = HideUnscopedTypars generalizedTypars tpenv
+
+ let valscheme = BuildValScheme declKind (Some partialValReprInfo) valscheme2
+
+ let literalValue =
+ match literalExprOpt with
+ | None ->
+ let hasLiteralAttr = HasFSharpAttribute cenv.g cenv.g.attrib_LiteralAttribute attrs
+ if hasLiteralAttr then
+ errorR(Error(FSComp.SR.tcLiteralAttributeRequiresConstantValue(), m))
+ None
+
+ | Some e ->
+ let hasLiteralAttr, literalValue = TcLiteral cenv ty env tpenv (attrs, e)
+ if not hasLiteralAttr then
+ errorR(Error(FSComp.SR.tcValueInSignatureRequiresLiteralAttribute(), e.Range))
+ literalValue
+
+ let paramNames =
+ match valscheme.ValReprInfo with
+ | None -> None
+ | Some topValInfo -> topValInfo.ArgNames
+
+ let doc = doc.ToXmlDoc(true, paramNames)
+ let vspec = MakeAndPublishVal cenv env (altActualParent, true, declKind, ValNotInRecScope, valscheme, attrs, doc, literalValue, false)
+ assert(vspec.InlineInfo = inlineFlag)
+
+ vspec, tpenv)
+
diff --git a/src/fsharp/CheckExpressions.fsi b/src/fsharp/CheckExpressions.fsi
new file mode 100644
index 00000000000..06a135f3111
--- /dev/null
+++ b/src/fsharp/CheckExpressions.fsi
@@ -0,0 +1,783 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+module internal FSharp.Compiler.CheckExpressions
+
+open System
+open FSharp.Compiler
+open FSharp.Compiler.AbstractIL.IL
+open FSharp.Compiler.AbstractIL.Internal
+open FSharp.Compiler.AbstractIL.Internal.Library
+open FSharp.Compiler.AccessibilityLogic
+open FSharp.Compiler.CompilerGlobalState
+open FSharp.Compiler.ConstraintSolver
+open FSharp.Compiler.Import
+open FSharp.Compiler.InfoReader
+open FSharp.Compiler.Infos
+open FSharp.Compiler.MethodOverrides
+open FSharp.Compiler.NameResolution
+open FSharp.Compiler.PatternMatchCompilation
+open FSharp.Compiler.SyntaxTree
+open FSharp.Compiler.SyntaxTreeOps
+open FSharp.Compiler.XmlDoc
+open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.Text
+open FSharp.Compiler.TypedTree
+open FSharp.Compiler.TypedTreeOps
+
+#if !NO_EXTENSIONTYPING
+open FSharp.Compiler.ExtensionTyping
+#endif
+
+/// Represents information about the initialization field used to check that object constructors
+/// have completed before fields are accessed.
+type SafeInitData =
+ | SafeInitField of RecdFieldRef * RecdField
+ | NoSafeInitInfo
+
+/// Represents information about object constructors
+[]
+type CtorInfo
+
+val InitialImplicitCtorInfo: unit -> CtorInfo
+
+/// Represents an item in the environment that may restrict the automatic generalization of later
+/// declarations because it refers to type inference variables. As type inference progresses
+/// these type inference variables may get solved.
+[]
+type UngeneralizableItem
+
+[]
+/// Represents the type environment at a particular scope. Includes the name
+/// resolution environment, the ungeneralizable items from earlier in the scope
+/// and other information about the scope.
+type TcEnv =
+ { /// Name resolution information
+ eNameResEnv: NameResolutionEnv
+
+ /// The list of items in the environment that may contain free inference
+ /// variables (which may not be generalized). The relevant types may
+ /// change as a result of inference equations being asserted, hence may need to
+ /// be recomputed.
+ eUngeneralizableItems: UngeneralizableItem list
+
+ // Two (!) versions of the current module path
+ // These are used to:
+ // - Look up the appropriate point in the corresponding signature
+ // see if an item is public or not
+ // - Change fslib canonical module type to allow compiler references to these items
+ // - Record the cpath for concrete modul_specs, tycon_specs and excon_specs so they can cache their generated IL representation where necessary
+ // - Record the pubpath of public, concrete {val, tycon, modul, excon}_specs.
+ // This information is used mainly when building non-local references
+ // to public items.
+ //
+ // Of the two, 'ePath' is the one that's barely used. It's only
+ // used by UpdateAccModuleOrNamespaceType to modify the CCU while compiling FSharp.Core
+ ePath: Ident list
+
+ eCompPath: CompilationPath
+
+ eAccessPath: CompilationPath
+
+ /// This field is computed from other fields, but we amortize the cost of computing it.
+ eAccessRights: AccessorDomain
+
+ /// Internals under these should be accessible
+ eInternalsVisibleCompPaths: CompilationPath list
+
+ /// Mutable accumulator for the current module type
+ eModuleOrNamespaceTypeAccumulator: ModuleOrNamespaceType ref
+
+ /// Context information for type checker
+ eContextInfo: ContextInfo
+
+ /// Here Some tcref indicates we can access protected members in all super types
+ eFamilyType: TyconRef option
+
+ // Information to enforce special restrictions on valid expressions
+ // for .NET constructors.
+ eCtorInfo: CtorInfo option
+
+ eCallerMemberName: string option
+ }
+
+ member DisplayEnv : DisplayEnv
+ member NameEnv : NameResolution.NameResolutionEnv
+ member AccessRights : AccessorDomain
+
+//-------------------------------------------------------------------------
+// Some of the exceptions arising from type checking. These should be moved to
+// use ErrorLogger.
+//-------------------------------------------------------------------------
+
+exception BakedInMemberConstraintName of string * range
+exception FunctionExpected of DisplayEnv * TType * range
+exception NotAFunction of DisplayEnv * TType * range * range
+exception NotAFunctionButIndexer of DisplayEnv * TType * string option * range * range
+exception Recursion of DisplayEnv * Ident * TType * TType * range
+exception RecursiveUseCheckedAtRuntime of DisplayEnv * ValRef * range
+exception LetRecEvaluatedOutOfOrder of DisplayEnv * ValRef * ValRef * range
+exception LetRecCheckedAtRuntime of range
+exception LetRecUnsound of DisplayEnv * ValRef list * range
+exception TyconBadArgs of DisplayEnv * TyconRef * int * range
+exception UnionCaseWrongArguments of DisplayEnv * int * int * range
+exception UnionCaseWrongNumberOfArgs of DisplayEnv * int * int * range
+exception FieldsFromDifferentTypes of DisplayEnv * RecdFieldRef * RecdFieldRef * range
+exception FieldGivenTwice of DisplayEnv * RecdFieldRef * range
+exception MissingFields of string list * range
+exception UnitTypeExpected of DisplayEnv * TType * range
+exception UnitTypeExpectedWithEquality of DisplayEnv * TType * range
+exception UnitTypeExpectedWithPossiblePropertySetter of DisplayEnv * TType * string * string * range
+exception UnitTypeExpectedWithPossibleAssignment of DisplayEnv * TType * bool * string * range
+exception FunctionValueUnexpected of DisplayEnv * TType * range
+exception UnionPatternsBindDifferentNames of range
+exception VarBoundTwice of Ident
+exception ValueRestriction of DisplayEnv * bool * Val * Typar * range
+exception ValNotMutable of DisplayEnv * ValRef * range
+exception ValNotLocal of DisplayEnv * ValRef * range
+exception InvalidRuntimeCoercion of DisplayEnv * TType * TType * range
+exception IndeterminateRuntimeCoercion of DisplayEnv * TType * TType * range
+exception IndeterminateStaticCoercion of DisplayEnv * TType * TType * range
+exception StaticCoercionShouldUseBox of DisplayEnv * TType * TType * range
+exception RuntimeCoercionSourceSealed of DisplayEnv * TType * range
+exception CoercionTargetSealed of DisplayEnv * TType * range
+exception UpcastUnnecessary of range
+exception TypeTestUnnecessary of range
+exception SelfRefObjCtor of bool * range
+exception VirtualAugmentationOnNullValuedType of range
+exception NonVirtualAugmentationOnNullValuedType of range
+exception UseOfAddressOfOperator of range
+exception DeprecatedThreadStaticBindingWarning of range
+exception IntfImplInIntrinsicAugmentation of range
+exception IntfImplInExtrinsicAugmentation of range
+exception OverrideInIntrinsicAugmentation of range
+exception OverrideInExtrinsicAugmentation of range
+exception NonUniqueInferredAbstractSlot of TcGlobals * DisplayEnv * string * MethInfo * MethInfo * range
+exception StandardOperatorRedefinitionWarning of string * range
+exception InvalidInternalsVisibleToAssemblyName of (*badName*)string * (*fileName option*) string option
+
+val TcFieldInit : range -> ILFieldInit -> Const
+
+val LightweightTcValForUsingInBuildMethodCall : g : TcGlobals -> vref:ValRef -> vrefFlags : ValUseFlag -> vrefTypeInst : TTypes -> m : range -> Expr * TType
+
+//-------------------------------------------------------------------------
+// The rest are all helpers needed for declaration checking (CheckDeclarations.fs)
+//-------------------------------------------------------------------------
+
+/// Represents the current environment of type variables that have implicit scope
+/// (i.e. are without explicit declaration).
+type UnscopedTyparEnv
+
+/// Represents the compilation environment for typechecking a single file in an assembly.
+[]
+type TcFileState =
+ { g: TcGlobals
+
+ /// Push an entry every time a recursive value binding is used,
+ /// in order to be able to fix up recursive type applications as
+ /// we infer type parameters
+ mutable recUses: ValMultiMap<(Expr ref * range * bool)>
+
+ /// Checks to run after all inference is complete.
+ mutable postInferenceChecks: ResizeArray unit>
+
+ /// Set to true if this file causes the creation of generated provided types.
+ mutable createsGeneratedProvidedTypes: bool
+
+ /// Are we in a script? if so relax the reporting of discarded-expression warnings at the top level
+ isScript: bool
+
+ /// Environment needed to convert IL types to F# types in the importer.
+ amap: Import.ImportMap
+
+ /// Used to generate new syntactic argument names in post-parse syntactic processing
+ synArgNameGenerator: SynArgNameGenerator
+
+ tcSink: TcResultsSink
+
+ /// Holds a reference to the component being compiled.
+ /// This field is very rarely used (mainly when fixing up forward references to fslib.
+ topCcu: CcuThunk
+
+ /// Holds the current inference constraints
+ css: ConstraintSolverState
+
+ /// Are we compiling the signature of a module from fslib?
+ compilingCanonicalFslibModuleType: bool
+
+ /// Is this a .fsi file?
+ isSig: bool
+
+ /// Does this .fs file have a .fsi file?
+ haveSig: bool
+
+ /// Used to generate names
+ niceNameGen: NiceNameGenerator
+
+ /// Used to read and cache information about types and members
+ infoReader: InfoReader
+
+ /// Used to resolve names
+ nameResolver: NameResolver
+
+ /// The set of active conditional defines. The value is None when conditional erasure is disabled in tooling.
+ conditionalDefines: string list option
+
+ isInternalTestSpanStackReferring: bool
+ // forward call
+ TcSequenceExpressionEntry: TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> bool * bool ref * SynExpr -> range -> Expr * UnscopedTyparEnv
+ // forward call
+ TcArrayOrListSequenceExpression: TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> bool * SynExpr -> range -> Expr * UnscopedTyparEnv
+ // forward call
+ TcComputationExpression: TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv
+ }
+ static member Create:
+ g: TcGlobals *
+ isScript: bool *
+ niceNameGen: NiceNameGenerator *
+ amap: ImportMap *
+ topCcu: CcuThunk *
+ isSig: bool *
+ haveSig: bool *
+ conditionalDefines: string list option *
+ tcSink: TcResultsSink *
+ tcVal: TcValF *
+ isInternalTestSpanStackReferring: bool *
+ // forward call to CheckComputationExpressions.fs
+ tcSequenceExpressionEntry: (TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> bool * bool ref * SynExpr -> range -> Expr * UnscopedTyparEnv) *
+ // forward call to CheckComputationExpressions.fs
+ tcArrayOrListSequenceExpression: (TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> bool * SynExpr -> range -> Expr * UnscopedTyparEnv) *
+ // forward call to CheckComputationExpressions.fs
+ tcComputationExpression: (TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv)
+ -> TcFileState
+
+/// Represents information about the module or type in which a member or value is declared.
+type MemberOrValContainerInfo =
+ | MemberOrValContainerInfo of
+ tcref: TyconRef *
+ optIntfSlotTy: (TType * SlotImplSet) option *
+ baseValOpt: Val option *
+ safeInitInfo: SafeInitData *
+ declaredTyconTypars: Typars
+
+/// Provides information about the context for a value or member definition.
+type ContainerInfo =
+ | ContainerInfo of
+ ParentRef *
+ MemberOrValContainerInfo option
+ member ParentRef : ParentRef
+
+val ExprContainerInfo: ContainerInfo
+
+/// Indicates if member declarations are allowed to be abstract members.
+type NewSlotsOK =
+ | NewSlotsOK
+ | NoNewSlots
+
+/// Indicates if member declarations are allowed to be override members.
+type OverridesOK =
+ | OverridesOK
+ | WarnOnOverrides
+ | ErrorOnOverrides
+
+/// A flag to represent the sort of bindings are we processing.
+type DeclKind =
+ /// A binding in a module, or a member
+ | ModuleOrMemberBinding
+
+ /// Extensions to a type within the same assembly
+ | IntrinsicExtensionBinding
+
+ /// Extensions to a type in a different assembly
+ | ExtrinsicExtensionBinding
+
+ /// A binding in a class
+ | ClassLetBinding of isStatic: bool
+
+ /// A binding in an object expression
+ | ObjectExpressionOverrideBinding
+
+ /// A binding in an expression
+ | ExpressionBinding
+
+ static member IsModuleOrMemberOrExtensionBinding: DeclKind -> bool
+
+ static member MustHaveArity: DeclKind -> bool
+
+ member CanBeDllImport: bool
+
+ static member IsAccessModifierPermitted: DeclKind -> bool
+
+ static member ImplicitlyStatic: DeclKind -> bool
+
+ static member AllowedAttribTargets: MemberFlags option -> DeclKind -> AttributeTargets
+
+ // Note: now always true
+ static member CanGeneralizeConstrainedTypars: DeclKind -> bool
+
+ static member ConvertToLinearBindings: DeclKind -> bool
+
+ static member CanOverrideOrImplement: DeclKind -> OverridesOK
+
+/// Indicates whether a syntactic type is allowed to include new type variables
+/// not declared anywhere, e.g. `let f (x: 'T option) = x.Value`
+type ImplicitlyBoundTyparsAllowed =
+ | NewTyparsOKButWarnIfNotRigid
+ | NewTyparsOK
+ | NoNewTypars
+
+/// Indicates whether constraints should be checked when checking syntactic types
+type CheckConstraints =
+ | CheckCxs
+ | NoCheckCxs
+
+/// Indicates if a member binding is an object expression binding
+type IsObjExprBinding =
+ | ObjExprBinding
+ | ValOrMemberBinding
+
+/// Represents the initial information about a recursive binding
+type RecDefnBindingInfo =
+ | RecDefnBindingInfo of
+ containerInfo: ContainerInfo *
+ newslotsOk: NewSlotsOK *
+ declKind: DeclKind *
+ synBinding: SynBinding
+
+/// Represents the ValReprInfo for a value, before the typars are fully inferred
+type PartialValReprInfo =
+ | PartialValReprInfo of
+ curriedArgInfos: ArgReprInfo list list *
+ returnInfo: ArgReprInfo
+
+/// Holds the initial ValMemberInfo and other information before it is fully completed
+type PreValMemberInfo =
+ | PreValMemberInfo of
+ memberInfo: ValMemberInfo *
+ logicalName: string *
+ compiledName: string
+
+/// The result of checking a value or member signature
+type ValSpecResult =
+ | ValSpecResult of
+ altActualParent: ParentRef *
+ memberInfoOpt: PreValMemberInfo option *
+ id: Ident *
+ enclosingDeclaredTypars: Typars *
+ declaredTypars: Typars *
+ ty: TType *
+ partialValReprInfo: PartialValReprInfo *
+ declKind: DeclKind
+
+/// An empty environment of type variables with implicit scope
+val emptyUnscopedTyparEnv: UnscopedTyparEnv
+
+/// A type to represent information associated with values to indicate what explicit (declared) type parameters
+/// are given and what additional type parameters can be inferred, if any.
+///
+/// The declared type parameters, e.g. let f<'a> (x:'a) = x, plus an indication
+/// of whether additional polymorphism may be inferred, e.g. let f<'a, ..> (x:'a) y = x
+type ExplicitTyparInfo =
+ | ExplicitTyparInfo of
+ rigidCopyOfDeclaredTypars: Typars *
+ declaredTypars: Typars *
+ infer: bool
+
+/// NormalizedBindingRhs records the r.h.s. of a binding after some munging just before type checking.
+type NormalizedBindingRhs =
+ | NormalizedBindingRhs of
+ simplePats: SynSimplePats list *
+ returnTyOpt: SynBindingReturnInfo option *
+ rhsExpr: SynExpr
+
+/// Represents a syntactic, unchecked binding after the resolution of the name resolution status of pattern
+/// constructors and after "pushing" all complex patterns to the right hand side.
+type NormalizedBinding =
+ | NormalizedBinding of
+ visibility: SynAccess option *
+ kind: SynBindingKind *
+ mustInline: bool *
+ isMutable: bool *
+ attribs: SynAttribute list *
+ xmlDoc: XmlDoc *
+ typars: SynValTyparDecls *
+ valSynData: SynValData *
+ pat: SynPat *
+ rhsExpr: NormalizedBindingRhs *
+ mBinding: range *
+ spBinding: DebugPointForBinding
+
+/// RecursiveBindingInfo - flows through initial steps of TcLetrec
+type RecursiveBindingInfo =
+ | RecursiveBindingInfo of
+ recBindIndex: int * // index of the binding in the recursive group
+ containerInfo: ContainerInfo *
+ enclosingDeclaredTypars: Typars *
+ inlineFlag: ValInline *
+ vspec: Val *
+ explicitTyparInfo: ExplicitTyparInfo *
+ partialValReprInfo: PartialValReprInfo *
+ memberInfoOpt: PreValMemberInfo option *
+ baseValOpt: Val option *
+ safeThisValOpt: Val option *
+ safeInitInfo: SafeInitData *
+ visibility: SynAccess option *
+ ty: TType *
+ declKind: DeclKind
+ member Val: Val
+ member EnclosingDeclaredTypars: Typar list
+ member Index: int
+
+/// Represents the results of the first phase of preparing simple values from a pattern
+[]
+type PrelimValScheme1 =
+ member Ident: Ident
+ member Type: TType
+
+/// Represents the results of the first phase of preparing bindings
+[]
+type CheckedBindingInfo
+
+/// Represnts the results of the second phase of checking simple values
+type ValScheme =
+ | ValScheme of
+ id: Ident *
+ typeScheme: TypeScheme *
+ topValInfo: ValReprInfo option *
+ memberInfo: PreValMemberInfo option *
+ isMutable: bool *
+ inlineInfo: ValInline *
+ baseOrThisInfo: ValBaseOrThisInfo *
+ visibility: SynAccess option *
+ compgen: bool *
+ isIncrClass: bool *
+ isTyFunc: bool *
+ hasDeclaredTypars: bool
+
+/// Represents a recursive binding after it has been normalized but before it's info has been put together
+type NormalizedRecBindingDefn =
+ | NormalizedRecBindingDefn of
+ containerInfo: ContainerInfo *
+ newslotsOk: NewSlotsOK *
+ declKind: DeclKind *
+ binding: NormalizedBinding
+
+/// Represents a recursive binding after it has been normalized but before it has been checked
+type PreCheckingRecursiveBinding =
+ { SyntacticBinding: NormalizedBinding
+ RecBindingInfo: RecursiveBindingInfo }
+
+/// Represents a recursive binding after it has been checked but prior to generalization
+type PreGeneralizationRecursiveBinding =
+ { ExtraGeneralizableTypars: Typars
+ CheckedBinding: CheckedBindingInfo
+ RecBindingInfo: RecursiveBindingInfo }
+
+/// Represents the usage points of a recursive binding that need later adjustment once the
+/// type of the member of value is fully inferred.
+[]
+type RecursiveUseFixupPoints
+
+/// Represents a recursive binding after it has been both checked and generalized
+type PostGeneralizationRecursiveBinding =
+ { ValScheme: ValScheme
+ CheckedBinding: CheckedBindingInfo
+ RecBindingInfo: RecursiveBindingInfo }
+ member GeneralizedTypars: Typar list
+
+/// Represents a recursive binding after it has been both checked and generalized and after
+/// the special adjustments for 'as this' class initialization checks have been inserted into members.
+type PostSpecialValsRecursiveBinding =
+ { ValScheme: ValScheme
+ Binding: Binding }
+
+/// Represents a recursive binding after it has been both checked and generalized, but
+/// before initialization recursion has been rewritten
+type PreInitializationGraphEliminationBinding =
+ { FixupPoints: RecursiveUseFixupPoints
+ Binding: Binding }
+
+/// Record the entire contents of a module or namespace type as not-generalizable, that is
+/// if any type variables occur free in the module or namespace type (because type inference
+/// is not yet complete), then they can't be generalized.
+val addFreeItemOfModuleTy: ModuleOrNamespaceType -> UngeneralizableItem list -> UngeneralizableItem list
+
+/// Merge together lists of type variables to generalize, keeping canonical order
+val unionGeneralizedTypars: typarSets:Typar list list -> Typar list
+
+/// Add a list of explicitly declared type variables to the environment, producing a new environment
+val AddDeclaredTypars: check: CheckForDuplicateTyparFlag -> typars: Typar list -> env: TcEnv -> TcEnv
+
+/// Add a value to the environment, producing a new environment. Report to the sink.
+val AddLocalVal: NameResolution.TcResultsSink -> scopem: range -> v: Val -> TcEnv -> TcEnv
+
+/// Add a value to the environment, producing a new environment
+val AddLocalValPrimitive: v: Val -> TcEnv -> TcEnv
+
+/// Add a list of values to the environment, producing a new environment. Report to the sink.
+val AddLocalVals: tcSink: TcResultsSink -> scopem: range -> vals: Val list -> env: TcEnv -> TcEnv
+
+/// Set the type of a 'Val' after it has been fully inferred.
+val AdjustRecType: vspec: Val -> vscheme: ValScheme -> unit
+
+/// Process a normalized recursive binding and prepare for progressive generalization
+val AnalyzeAndMakeAndPublishRecursiveValue: overridesOK:OverridesOK -> isGeneratedEventVal:bool -> cenv:TcFileState -> env:TcEnv -> tpenv:UnscopedTyparEnv * recBindIdx:int -> NormalizedRecBindingDefn -> (PreCheckingRecursiveBinding list * Val list) * (UnscopedTyparEnv * int)
+
+/// Check that a member can be included in an interface
+val CheckForNonAbstractInterface: declKind:DeclKind -> tcref:TyconRef -> memberFlags:MemberFlags -> m:range -> unit
+
+/// Check the flags on a member definition for consistency
+val CheckMemberFlags: optIntfSlotTy:'a option -> newslotsOK:NewSlotsOK -> overridesOK:OverridesOK -> memberFlags:MemberFlags -> m:range -> unit
+
+/// Check a super type is valid
+val CheckSuperType: cenv:TcFileState -> ty:TType -> m:range -> unit
+
+/// After inference, view a set of declared type parameters in a canonical way.
+val ChooseCanonicalDeclaredTyparsAfterInference: g: TcGlobals -> denv: DisplayEnv -> declaredTypars: Typar list -> m: range -> Typar list
+
+/// After inference, view a ValSchem in a canonical way.
+val ChooseCanonicalValSchemeAfterInference: g: TcGlobals -> denv: DisplayEnv -> vscheme: ValScheme -> m: range -> ValScheme
+
+/// Check if the type annotations and inferred type information in a value give a
+/// full and complete generic type for a value. If so, enable generic recursion.
+val ComputeIsComplete: enclosingDeclaredTypars:Typar list -> declaredTypars:Typar list -> ty:TType -> bool
+
+/// Compute the available access rights from a particular location in code
+val ComputeAccessRights: eAccessPath: CompilationPath -> eInternalsVisibleCompPaths: CompilationPath list -> eFamilyType: TyconRef option -> AccessorDomain
+
+/// Compute the available access rights and module/entity compilation path for a paricular location in code
+val ComputeAccessAndCompPath: env: TcEnv -> declKindOpt:DeclKind option -> m: range -> vis: SynAccess option -> overrideVis: Accessibility option -> actualParent: ParentRef -> Accessibility * CompilationPath option
+
+/// Get the expression resulting from turning an expression into an enumerable value, e.g. at 'for' loops
+val ConvertArbitraryExprToEnumerable: cenv:TcFileState -> ty:TType -> env:TcEnv -> expr:Expr -> Expr * TType
+
+/// Invoke pattern match compilation
+val CompilePatternForMatchClauses: cenv:TcFileState -> env:TcEnv -> mExpr:range -> matchm:range -> warnOnUnused:bool -> actionOnFailure:ActionOnFailure -> inputExprOpt:Expr option -> inputTy:TType -> resultTy:TType -> tclauses:TypedMatchClause list -> Val * Expr
+
+/// Process recursive bindings so that initialization is through laziness and is checked.
+/// The bindings may be either plain 'let rec' bindings or mutually recursive nestings of modules and types.
+/// The functions must iterate the actual bindings and process them to the overall result.
+val EliminateInitializationGraphs:
+ g: TcGlobals
+ -> mustHaveArity: bool
+ -> denv: DisplayEnv
+ -> bindings: 'Binding list
+ -> iterBindings:((PreInitializationGraphEliminationBinding list -> unit) -> 'Binding list -> unit)
+ -> buildLets: (Binding list -> 'Result)
+ -> mapBindings: ((PreInitializationGraphEliminationBinding list -> Binding list) -> 'Binding list -> 'Result list)
+ -> bindsm: range
+ -> 'Result list
+
+/// Adjust a recursive binding after generalization
+val FixupLetrecBind: cenv:TcFileState -> denv:DisplayEnv -> generalizedTyparsForRecursiveBlock:Typars -> bind:PostSpecialValsRecursiveBinding -> PreInitializationGraphEliminationBinding
+
+/// Produce a fresh view of an object type, e.g. 'List' becomes 'List>' for new
+/// inference variables with the given rigidity.
+val FreshenObjectArgType: cenv: TcFileState -> m: range -> rigid: TyparRigidity -> tcref: TyconRef -> isExtrinsic: bool -> declaredTyconTypars: Typar list -> TType * Typar list * TyparInst * TType * TType
+
+/// Get the accumulated module/namespace type for the current module/namespace being processed.
+val GetCurrAccumulatedModuleOrNamespaceType: env: TcEnv -> ModuleOrNamespaceType
+
+/// Get the "this" variable from the lambda for an instance member binding
+val GetInstanceMemberThisVariable: vspec: Val * expr: Expr -> Val option
+
+/// Build the full ValReprInfo one type inference is complete.
+val InferGenericArityFromTyScheme: TypeScheme -> partialValReprInfo: PartialValReprInfo -> ValReprInfo
+
+/// Locate the environment within a particular namespace path, used to process a
+/// 'namespace' declaration.
+val LocateEnv: ccu: CcuThunk -> env: TcEnv -> enclosingNamespacePath: Ident list -> TcEnv
+
+/// Make the check for safe initialization of a member
+val MakeCheckSafeInit: g: TcGlobals -> tinst: TypeInst -> safeInitInfo: SafeInitData -> reqExpr: Expr -> expr: Expr -> Expr
+
+/// Make an initial 'Val' and publish it to the environment and mutable module type accumulator.
+val MakeAndPublishVal: cenv: TcFileState -> env: TcEnv -> altActualParent: ParentRef * inSig: bool * declKind: DeclKind * vrec: ValRecursiveScopeInfo * vscheme: ValScheme * attrs: Attribs * doc: XmlDoc * konst: Const option * isGeneratedEventVal: bool -> Val
+
+/// Make an initial 'base' value
+val MakeAndPublishBaseVal: cenv: TcFileState -> env: TcEnv -> Ident option -> TType -> Val option
+
+/// Make simple values (which are not recursive nor members)
+val MakeAndPublishSimpleVals: cenv: TcFileState -> env: TcEnv -> names: NameMap -> NameMap<(Val * TypeScheme)> * NameMap
+
+/// Make an initial implicit safe initialization value
+val MakeAndPublishSafeThisVal: cenv: TcFileState -> env: TcEnv -> thisIdOpt: Ident option -> thisTy: TType -> Val option
+
+/// Make initial information for a member value
+val MakeMemberDataAndMangledNameForMemberVal: g: TcGlobals * tcref: TyconRef * isExtrinsic: bool * attrs: Attribs * optImplSlotTys: TType list * memberFlags: MemberFlags * valSynData: SynValInfo * id: Ident * isCompGen: bool -> PreValMemberInfo
+
+/// Return a new environment suitable for processing declarations in the interior of a type definition
+val MakeInnerEnvForTyconRef: env: TcEnv -> tcref: TyconRef -> isExtrinsicExtension: bool -> TcEnv
+
+/// Return a new environment suitable for processing declarations in the interior of a module definition
+/// including creating an accumulator for the module type.
+val MakeInnerEnv: addOpenToNameEnv: bool -> env: TcEnv -> nm: Ident -> modKind: ModuleOrNamespaceKind -> TcEnv * ModuleOrNamespaceType ref
+
+/// Return a new environment suitable for processing declarations in the interior of a module definition
+/// given that the accumulator for the module type already exisits.
+val MakeInnerEnvWithAcc: addOpenToNameEnv: bool -> env: TcEnv -> nm: Ident -> mtypeAcc: ModuleOrNamespaceType ref -> modKind: ModuleOrNamespaceKind -> TcEnv
+
+/// Produce a post-generalization type scheme for a simple type where no type inference generalization
+/// is appplied.
+val NonGenericTypeScheme: ty: TType -> TypeScheme
+
+/// Publish a module definition to the module/namespace type accumulator.
+val PublishModuleDefn: cenv: TcFileState -> env: TcEnv -> mspec: ModuleOrNamespace -> unit
+
+/// Publish a type definition to the module/namespace type accumulator.
+val PublishTypeDefn: cenv: TcFileState -> env: TcEnv -> mspec: Tycon -> unit
+
+/// Publish a value definition to the module/namespace type accumulator.
+val PublishValueDefn: cenv: TcFileState -> env: TcEnv -> declKind: DeclKind -> vspec: Val -> unit
+
+/// Mark a typar as no longer being an inference type variable
+val SetTyparRigid: DisplayEnv -> range -> Typar -> unit
+
+/// Check and publish a value specification (in a signature or 'abstract' member) to the
+/// module/namespace type accumulator and return the resulting Val(s). Normally only one
+/// 'Val' results but CLI events may produce both and add_Event and _remove_Event Val.
+val TcAndPublishValSpec: cenv: TcFileState * env: TcEnv * containerInfo: ContainerInfo * declKind: DeclKind * memFlagsOpt: MemberFlags option * tpenv: UnscopedTyparEnv * valSpfn: SynValSig -> Val list * UnscopedTyparEnv
+
+/// Check a set of attributes
+val TcAttributes: cenv: TcFileState -> env: TcEnv -> attrTgt: AttributeTargets -> synAttribs: SynAttribute list -> Attrib list
+
+/// Check a set of attributes and allow failure because a later phase of type realization
+/// may successfully check the attributes (if the attribute type or its arguments is in the
+/// same recursive group)
+val TcAttributesCanFail: cenv:TcFileState -> env:TcEnv -> attrTgt:AttributeTargets -> synAttribs:SynAttribute list -> Attrib list * (unit -> Attribs)
+
+/// Check a set of attributes which can only target specific elements
+val TcAttributesWithPossibleTargets: canFail: bool -> cenv: TcFileState -> env: TcEnv -> attrTgt: AttributeTargets -> synAttribs: SynAttribute list -> (AttributeTargets * Attrib) list * bool
+
+/// Check a constant value, e.g. a literal
+val TcConst: cenv: TcFileState -> ty: TType -> m: range -> env: TcEnv -> c: SynConst -> Const
+
+/// Check a syntactic expression and convert it to a typed tree expression
+val TcExpr: cenv:TcFileState -> ty:TType -> env:TcEnv -> tpenv:UnscopedTyparEnv -> expr:SynExpr -> Expr * UnscopedTyparEnv
+
+/// Check a syntactic expression and convert it to a typed tree expression
+val TcExprOfUnknownType: cenv:TcFileState -> env:TcEnv -> tpenv:UnscopedTyparEnv -> expr:SynExpr -> Expr * TType * UnscopedTyparEnv
+
+/// Check a syntactic expression and convert it to a typed tree expression. Possibly allow for subsumption flexibility
+/// and insert a coercion if necessary.
+val TcExprFlex: cenv:TcFileState -> flex:bool -> compat:bool -> ty:TType -> env:TcEnv -> tpenv:UnscopedTyparEnv -> e:SynExpr -> Expr * UnscopedTyparEnv
+
+/// Check a syntactic statement and convert it to a typed tree expression.
+val TcStmtThatCantBeCtorBody: cenv:TcFileState -> env:TcEnv -> tpenv:UnscopedTyparEnv -> expr:SynExpr -> Expr * UnscopedTyparEnv
+
+/// Check a syntactic expression and convert it to a typed tree expression
+val TcExprUndelayed: cenv:TcFileState -> overallTy:TType -> env:TcEnv -> tpenv:UnscopedTyparEnv -> synExpr:SynExpr -> Expr * UnscopedTyparEnv
+
+/// Check a linear expression (e.g. a sequence of 'let') in a tail-recursive way
+/// and convert it to a typed tree expression, using the bodyChecker to check the parts
+/// that are not linear.
+val TcLinearExprs: bodyChecker:(TType -> TcEnv -> UnscopedTyparEnv -> SynExpr -> Expr * UnscopedTyparEnv) -> cenv:TcFileState -> env:TcEnv -> overallTy:TType -> tpenv:UnscopedTyparEnv -> isCompExpr:bool -> expr:SynExpr -> cont:(Expr * UnscopedTyparEnv -> Expr * UnscopedTyparEnv) -> Expr * UnscopedTyparEnv
+
+/// Try to check a syntactic statement and indicate if it's type is not unit without emitting a warning
+val TryTcStmt: cenv:TcFileState -> env:TcEnv -> tpenv:UnscopedTyparEnv -> synExpr:SynExpr -> bool * Expr * UnscopedTyparEnv
+
+/// Check a pattern being used as a pattern match
+val TcMatchPattern: cenv:TcFileState -> inputTy:TType -> env:TcEnv -> tpenv:UnscopedTyparEnv -> pat:SynPat * optWhenExpr:SynExpr option -> Pattern * Expr option * Val list * TcEnv * UnscopedTyparEnv
+
+val (|BinOpExpr|_|): SynExpr -> (Ident * SynExpr * SynExpr) option
+
+/// Check a set of let bindings
+val TcLetBindings: cenv:TcFileState -> env:TcEnv -> containerInfo:ContainerInfo -> declKind:DeclKind -> tpenv:UnscopedTyparEnv -> binds:SynBinding list * bindsm:range * scopem:range -> ModuleOrNamespaceExpr list * TcEnv * UnscopedTyparEnv
+
+/// Check an individual `let rec` binding
+val TcLetrecBinding: cenv:TcFileState * envRec:TcEnv * scopem:range * extraGeneralizableTypars:Typars * reqdThisValTyOpt:TType option -> envNonRec:TcEnv * generalizedRecBinds:PostGeneralizationRecursiveBinding list * preGeneralizationRecBinds:PreGeneralizationRecursiveBinding list * tpenv:UnscopedTyparEnv * uncheckedRecBindsTable:Map -> rbind:PreCheckingRecursiveBinding -> TcEnv * PostGeneralizationRecursiveBinding list * PreGeneralizationRecursiveBinding list * UnscopedTyparEnv * Map
+
+/// Get the binding for the implicit safe initialziation check value if it is being used
+val TcLetrecComputeCtorSafeThisValBind: cenv:TcFileState -> safeThisValOpt:Val option -> Binding option
+
+/// Check a collection of `let rec` bindings
+val TcLetrec: overridesOK:OverridesOK -> cenv:TcFileState -> env:TcEnv -> tpenv:UnscopedTyparEnv -> binds:RecDefnBindingInfo list * bindsm:range * scopem:range -> Bindings * TcEnv * UnscopedTyparEnv
+
+/// Part of check a collection of recursive bindings that might include members
+val TcLetrecAdjustMemberForSpecialVals: cenv: TcFileState -> pgrbind: PostGeneralizationRecursiveBinding -> PostSpecialValsRecursiveBinding
+
+/// Check an inheritance expression or other 'new XYZ()' expression
+val TcNewExpr: cenv:TcFileState -> env:TcEnv -> tpenv:UnscopedTyparEnv -> objTy:TType -> mObjTyOpt:range option -> superInit:bool -> arg:SynExpr -> mWholeExprOrObjTy:range -> Expr * UnscopedTyparEnv
+
+#if !NO_EXTENSIONTYPING
+/// Check the application of a provided type to static args
+val TcProvidedTypeAppToStaticConstantArgs: cenv:TcFileState -> env:TcEnv -> optGeneratedTypePath:string list option -> tpenv:UnscopedTyparEnv -> tcref:TyconRef -> args:SynType list -> m:range -> bool * Tainted * (unit -> unit)
+#endif
+
+/// Check a set of simple patterns, e.g. the declarations of parameters for an implicit constructor.
+val TcSimplePatsOfUnknownType: cenv: TcFileState -> optArgsOK: bool -> checkCxs: CheckConstraints -> env: TcEnv -> tpenv: UnscopedTyparEnv -> spats: SynSimplePats -> string list * (UnscopedTyparEnv * NameMap * Set)
+
+/// Check a set of explicitly declared constraints on type parameters
+val TcTyparConstraints: cenv: TcFileState -> newOk: ImplicitlyBoundTyparsAllowed -> checkCxs: CheckConstraints -> occ: ItemOccurence -> env: TcEnv -> tpenv: UnscopedTyparEnv -> synConstraints: SynTypeConstraint list -> UnscopedTyparEnv
+
+/// Check a collection of type parameters declarations
+val TcTyparDecls: cenv: TcFileState -> env: TcEnv -> synTypars: SynTyparDecl list -> Typar list
+
+/// Check a syntactic type
+val TcType: cenv: TcFileState -> newOk: ImplicitlyBoundTyparsAllowed -> checkCxs: CheckConstraints -> occ: ItemOccurence -> env: TcEnv -> tpenv: UnscopedTyparEnv -> ty: SynType -> TType * UnscopedTyparEnv
+
+/// Check a syntactic type or unit of measure
+val TcTypeOrMeasureAndRecover: optKind: TyparKind option -> cenv: TcFileState -> newOk: ImplicitlyBoundTyparsAllowed -> checkCxs: CheckConstraints -> occ: ItemOccurence -> env: TcEnv -> tpenv: UnscopedTyparEnv -> ty: SynType -> TType * UnscopedTyparEnv
+
+/// Check a syntactic type (with error recovery)
+val TcTypeAndRecover: cenv: TcFileState -> newOk: ImplicitlyBoundTyparsAllowed -> checkCxs: CheckConstraints -> occ: ItemOccurence -> env: TcEnv -> tpenv: UnscopedTyparEnv -> ty: SynType -> TType * UnscopedTyparEnv
+
+/// Check a specification of a value or member in a signature or an abstract member
+val TcValSpec: cenv: TcFileState -> TcEnv -> DeclKind -> ImplicitlyBoundTyparsAllowed -> ContainerInfo -> MemberFlags option -> thisTyOpt: TType option -> UnscopedTyparEnv -> SynValSig -> Attrib list -> ValSpecResult list * UnscopedTyparEnv
+
+/// Given the declaration of a function or member, process it to produce the ValReprInfo
+/// giving the names and attributes relevant to arguments and return, but before type
+/// parameters have been fully inferred via generalization.
+val TranslateTopValSynInfo: range -> tcAttributes: (AttributeTargets -> SynAttribute list -> Attrib list) -> synValInfo: SynValInfo -> PartialValReprInfo
+
+/// Given the declaration of a function or member, complete the processing of its ValReprInfo
+/// once type parameters have been fully inferred via generalization.
+val TranslatePartialArity: tps: Typar list -> PartialValReprInfo -> ValReprInfo
+
+/// Constrain two types to be equal within this type checking context
+val UnifyTypes : cenv:TcFileState -> env:TcEnv -> m:range -> actualTy:TType -> expectedTy:TType -> unit
+
+module GeneralizationHelpers =
+
+ /// Given an environment, compute the set of inference type variables which may not be
+ /// generalised, because they appear somewhere in the types of the constructs availabe
+ /// in the environment.
+ val ComputeUngeneralizableTypars: env: TcEnv -> Zset
+
+ /// Given an environment, compute the set of trait solutions which must appear before
+ /// the current location, not after (to prevent use-before definitiosn and
+ /// forward calls via type inference filling in trait solutions).
+ val ComputeUnabstractableTraitSolutions: env: TcEnv -> FreeLocals
+
+ /// Given an environment, compute the set of type definitions which must appear before
+ /// the current location, not after (to prevent use-before-definition of type definitions
+ /// via type inference).
+ val ComputeUnabstractableTycons: env: TcEnv -> FreeTycons
+
+// Logically extends System.AttributeTargets for F# constructs
+module AttributeTargets =
+ /// The allowed attribute targets for an F# field declaration
+ val FieldDecl: AttributeTargets
+
+ /// The allowed attribute targets for an F# field declaration once it's known to be targeting
+ /// a field not a property (see useGenuineField)
+ val FieldDeclRestricted: AttributeTargets
+
+ /// The allowed attribute targets for an F# union case declaration
+ val UnionCaseDecl: AttributeTargets
+
+ /// The allowed attribute targets for an F# type declaration
+ val TyconDecl: AttributeTargets
+
+ /// The allowed attribute targets for an F# exception declaration
+ val ExnDecl: AttributeTargets
+
+ /// The allowed attribute targets for an F# module declaration
+ val ModuleDecl: AttributeTargets
+
+ /// The allowed attribute targets for an F# top level 'do' expression
+ val Top: AttributeTargets
+
+module BindingNormalization =
+ /// Take a syntactic binding and do the very first processing step to normalize it.
+ val NormalizeBinding: isObjExprBinding: IsObjExprBinding -> cenv: TcFileState -> env: TcEnv -> binding: SynBinding -> NormalizedBinding
+
diff --git a/src/fsharp/CheckFormatStrings.fs b/src/fsharp/CheckFormatStrings.fs
index 1622a61351c..95b6306c17f 100644
--- a/src/fsharp/CheckFormatStrings.fs
+++ b/src/fsharp/CheckFormatStrings.fs
@@ -2,15 +2,18 @@
module internal FSharp.Compiler.CheckFormatStrings
+open System.Text
open FSharp.Compiler
open FSharp.Compiler.AbstractIL.Internal.Library
-open FSharp.Compiler.Ast
-open FSharp.Compiler.Range
-open FSharp.Compiler.Tast
-open FSharp.Compiler.Tastops
-open FSharp.Compiler.TcGlobals
open FSharp.Compiler.ConstraintSolver
+open FSharp.Compiler.Lib
open FSharp.Compiler.NameResolution
+open FSharp.Compiler.SyntaxTree
+open FSharp.Compiler.SyntaxTreeOps
+open FSharp.Compiler.Text
+open FSharp.Compiler.TypedTree
+open FSharp.Compiler.TypedTreeOps
+open FSharp.Compiler.TcGlobals
type FormatItem = Simple of TType | FuncAndVal
@@ -21,7 +24,7 @@ let copyAndFixupFormatTypar m tp =
let lowestDefaultPriority = 0 (* See comment on TyparConstraint.DefaultsTo *)
let mkFlexibleFormatTypar m tys dflt =
- let tp = NewTypar (TyparKind.Type,TyparRigidity.Rigid,Typar(mkSynId m "fmt",HeadTypeStaticReq,true),false,TyparDynamicReq.Yes,[],false,false)
+ let tp = Construct.NewTypar (TyparKind.Type,TyparRigidity.Rigid,Typar(mkSynId m "fmt",HeadTypeStaticReq,true),false,TyparDynamicReq.Yes,[],false,false)
tp.SetConstraints [ TyparConstraint.SimpleChoice (tys,m); TyparConstraint.DefaultsTo (lowestDefaultPriority,dflt,m)]
copyAndFixupFormatTypar m tp
@@ -46,31 +49,153 @@ let newInfo () =
addZeros = false
precision = false}
-let parseFormatStringInternal (m:range) (g: TcGlobals) (context: FormatStringCheckContext option) fmt bty cty =
- // Offset is used to adjust ranges depending on whether input string is regular, verbatim or triple-quote.
- // We construct a new 'fmt' string since the current 'fmt' string doesn't distinguish between "\n" and escaped "\\n".
- let (offset, fmt) =
+let parseFormatStringInternal (m: range) (fragRanges: range list) (g: TcGlobals) isInterpolated isFormattableString (context: FormatStringCheckContext option) fmt printerArgTy printerResidueTy =
+
+ // As background: the F# compiler tokenizes strings on the assumption that the only thing you need from
+ // them is the actual corresponding text, e.g. of a string literal. This means many different textual input strings
+ // in the input file correspond to the 'fmt' string we have here.
+ //
+ // The problem with this is that when we go to colorize the format specifiers in string, we need to do
+ // that with respect to the original string source text in order to lay down accurate colorizations.
+ //
+ // One approach would be to change the F# lexer to also crack every string in a more structured way, recording
+ // both the original source text and the actual string literal. However this would be invasive and possibly
+ // too expensive since the vast majority of strings don't need this treatment.
+ //
+ // So instead, for format strings alone - and only when processing in the IDE - we crack the "original"
+ // source of the string by going back and getting the format string from the input source file by using the
+ // relevant ranges
+ //
+ // For interpolated strings this may involve many fragments, e.g.
+ // $"abc %d{"
+ // "} def %s{"
+ // "} xyz"
+ // In this case we are given the range of each fragment. One annoying thing is that we must lop off the
+ // quotations, $, {, } symbols off the end of each string fragment. This information should probably
+ // be given to us by the lexer.
+ //
+ // Note this also means that when compiling (command-line or background IncrementalBuilder in the IDE
+ // there are no accurate intra-string ranges available for exact error message locations within the string.
+ // The 'm' range passed as an input is however accurate and covers the whole string.
+ ///
+ let fmt, fragments =
+
+ //printfn "--------------------"
+ //printfn "context.IsSome = %b" context.IsSome
+ //printfn "fmt = <<<%s>>>" fmt
+ //printfn "isInterpolated = %b" isInterpolated
+ //printfn "fragRanges = %A" fragRanges
+
match context with
- | Some context ->
+ | Some context when fragRanges.Length > 0 ->
let sourceText = context.SourceText
+ //printfn "sourceText.IsSome = %b" sourceText.IsSome
let lineStartPositions = context.LineStartPositions
+ //printfn "lineStartPositions.Length = %d" lineStartPositions.Length
let length = sourceText.Length
- if m.EndLine < lineStartPositions.Length then
- let startIndex = lineStartPositions.[m.StartLine-1] + m.StartColumn
- let endIndex = lineStartPositions.[m.EndLine-1] + m.EndColumn - 1
- if startIndex < length-3 && sourceText.SubTextEquals("\"\"\"", startIndex) then
- (3, sourceText.GetSubTextString(startIndex + 3, endIndex - startIndex))
- elif startIndex < length-2 && sourceText.SubTextEquals("@\"", startIndex) then
- (2, sourceText.GetSubTextString(startIndex + 2, endIndex + 1 - startIndex))
- else (1, sourceText.GetSubTextString(startIndex + 1, endIndex - startIndex))
- else (1, fmt)
- | None -> (1, fmt)
-
- let len = String.length fmt
+ let numFrags = fragRanges.Length
+ let fmts =
+ [ for i, fragRange in List.indexed fragRanges do
+ let m = fragRange
+ //printfn "m.EndLine = %d" m.EndLine
+ if m.StartLine - 1 < lineStartPositions.Length && m.EndLine - 1 < lineStartPositions.Length then
+ let startIndex = lineStartPositions.[m.StartLine-1] + m.StartColumn
+ let endIndex = lineStartPositions.[m.EndLine-1] + m.EndColumn
+ // Note, some extra """ text may be included at end of these snippets, meaning CheckFormatString in the IDE
+ // may be using a slightly false format string to colorize the %d markers. This doesn't matter as there
+ // won't be relevant %d in these sections
+ //
+ // However we make an effort to remove these to keep the calls to GetSubStringText valid. So
+ // we work out how much extra text there is at the end of the last line of the fragment,
+ // which may or may not be quote markers. If there's no flex, we don't trim the quote marks
+ let endNextLineIndex = if m.EndLine < lineStartPositions.Length then lineStartPositions.[m.EndLine] else endIndex
+ let endIndexFlex = endNextLineIndex - endIndex
+ let mLength = endIndex - startIndex
+
+ //let startIndex2 = if m.StartLine < lineStartPositions.Length then lineStartPositions.[m.StartLine] else startIndex
+ //let sourceLineFromOffset = sourceText.GetSubTextString(startIndex, (startIndex2 - startIndex))
+ //printfn "i = %d, mLength = %d, endIndexFlex = %d, sourceLineFromOffset = <<<%s>>>" i mLength endIndexFlex sourceLineFromOffset
+
+ if isInterpolated && i=0 && startIndex < length-4 && sourceText.SubTextEquals("$\"\"\"", startIndex) then
+ // Take of the ending triple quote or '{'
+ let fragLength = mLength - 4 - min endIndexFlex (if i = numFrags-1 then 3 else 1)
+ (4, sourceText.GetSubTextString(startIndex + 4, fragLength), m)
+ elif not isInterpolated && i=0 && startIndex < length-3 && sourceText.SubTextEquals("\"\"\"", startIndex) then
+ // Take of the ending triple quote or '{'
+ let fragLength = mLength - 2 - min endIndexFlex (if i = numFrags-1 then 3 else 1)
+ (3, sourceText.GetSubTextString(startIndex + 3, fragLength), m)
+ elif isInterpolated && i=0 && startIndex < length-3 && sourceText.SubTextEquals("$@\"", startIndex) then
+ // Take of the ending quote or '{', always length 1
+ let fragLength = mLength - 3 - min endIndexFlex 1
+ (3, sourceText.GetSubTextString(startIndex + 3, fragLength), m)
+ elif isInterpolated && i=0 && startIndex < length-3 && sourceText.SubTextEquals("@$\"", startIndex) then
+ // Take of the ending quote or '{', always length 1
+ let fragLength = mLength - 3 - min endIndexFlex 1
+ (3, sourceText.GetSubTextString(startIndex + 3, fragLength), m)
+ elif not isInterpolated && i=0 && startIndex < length-2 && sourceText.SubTextEquals("@\"", startIndex) then
+ // Take of the ending quote or '{', always length 1
+ let fragLength = mLength - 2 - min endIndexFlex 1
+ (2, sourceText.GetSubTextString(startIndex + 2, fragLength), m)
+ elif isInterpolated && i=0 && startIndex < length-2 && sourceText.SubTextEquals("$\"", startIndex) then
+ // Take of the ending quote or '{', always length 1
+ let fragLength = mLength - 2 - min endIndexFlex 1
+ (2, sourceText.GetSubTextString(startIndex + 2, fragLength), m)
+ elif isInterpolated && i <> 0 && startIndex < length-1 && sourceText.SubTextEquals("}", startIndex) then
+ // Take of the ending quote or '{', always length 1
+ let fragLength = mLength - 1 - min endIndexFlex 1
+ (1, sourceText.GetSubTextString(startIndex + 1, fragLength), m)
+ else
+ // Take of the ending quote or '{', always length 1
+ let fragLength = mLength - 1 - min endIndexFlex 1
+ (1, sourceText.GetSubTextString(startIndex + 1, fragLength), m)
+ else (1, fmt, m) ]
+
+ //printfn "fmts = %A" fmts
+
+ // Join the fragments with holes. Note this join is only used on the IDE path,
+ // the CheckExpressions.fs does its own joining with the right alignments etc. substituted
+ // On the IDE path we don't do any checking of these in this file (some checking is
+ // done in CheckExpressions.fs) so it's ok to join with just '%P()'.
+ let fmt = fmts |> List.map p23 |> String.concat "%P()"
+ let fragments, _ =
+ (0, fmts) ||> List.mapFold (fun i (offset, fmt, fragRange) ->
+ (i, offset, fragRange), i + fmt.Length + 4) // the '4' is the length of '%P()' joins
+
+ //printfn "fmt2 = <<<%s>>>" fmt
+ //printfn "fragments = %A" fragments
+ fmt, fragments
+ | _ ->
+ // Don't muck with the fmt when there is no source code context to go get the original
+ // source code (i.e. when compiling or background checking)
+ fmt, [ (0, 1, m) ]
+
+ let len = fmt.Length
let specifierLocations = ResizeArray()
- let rec parseLoop acc (i, relLine, relCol) =
+ // For FormattableString we collect a .NET Format String with {0} etc. replacing text. '%%' are replaced
+ // by '%', we check there are no '%' formats, and '{{' and '}}' are *not* replaced since the subsequent
+ // call to String.Format etc. will process them.
+ let dotnetFormatString = StringBuilder()
+ let appendToDotnetFormatString (s: string) = dotnetFormatString.Append(s) |> ignore
+ let mutable dotnetFormatStringInterpolationHoleCount = 0
+ let percentATys = ResizeArray<_>()
+
+ // fragLine, fragCol - track our location w.r.t. the marker for the start of this chunk
+ //
+ let rec parseLoop acc (i, fragLine, fragCol) fragments =
+
+ // Check if we've moved into the next fragment. Note this will always activate on
+ // the first step, i.e. when i=0
+ let (struct (fragLine, fragCol, fragments)) =
+ match fragments with
+ | (idx, fragOffset, fragRange: range)::rest when i >= idx ->
+ //printfn "i = %d, idx = %d, moving into next fragment at %A plus fragOffset %d" i idx fragRange fragOffset
+ struct (fragRange.StartLine, fragRange.StartColumn + fragOffset, rest)
+
+ | _ -> struct (fragLine, fragCol, fragments)
+ //printfn "parseLoop: i = %d, fragLine = %d, fragCol = %d" i fragLine fragCol
+
if i >= len then
let argtys =
if acc |> List.forall (fun (p, _) -> p = None) then // without positional specifiers
@@ -79,13 +204,14 @@ let parseFormatStringInternal (m:range) (g: TcGlobals) (context: FormatStringChe
failwithf "%s" <| FSComp.SR.forPositionalSpecifiersNotPermitted()
argtys
elif System.Char.IsSurrogatePair(fmt,i) then
- parseLoop acc (i+2, relLine, relCol+2)
+ appendToDotnetFormatString (fmt.[i..i+1])
+ parseLoop acc (i+2, fragLine, fragCol+2) fragments
else
let c = fmt.[i]
match c with
| '%' ->
- let startCol = relCol
- let relCol = relCol+1
+ let startFragCol = fragCol
+ let fragCol = fragCol+1
let i = i+1
if i >= len then failwithf "%s" <| FSComp.SR.forMissingFormatSpecifier()
let info = newInfo()
@@ -109,7 +235,7 @@ let parseFormatStringInternal (m:range) (g: TcGlobals) (context: FormatStringChe
if info.numPrefixIfPos <> None then failwithf "%s" <| FSComp.SR.forPrefixFlagSpacePlusSetTwice()
info.numPrefixIfPos <- Some ' '
flags(i+1)
- | '#' -> failwithf "%s" <| FSComp.SR.forHashSpecifierIsInvalid()
+ | '#' -> failwithf "%s" <| FSComp.SR.forHashSpecifierIsInvalid()
| _ -> i
let rec digitsPrecision i =
@@ -131,18 +257,18 @@ let parseFormatStringInternal (m:range) (g: TcGlobals) (context: FormatStringChe
| '.' -> precision (i+1)
| _ -> false,i
- let rec digitsWidthAndPrecision i =
+ let rec digitsWidthAndPrecision n i =
if i >= len then failwithf "%s" <| FSComp.SR.forBadPrecision()
match fmt.[i] with
- | c when System.Char.IsDigit c -> digitsWidthAndPrecision (i+1)
- | _ -> optionalDotAndPrecision i
+ | c when System.Char.IsDigit c -> digitsWidthAndPrecision (n*10 + int c - int '0') (i+1)
+ | _ -> Some n, optionalDotAndPrecision i
let widthAndPrecision i =
if i >= len then failwithf "%s" <| FSComp.SR.forBadPrecision()
match fmt.[i] with
- | c when System.Char.IsDigit c -> false,digitsWidthAndPrecision i
- | '*' -> true,optionalDotAndPrecision (i+1)
- | _ -> false,optionalDotAndPrecision i
+ | c when System.Char.IsDigit c -> false,digitsWidthAndPrecision 0 i
+ | '*' -> true, (None, optionalDotAndPrecision (i+1))
+ | _ -> false, (None, optionalDotAndPrecision i)
let rec digitsPosition n i =
if i >= len then failwithf "%s" <| FSComp.SR.forBadPrecision()
@@ -160,15 +286,15 @@ let parseFormatStringInternal (m:range) (g: TcGlobals) (context: FormatStringChe
let oldI = i
let posi, i = position i
- let relCol = relCol + i - oldI
+ let fragCol = fragCol + i - oldI
let oldI = i
let i = flags i
- let relCol = relCol + i - oldI
+ let fragCol = fragCol + i - oldI
let oldI = i
- let widthArg,(precisionArg,i) = widthAndPrecision i
- let relCol = relCol + i - oldI
+ let widthArg,(widthValue, (precisionArg,i)) = widthAndPrecision i
+ let fragCol = fragCol + i - oldI
if i >= len then failwithf "%s" <| FSComp.SR.forBadPrecision()
@@ -176,127 +302,185 @@ let parseFormatStringInternal (m:range) (g: TcGlobals) (context: FormatStringChe
let acc = if widthArg then (Option.map ((+)1) posi, g.int_ty) :: acc else acc
- let checkNoPrecision c = if info.precision then failwithf "%s" <| FSComp.SR.forFormatDoesntSupportPrecision(c.ToString())
- let checkNoZeroFlag c = if info.addZeros then failwithf "%s" <| FSComp.SR.forDoesNotSupportZeroFlag(c.ToString())
- let checkNoNumericPrefix c = if info.numPrefixIfPos <> None then
- failwithf "%s" <| FSComp.SR.forDoesNotSupportPrefixFlag(c.ToString(), (Option.get info.numPrefixIfPos).ToString())
+ let checkNoPrecision c =
+ if info.precision then failwithf "%s" <| FSComp.SR.forFormatDoesntSupportPrecision(c.ToString())
+
+ let checkNoZeroFlag c =
+ if info.addZeros then failwithf "%s" <| FSComp.SR.forDoesNotSupportZeroFlag(c.ToString())
+
+ let checkNoNumericPrefix c =
+ match info.numPrefixIfPos with
+ | Some n -> failwithf "%s" <| FSComp.SR.forDoesNotSupportPrefixFlag(c.ToString(), n.ToString())
+ | None -> ()
let checkOtherFlags c =
checkNoPrecision c
checkNoZeroFlag c
checkNoNumericPrefix c
- let collectSpecifierLocation relLine relCol numStdArgs =
- let numArgsForSpecifier =
- numStdArgs + (if widthArg then 1 else 0) + (if precisionArg then 1 else 0)
- match relLine with
- | 0 ->
- specifierLocations.Add(
- (Range.mkFileIndexRange m.FileIndex
- (Range.mkPos m.StartLine (startCol + offset))
- (Range.mkPos m.StartLine (relCol + offset + 1))), numArgsForSpecifier)
- | _ ->
+ // Explicitly typed holes in interpolated strings "....%d{x}..." get additional '%P()' as a hole place marker
+ let skipPossibleInterpolationHole i =
+ if isInterpolated then
+ if i+1 < len && fmt.[i] = '%' && fmt.[i+1] = 'P' then
+ let i = i + 2
+ if i+1 < len && fmt.[i] = '(' && fmt.[i+1] = ')' then
+ if isFormattableString then
+ failwithf "%s" <| FSComp.SR.forFormatInvalidForInterpolated4()
+ i + 2
+ else
+ failwithf "%s" <| FSComp.SR.forFormatInvalidForInterpolated2()
+ else
+ failwithf "%s" <| FSComp.SR.forFormatInvalidForInterpolated()
+ else i
+
+ // Implicitly typed holes in interpolated strings are translated to '... %P(...)...' in the
+ // type checker. They should always have '(...)' after for format string.
+ let requireAndSkipInterpolationHoleFormat i =
+ if i < len && fmt.[i] = '(' then
+ let i2 = fmt.IndexOf(")", i+1)
+ if i2 = -1 then
+ failwithf "%s" <| FSComp.SR.forFormatInvalidForInterpolated3()
+ else
+ let dotnetAlignment = match widthValue with None -> "" | Some w -> "," + (if info.leftJustify then "-" else "") + string w
+ let dotnetNumberFormat = match fmt.[i+1..i2-1] with "" -> "" | s -> ":" + s
+ appendToDotnetFormatString ("{" + string dotnetFormatStringInterpolationHoleCount + dotnetAlignment + dotnetNumberFormat + "}")
+ dotnetFormatStringInterpolationHoleCount <- dotnetFormatStringInterpolationHoleCount + 1
+ i2+1
+ else
+ failwithf "%s" <| FSComp.SR.forFormatInvalidForInterpolated3()
+
+ let collectSpecifierLocation fragLine fragCol numStdArgs =
+ match context with
+ | Some _ ->
+ let numArgsForSpecifier =
+ numStdArgs + (if widthArg then 1 else 0) + (if precisionArg then 1 else 0)
specifierLocations.Add(
- (Range.mkFileIndexRange m.FileIndex
- (Range.mkPos (m.StartLine + relLine) startCol)
- (Range.mkPos (m.StartLine + relLine) (relCol + 1))), numArgsForSpecifier)
+ (Range.mkFileIndexRange m.FileIndex
+ (Pos.mkPos fragLine startFragCol)
+ (Pos.mkPos fragLine (fragCol + 1))), numArgsForSpecifier)
+ | None -> ()
let ch = fmt.[i]
match ch with
| '%' ->
- collectSpecifierLocation relLine relCol 0
- parseLoop acc (i+1, relLine, relCol+1)
+ collectSpecifierLocation fragLine fragCol 0
+ appendToDotnetFormatString "%"
+ parseLoop acc (i+1, fragLine, fragCol+1) fragments
| ('d' | 'i' | 'o' | 'u' | 'x' | 'X') ->
if info.precision then failwithf "%s" <| FSComp.SR.forFormatDoesntSupportPrecision(ch.ToString())
- collectSpecifierLocation relLine relCol 1
- parseLoop ((posi, mkFlexibleIntFormatTypar g m) :: acc) (i+1, relLine, relCol+1)
+ collectSpecifierLocation fragLine fragCol 1
+ let i = skipPossibleInterpolationHole (i+1)
+ parseLoop ((posi, mkFlexibleIntFormatTypar g m) :: acc) (i, fragLine, fragCol+1) fragments
| ('l' | 'L') ->
if info.precision then failwithf "%s" <| FSComp.SR.forFormatDoesntSupportPrecision(ch.ToString())
- let relCol = relCol+1
+ let fragCol = fragCol+1
let i = i+1
// "bad format specifier ... In F# code you can use %d, %x, %o or %u instead ..."
if i >= len then
- failwithf "%s" <| FSComp.SR.forBadFormatSpecifier()
+ raise (Failure (FSComp.SR.forBadFormatSpecifier()))
// Always error for %l and %Lx
failwithf "%s" <| FSComp.SR.forLIsUnnecessary()
match fmt.[i] with
| ('d' | 'i' | 'o' | 'u' | 'x' | 'X') ->
- collectSpecifierLocation relLine relCol 1
- parseLoop ((posi, mkFlexibleIntFormatTypar g m) :: acc) (i+1, relLine, relCol+1)
+ collectSpecifierLocation fragLine fragCol 1
+ let i = skipPossibleInterpolationHole (i+1)
+ parseLoop ((posi, mkFlexibleIntFormatTypar g m) :: acc) (i, fragLine, fragCol+1) fragments
| _ -> failwithf "%s" <| FSComp.SR.forBadFormatSpecifier()
| ('h' | 'H') ->
failwithf "%s" <| FSComp.SR.forHIsUnnecessary()
| 'M' ->
- collectSpecifierLocation relLine relCol 1
- parseLoop ((posi, mkFlexibleDecimalFormatTypar g m) :: acc) (i+1, relLine, relCol+1)
+ collectSpecifierLocation fragLine fragCol 1
+ let i = skipPossibleInterpolationHole (i+1)
+ parseLoop ((posi, mkFlexibleDecimalFormatTypar g m) :: acc) (i, fragLine, fragCol+1) fragments
| ('f' | 'F' | 'e' | 'E' | 'g' | 'G') ->
- collectSpecifierLocation relLine relCol 1
- parseLoop ((posi, mkFlexibleFloatFormatTypar g m) :: acc) (i+1, relLine, relCol+1)
+ collectSpecifierLocation fragLine fragCol 1
+ let i = skipPossibleInterpolationHole (i+1)
+ parseLoop ((posi, mkFlexibleFloatFormatTypar g m) :: acc) (i, fragLine, fragCol+1) fragments
| 'b' ->
checkOtherFlags ch
- collectSpecifierLocation relLine relCol 1
- parseLoop ((posi, g.bool_ty) :: acc) (i+1, relLine, relCol+1)
+ collectSpecifierLocation fragLine fragCol 1
+ let i = skipPossibleInterpolationHole (i+1)
+ parseLoop ((posi, g.bool_ty) :: acc) (i, fragLine, fragCol+1) fragments
| 'c' ->
checkOtherFlags ch
- collectSpecifierLocation relLine relCol 1
- parseLoop ((posi, g.char_ty) :: acc) (i+1, relLine, relCol+1)
+ collectSpecifierLocation fragLine fragCol 1
+ let i = skipPossibleInterpolationHole (i+1)
+ parseLoop ((posi, g.char_ty) :: acc) (i, fragLine, fragCol+1) fragments
| 's' ->
checkOtherFlags ch
- collectSpecifierLocation relLine relCol 1
- parseLoop ((posi, g.string_ty) :: acc) (i+1, relLine, relCol+1)
+ collectSpecifierLocation fragLine fragCol 1
+ let i = skipPossibleInterpolationHole (i+1)
+ parseLoop ((posi, g.string_ty) :: acc) (i, fragLine, fragCol+1) fragments
| 'O' ->
checkOtherFlags ch
- collectSpecifierLocation relLine relCol 1
- parseLoop ((posi, NewInferenceType ()) :: acc) (i+1, relLine, relCol+1)
+ collectSpecifierLocation fragLine fragCol 1
+ let i = skipPossibleInterpolationHole (i+1)
+ parseLoop ((posi, NewInferenceType ()) :: acc) (i, fragLine, fragCol+1) fragments
+
+ // residue of hole "...{n}..." in interpolated strings become %P(...)
+ | 'P' when isInterpolated ->
+ checkOtherFlags ch
+ let i = requireAndSkipInterpolationHoleFormat (i+1)
+ // Note, the fragCol doesn't advance at all as these are magically inserted.
+ parseLoop ((posi, NewInferenceType ()) :: acc) (i, fragLine, startFragCol) fragments
| 'A' ->
match info.numPrefixIfPos with
| None // %A has BindingFlags=Public, %+A has BindingFlags=Public | NonPublic
| Some '+' ->
- collectSpecifierLocation relLine relCol 1
- parseLoop ((posi, NewInferenceType ()) :: acc) (i+1, relLine, relCol+1)
- | Some _ -> failwithf "%s" <| FSComp.SR.forDoesNotSupportPrefixFlag(ch.ToString(), (Option.get info.numPrefixIfPos).ToString())
+ collectSpecifierLocation fragLine fragCol 1
+ let i = skipPossibleInterpolationHole (i+1)
+ let xty = NewInferenceType ()
+ percentATys.Add(xty)
+ parseLoop ((posi, xty) :: acc) (i, fragLine, fragCol+1) fragments
+ | Some n -> failwithf "%s" <| FSComp.SR.forDoesNotSupportPrefixFlag(ch.ToString(), n.ToString())
| 'a' ->
checkOtherFlags ch
let xty = NewInferenceType ()
- let fty = bty --> (xty --> cty)
- collectSpecifierLocation relLine relCol 2
- parseLoop ((Option.map ((+)1) posi, xty) :: (posi, fty) :: acc) (i+1, relLine, relCol+1)
+ let fty = printerArgTy --> (xty --> printerResidueTy)
+ collectSpecifierLocation fragLine fragCol 2
+ let i = skipPossibleInterpolationHole (i+1)
+ parseLoop ((Option.map ((+)1) posi, xty) :: (posi, fty) :: acc) (i, fragLine, fragCol+1) fragments
| 't' ->
checkOtherFlags ch
- collectSpecifierLocation relLine relCol 1
- parseLoop ((posi, bty --> cty) :: acc) (i+1, relLine, relCol+1)
+ collectSpecifierLocation fragLine fragCol 1
+ let i = skipPossibleInterpolationHole (i+1)
+ parseLoop ((posi, printerArgTy --> printerResidueTy) :: acc) (i, fragLine, fragCol+1) fragments
- | c -> failwithf "%s" <| FSComp.SR.forBadFormatSpecifierGeneral(String.make 1 c)
+ | c -> failwithf "%s" <| FSComp.SR.forBadFormatSpecifierGeneral(String.make 1 c)
- | '\n' -> parseLoop acc (i+1, relLine+1, 0)
- | _ -> parseLoop acc (i+1, relLine, relCol+1)
+ | '\n' ->
+ appendToDotnetFormatString fmt.[i..i]
+ parseLoop acc (i+1, fragLine+1, 0) fragments
+ | _ ->
+ appendToDotnetFormatString fmt.[i..i]
+ parseLoop acc (i+1, fragLine, fragCol+1) fragments
- let results = parseLoop [] (0, 0, m.StartColumn)
- results, Seq.toList specifierLocations
+ let results = parseLoop [] (0, 0, m.StartColumn) fragments
+ results, Seq.toList specifierLocations, dotnetFormatString.ToString(), percentATys.ToArray()
-let ParseFormatString m g formatStringCheckContext fmt bty cty dty =
- let argtys, specifierLocations = parseFormatStringInternal m g formatStringCheckContext fmt bty cty
- let aty = List.foldBack (-->) argtys dty
- let ety = mkRefTupledTy g argtys
- (aty, ety), specifierLocations
+let ParseFormatString m fragmentRanges g isInterpolated isFormattableString formatStringCheckContext fmt printerArgTy printerResidueTy printerResultTy =
+ let argTys, specifierLocations, dotnetFormatString, percentATys = parseFormatStringInternal m fragmentRanges g isInterpolated isFormattableString formatStringCheckContext fmt printerArgTy printerResidueTy
+ let printerTy = List.foldBack (-->) argTys printerResultTy
+ let printerTupleTy = mkRefTupledTy g argTys
+ argTys, printerTy, printerTupleTy, percentATys, specifierLocations, dotnetFormatString
-let TryCountFormatStringArguments m g fmt bty cty =
+let TryCountFormatStringArguments m g isInterpolated fmt printerArgTy printerResidueTy =
try
- let argtys, _specifierLocations = parseFormatStringInternal m g None fmt bty cty
- Some argtys.Length
+ let argTys, _specifierLocations, _dotnetFormatString, _percentATys = parseFormatStringInternal m [] g isInterpolated false None fmt printerArgTy printerResidueTy
+ Some argTys.Length
with _ ->
None
diff --git a/src/fsharp/CheckFormatStrings.fsi b/src/fsharp/CheckFormatStrings.fsi
index 10768a94242..ffafb37d6c0 100644
--- a/src/fsharp/CheckFormatStrings.fsi
+++ b/src/fsharp/CheckFormatStrings.fsi
@@ -7,11 +7,11 @@
module internal FSharp.Compiler.CheckFormatStrings
-open FSharp.Compiler
open FSharp.Compiler.NameResolution
-open FSharp.Compiler.Tast
open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.Text
+open FSharp.Compiler.TypedTree
-val ParseFormatString : Range.range -> TcGlobals -> formatStringCheckContext: FormatStringCheckContext option -> fmt: string -> bty: TType -> cty: TType -> dty: TType -> (TType * TType) * (Range.range * int) list
+val ParseFormatString : m: range -> fragmentRanges: range list -> g: TcGlobals -> isInterpolated: bool -> isFormattableString: bool -> formatStringCheckContext: FormatStringCheckContext option -> fmt: string -> printerArgTy: TType -> printerResidueTy: TType -> printerResultTy: TType -> TType list * TType * TType * TType[] * (range * int) list * string
-val TryCountFormatStringArguments : m:Range.range -> g:TcGlobals -> fmt:string -> bty:TType -> cty:TType -> int option
+val TryCountFormatStringArguments: m: range -> g: TcGlobals -> isInterpolated: bool -> fmt:string -> printerArgTy:TType -> printerResidueTy:TType -> int option
diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs
deleted file mode 100644
index 0548fd1269e..00000000000
--- a/src/fsharp/CompileOps.fs
+++ /dev/null
@@ -1,5596 +0,0 @@
-// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-
-/// Coordinating compiler operations - configuration, loading initial context, reporting errors etc.
-module internal FSharp.Compiler.CompileOps
-
-open System
-open System.Collections.Generic
-open System.Diagnostics
-open System.IO
-open System.Text
-
-open Internal.Utilities
-open Internal.Utilities.Collections
-open Internal.Utilities.Filename
-open Internal.Utilities.Text
-
-open FSharp.Compiler.AbstractIL
-open FSharp.Compiler.AbstractIL.IL
-open FSharp.Compiler.AbstractIL.ILBinaryReader
-open FSharp.Compiler.AbstractIL.ILPdbWriter
-open FSharp.Compiler.AbstractIL.Internal
-open FSharp.Compiler.AbstractIL.Internal.Library
-open FSharp.Compiler.AbstractIL.Extensions.ILX
-open FSharp.Compiler.AbstractIL.Diagnostics
-
-open FSharp.Compiler
-open FSharp.Compiler.Ast
-open FSharp.Compiler.AttributeChecking
-open FSharp.Compiler.ConstraintSolver
-open FSharp.Compiler.DiagnosticMessage
-open FSharp.Compiler.ErrorLogger
-open FSharp.Compiler.Features
-open FSharp.Compiler.Import
-open FSharp.Compiler.Infos
-open FSharp.Compiler.Lexhelp
-open FSharp.Compiler.Lib
-open FSharp.Compiler.MethodCalls
-open FSharp.Compiler.MethodOverrides
-open FSharp.Compiler.NameResolution
-open FSharp.Compiler.PrettyNaming
-open FSharp.Compiler.Range
-open FSharp.Compiler.ReferenceResolver
-open FSharp.Compiler.SignatureConformance
-open FSharp.Compiler.TastPickle
-open FSharp.Compiler.TypeChecker
-open FSharp.Compiler.Tast
-open FSharp.Compiler.Tastops
-open FSharp.Compiler.TcGlobals
-open FSharp.Compiler.Text
-
-open FSharp.Compiler.DotNetFrameworkDependencies
-
-#if !NO_EXTENSIONTYPING
-open FSharp.Compiler.ExtensionTyping
-open Microsoft.FSharp.Core.CompilerServices
-#endif
-
-#if DEBUG
-[]
-module internal CompilerService =
- let showAssertForUnexpectedException = ref true
-#endif // DEBUG
-
-//----------------------------------------------------------------------------
-// Some Globals
-//--------------------------------------------------------------------------
-
-let FSharpSigFileSuffixes = [".mli";".fsi"]
-let mlCompatSuffixes = [".mli";".ml"]
-let FSharpImplFileSuffixes = [".ml";".fs";".fsscript";".fsx"]
-let resSuffixes = [".resx"]
-let FSharpScriptFileSuffixes = [".fsscript";".fsx"]
-let doNotRequireNamespaceOrModuleSuffixes = [".mli";".ml"] @ FSharpScriptFileSuffixes
-let FSharpLightSyntaxFileSuffixes: string list = [ ".fs";".fsscript";".fsx";".fsi" ]
-
-
-//----------------------------------------------------------------------------
-// ERROR REPORTING
-//--------------------------------------------------------------------------
-
-exception HashIncludeNotAllowedInNonScript of range
-exception HashReferenceNotAllowedInNonScript of range
-exception HashDirectiveNotAllowedInNonScript of range
-exception FileNameNotResolved of (*filename*) string * (*description of searched locations*) string * range
-exception AssemblyNotResolved of (*originalName*) string * range
-exception LoadedSourceNotFoundIgnoring of (*filename*) string * range
-exception MSBuildReferenceResolutionWarning of (*MSBuild warning code*)string * (*Message*)string * range
-exception MSBuildReferenceResolutionError of (*MSBuild warning code*)string * (*Message*)string * range
-exception DeprecatedCommandLineOptionFull of string * range
-exception DeprecatedCommandLineOptionForHtmlDoc of string * range
-exception DeprecatedCommandLineOptionSuggestAlternative of string * string * range
-exception DeprecatedCommandLineOptionNoDescription of string * range
-exception InternalCommandLineOption of string * range
-exception HashLoadedSourceHasIssues of (*warnings*) exn list * (*errors*) exn list * range
-exception HashLoadedScriptConsideredSource of range
-
-
-let GetRangeOfDiagnostic(err: PhasedDiagnostic) =
- let rec RangeFromException = function
- | ErrorFromAddingConstraint(_, err2, _) -> RangeFromException err2
-#if !NO_EXTENSIONTYPING
- | ExtensionTyping.ProvidedTypeResolutionNoRange e -> RangeFromException e
- | ExtensionTyping.ProvidedTypeResolution(m, _)
-#endif
- | ReservedKeyword(_, m)
- | IndentationProblem(_, m)
- | ErrorFromAddingTypeEquation(_, _, _, _, _, m)
- | ErrorFromApplyingDefault(_, _, _, _, _, m)
- | ErrorsFromAddingSubsumptionConstraint(_, _, _, _, _, _, m)
- | FunctionExpected(_, _, m)
- | BakedInMemberConstraintName(_, m)
- | StandardOperatorRedefinitionWarning(_, m)
- | BadEventTransformation m
- | ParameterlessStructCtor m
- | FieldNotMutable (_, _, m)
- | Recursion (_, _, _, _, m)
- | InvalidRuntimeCoercion(_, _, _, m)
- | IndeterminateRuntimeCoercion(_, _, _, m)
- | IndeterminateStaticCoercion (_, _, _, m)
- | StaticCoercionShouldUseBox (_, _, _, m)
- | CoercionTargetSealed(_, _, m)
- | UpcastUnnecessary m
- | QuotationTranslator.IgnoringPartOfQuotedTermWarning (_, m)
-
- | TypeTestUnnecessary m
- | RuntimeCoercionSourceSealed(_, _, m)
- | OverrideDoesntOverride(_, _, _, _, _, m)
- | UnionPatternsBindDifferentNames m
- | UnionCaseWrongArguments (_, _, _, m)
- | TypeIsImplicitlyAbstract m
- | RequiredButNotSpecified (_, _, _, _, m)
- | FunctionValueUnexpected (_, _, m)
- | UnitTypeExpected (_, _, m)
- | UnitTypeExpectedWithEquality (_, _, m)
- | UnitTypeExpectedWithPossiblePropertySetter (_, _, _, _, m)
- | UnitTypeExpectedWithPossibleAssignment (_, _, _, _, m)
- | UseOfAddressOfOperator m
- | DeprecatedThreadStaticBindingWarning m
- | NonUniqueInferredAbstractSlot (_, _, _, _, _, m)
- | DefensiveCopyWarning (_, m)
- | LetRecCheckedAtRuntime m
- | UpperCaseIdentifierInPattern m
- | NotUpperCaseConstructor m
- | RecursiveUseCheckedAtRuntime (_, _, m)
- | LetRecEvaluatedOutOfOrder (_, _, _, m)
- | Error (_, m)
- | ErrorWithSuggestions (_, m, _, _)
- | NumberedError (_, m)
- | SyntaxError (_, m)
- | InternalError (_, m)
- | FullAbstraction(_, m)
- | InterfaceNotRevealed(_, _, m)
- | WrappedError (_, m)
- | PatternMatchCompilation.MatchIncomplete (_, _, m)
- | PatternMatchCompilation.EnumMatchIncomplete (_, _, m)
- | PatternMatchCompilation.RuleNeverMatched m
- | ValNotMutable(_, _, m)
- | ValNotLocal(_, _, m)
- | MissingFields(_, m)
- | OverrideInIntrinsicAugmentation m
- | IntfImplInIntrinsicAugmentation m
- | OverrideInExtrinsicAugmentation m
- | IntfImplInExtrinsicAugmentation m
- | ValueRestriction(_, _, _, _, m)
- | LetRecUnsound (_, _, m)
- | ObsoleteError (_, m)
- | ObsoleteWarning (_, m)
- | Experimental (_, m)
- | PossibleUnverifiableCode m
- | UserCompilerMessage (_, _, m)
- | Deprecated(_, m)
- | LibraryUseOnly m
- | FieldsFromDifferentTypes (_, _, _, m)
- | IndeterminateType m
- | TyconBadArgs(_, _, _, m) ->
- Some m
-
- | FieldNotContained(_, arf, _, _) -> Some arf.Range
- | ValueNotContained(_, _, aval, _, _) -> Some aval.Range
- | ConstrNotContained(_, aval, _, _) -> Some aval.Id.idRange
- | ExnconstrNotContained(_, aexnc, _, _) -> Some aexnc.Range
-
- | VarBoundTwice id
- | UndefinedName(_, _, id, _) ->
- Some id.idRange
-
- | Duplicate(_, _, m)
- | NameClash(_, _, _, m, _, _, _)
- | UnresolvedOverloading(_, _, _, m)
- | UnresolvedConversionOperator (_, _, _, m)
- | PossibleOverload(_, _, _, m)
- | VirtualAugmentationOnNullValuedType m
- | NonVirtualAugmentationOnNullValuedType m
- | NonRigidTypar(_, _, _, _, _, m)
- | ConstraintSolverTupleDiffLengths(_, _, _, m, _)
- | ConstraintSolverInfiniteTypes(_, _, _, _, m, _)
- | ConstraintSolverMissingConstraint(_, _, _, m, _)
- | ConstraintSolverTypesNotInEqualityRelation(_, _, _, m, _, _)
- | ConstraintSolverError(_, m, _)
- | ConstraintSolverTypesNotInSubsumptionRelation(_, _, _, m, _)
- | ConstraintSolverRelatedInformation(_, m, _)
- | SelfRefObjCtor(_, m) ->
- Some m
-
- | NotAFunction(_, _, mfun, _) ->
- Some mfun
-
- | NotAFunctionButIndexer(_, _, _, mfun, _) ->
- Some mfun
-
- | IllegalFileNameChar(_) -> Some rangeCmdArgs
-
- | UnresolvedReferenceError(_, m)
- | UnresolvedPathReference(_, _, m)
- | DeprecatedCommandLineOptionFull(_, m)
- | DeprecatedCommandLineOptionForHtmlDoc(_, m)
- | DeprecatedCommandLineOptionSuggestAlternative(_, _, m)
- | DeprecatedCommandLineOptionNoDescription(_, m)
- | InternalCommandLineOption(_, m)
- | HashIncludeNotAllowedInNonScript m
- | HashReferenceNotAllowedInNonScript m
- | HashDirectiveNotAllowedInNonScript m
- | FileNameNotResolved(_, _, m)
- | LoadedSourceNotFoundIgnoring(_, m)
- | MSBuildReferenceResolutionWarning(_, _, m)
- | MSBuildReferenceResolutionError(_, _, m)
- | AssemblyNotResolved(_, m)
- | HashLoadedSourceHasIssues(_, _, m)
- | HashLoadedScriptConsideredSource m ->
- Some m
- // Strip TargetInvocationException wrappers
- | :? System.Reflection.TargetInvocationException as e ->
- RangeFromException e.InnerException
-#if !NO_EXTENSIONTYPING
- | :? TypeProviderError as e -> e.Range |> Some
-#endif
-
- | _ -> None
-
- RangeFromException err.Exception
-
-let GetDiagnosticNumber(err: PhasedDiagnostic) =
- let rec GetFromException(e: exn) =
- match e with
- (* DO NOT CHANGE THESE NUMBERS *)
- | ErrorFromAddingTypeEquation _ -> 1
- | FunctionExpected _ -> 2
- | NotAFunctionButIndexer _ -> 3217
- | NotAFunction _ -> 3
- | FieldNotMutable _ -> 5
- | Recursion _ -> 6
- | InvalidRuntimeCoercion _ -> 7
- | IndeterminateRuntimeCoercion _ -> 8
- | PossibleUnverifiableCode _ -> 9
- | SyntaxError _ -> 10
- // 11 cannot be reused
- // 12 cannot be reused
- | IndeterminateStaticCoercion _ -> 13
- | StaticCoercionShouldUseBox _ -> 14
- // 15 cannot be reused
- | RuntimeCoercionSourceSealed _ -> 16
- | OverrideDoesntOverride _ -> 17
- | UnionPatternsBindDifferentNames _ -> 18
- | UnionCaseWrongArguments _ -> 19
- | UnitTypeExpected _ -> 20
- | UnitTypeExpectedWithEquality _ -> 20
- | UnitTypeExpectedWithPossiblePropertySetter _ -> 20
- | UnitTypeExpectedWithPossibleAssignment _ -> 20
- | RecursiveUseCheckedAtRuntime _ -> 21
- | LetRecEvaluatedOutOfOrder _ -> 22
- | NameClash _ -> 23
- // 24 cannot be reused
- | PatternMatchCompilation.MatchIncomplete _ -> 25
- | PatternMatchCompilation.RuleNeverMatched _ -> 26
- | ValNotMutable _ -> 27
- | ValNotLocal _ -> 28
- | MissingFields _ -> 29
- | ValueRestriction _ -> 30
- | LetRecUnsound _ -> 31
- | FieldsFromDifferentTypes _ -> 32
- | TyconBadArgs _ -> 33
- | ValueNotContained _ -> 34
- | Deprecated _ -> 35
- | ConstrNotContained _ -> 36
- | Duplicate _ -> 37
- | VarBoundTwice _ -> 38
- | UndefinedName _ -> 39
- | LetRecCheckedAtRuntime _ -> 40
- | UnresolvedOverloading _ -> 41
- | LibraryUseOnly _ -> 42
- | ErrorFromAddingConstraint _ -> 43
- | ObsoleteWarning _ -> 44
- | FullAbstraction _ -> 45
- | ReservedKeyword _ -> 46
- | SelfRefObjCtor _ -> 47
- | VirtualAugmentationOnNullValuedType _ -> 48
- | UpperCaseIdentifierInPattern _ -> 49
- | InterfaceNotRevealed _ -> 50
- | UseOfAddressOfOperator _ -> 51
- | DefensiveCopyWarning _ -> 52
- | NotUpperCaseConstructor _ -> 53
- | TypeIsImplicitlyAbstract _ -> 54
- // 55 cannot be reused
- | DeprecatedThreadStaticBindingWarning _ -> 56
- | Experimental _ -> 57
- | IndentationProblem _ -> 58
- | CoercionTargetSealed _ -> 59
- | OverrideInIntrinsicAugmentation _ -> 60
- | NonVirtualAugmentationOnNullValuedType _ -> 61
- | UserCompilerMessage (_, n, _) -> n
- | ExnconstrNotContained _ -> 63
- | NonRigidTypar _ -> 64
- // 65 cannot be reused
- | UpcastUnnecessary _ -> 66
- | TypeTestUnnecessary _ -> 67
- | QuotationTranslator.IgnoringPartOfQuotedTermWarning _ -> 68
- | IntfImplInIntrinsicAugmentation _ -> 69
- | NonUniqueInferredAbstractSlot _ -> 70
- | ErrorFromApplyingDefault _ -> 71
- | IndeterminateType _ -> 72
- | InternalError _ -> 73
- | UnresolvedReferenceNoRange _
- | UnresolvedReferenceError _
- | UnresolvedPathReferenceNoRange _
- | UnresolvedPathReference _ -> 74
- | DeprecatedCommandLineOptionFull _
- | DeprecatedCommandLineOptionForHtmlDoc _
- | DeprecatedCommandLineOptionSuggestAlternative _
- | DeprecatedCommandLineOptionNoDescription _
- | InternalCommandLineOption _ -> 75
- | HashIncludeNotAllowedInNonScript _
- | HashReferenceNotAllowedInNonScript _
- | HashDirectiveNotAllowedInNonScript _ -> 76
- | BakedInMemberConstraintName _ -> 77
- | FileNameNotResolved _ -> 78
- | LoadedSourceNotFoundIgnoring _ -> 79
- // 80 cannot be reused
- | ParameterlessStructCtor _ -> 81
- | MSBuildReferenceResolutionWarning _ -> 82
- | MSBuildReferenceResolutionError _ -> 83
- | AssemblyNotResolved _ -> 84
- | HashLoadedSourceHasIssues _ -> 85
- | StandardOperatorRedefinitionWarning _ -> 86
- | InvalidInternalsVisibleToAssemblyName _ -> 87
- // 88 cannot be reused
- | OverrideInExtrinsicAugmentation _ -> 89
- | IntfImplInExtrinsicAugmentation _ -> 90
- | BadEventTransformation _ -> 91
- | HashLoadedScriptConsideredSource _ -> 92
- | UnresolvedConversionOperator _ -> 93
- // avoid 94-100 for safety
- | ObsoleteError _ -> 101
-#if !NO_EXTENSIONTYPING
- | ExtensionTyping.ProvidedTypeResolutionNoRange _
- | ExtensionTyping.ProvidedTypeResolution _ -> 103
-#endif
- | PatternMatchCompilation.EnumMatchIncomplete _ -> 104
- (* DO NOT CHANGE THE NUMBERS *)
-
- // Strip TargetInvocationException wrappers
- | :? System.Reflection.TargetInvocationException as e ->
- GetFromException e.InnerException
-
- | WrappedError(e, _) -> GetFromException e
-
- | Error ((n, _), _) -> n
- | ErrorWithSuggestions ((n, _), _, _, _) -> n
- | Failure _ -> 192
- | NumberedError((n, _), _) -> n
- | IllegalFileNameChar(fileName, invalidChar) -> fst (FSComp.SR.buildUnexpectedFileNameCharacter(fileName, string invalidChar))
-#if !NO_EXTENSIONTYPING
- | :? TypeProviderError as e -> e.Number
-#endif
- | ErrorsFromAddingSubsumptionConstraint (_, _, _, _, _, ContextInfo.DowncastUsedInsteadOfUpcast _, _) -> fst (FSComp.SR.considerUpcast("", ""))
- | _ -> 193
- GetFromException err.Exception
-
-let GetWarningLevel err =
- match err.Exception with
- // Level 5 warnings
- | RecursiveUseCheckedAtRuntime _
- | LetRecEvaluatedOutOfOrder _
- | DefensiveCopyWarning _
- | FullAbstraction _ -> 5
- | NumberedError((n, _), _)
- | ErrorWithSuggestions((n, _), _, _, _)
- | Error((n, _), _) ->
- // 1178, tcNoComparisonNeeded1, "The struct, record or union type '%s' is not structurally comparable because the type parameter %s does not satisfy the 'comparison' constraint..."
- // 1178, tcNoComparisonNeeded2, "The struct, record or union type '%s' is not structurally comparable because the type '%s' does not satisfy the 'comparison' constraint...."
- // 1178, tcNoEqualityNeeded1, "The struct, record or union type '%s' does not support structural equality because the type parameter %s does not satisfy the 'equality' constraint..."
- // 1178, tcNoEqualityNeeded2, "The struct, record or union type '%s' does not support structural equality because the type '%s' does not satisfy the 'equality' constraint...."
- if (n = 1178) then 5 else 2
- // Level 2
- | _ -> 2
-
-let warningOn err level specificWarnOn =
- let n = GetDiagnosticNumber err
- List.contains n specificWarnOn ||
- // Some specific warnings are never on by default, i.e. unused variable warnings
- match n with
- | 1182 -> false // chkUnusedValue - off by default
- | 3218 -> false // ArgumentsInSigAndImplMismatch - off by default
- | 3180 -> false // abImplicitHeapAllocation - off by default
- | _ -> level >= GetWarningLevel err
-
-let SplitRelatedDiagnostics(err: PhasedDiagnostic) =
- let ToPhased e = {Exception=e; Phase = err.Phase}
- let rec SplitRelatedException = function
- | UnresolvedOverloading(a, overloads, b, c) ->
- let related = overloads |> List.map ToPhased
- UnresolvedOverloading(a, [], b, c)|>ToPhased, related
- | ConstraintSolverRelatedInformation(fopt, m2, e) ->
- let e, related = SplitRelatedException e
- ConstraintSolverRelatedInformation(fopt, m2, e.Exception)|>ToPhased, related
- | ErrorFromAddingTypeEquation(g, denv, t1, t2, e, m) ->
- let e, related = SplitRelatedException e
- ErrorFromAddingTypeEquation(g, denv, t1, t2, e.Exception, m)|>ToPhased, related
- | ErrorFromApplyingDefault(g, denv, tp, defaultType, e, m) ->
- let e, related = SplitRelatedException e
- ErrorFromApplyingDefault(g, denv, tp, defaultType, e.Exception, m)|>ToPhased, related
- | ErrorsFromAddingSubsumptionConstraint(g, denv, t1, t2, e, contextInfo, m) ->
- let e, related = SplitRelatedException e
- ErrorsFromAddingSubsumptionConstraint(g, denv, t1, t2, e.Exception, contextInfo, m)|>ToPhased, related
- | ErrorFromAddingConstraint(x, e, m) ->
- let e, related = SplitRelatedException e
- ErrorFromAddingConstraint(x, e.Exception, m)|>ToPhased, related
- | WrappedError (e, m) ->
- let e, related = SplitRelatedException e
- WrappedError(e.Exception, m)|>ToPhased, related
- // Strip TargetInvocationException wrappers
- | :? System.Reflection.TargetInvocationException as e ->
- SplitRelatedException e.InnerException
- | e ->
- ToPhased e, []
- SplitRelatedException err.Exception
-
-
-let DeclareMesssage = FSharp.Compiler.DiagnosticMessage.DeclareResourceString
-
-do FSComp.SR.RunStartupValidation()
-let SeeAlsoE() = DeclareResourceString("SeeAlso", "%s")
-let ConstraintSolverTupleDiffLengthsE() = DeclareResourceString("ConstraintSolverTupleDiffLengths", "%d%d")
-let ConstraintSolverInfiniteTypesE() = DeclareResourceString("ConstraintSolverInfiniteTypes", "%s%s")
-let ConstraintSolverMissingConstraintE() = DeclareResourceString("ConstraintSolverMissingConstraint", "%s")
-let ConstraintSolverTypesNotInEqualityRelation1E() = DeclareResourceString("ConstraintSolverTypesNotInEqualityRelation1", "%s%s")
-let ConstraintSolverTypesNotInEqualityRelation2E() = DeclareResourceString("ConstraintSolverTypesNotInEqualityRelation2", "%s%s")
-let ConstraintSolverTypesNotInSubsumptionRelationE() = DeclareResourceString("ConstraintSolverTypesNotInSubsumptionRelation", "%s%s%s")
-let ErrorFromAddingTypeEquation1E() = DeclareResourceString("ErrorFromAddingTypeEquation1", "%s%s%s")
-let ErrorFromAddingTypeEquation2E() = DeclareResourceString("ErrorFromAddingTypeEquation2", "%s%s%s")
-let ErrorFromApplyingDefault1E() = DeclareResourceString("ErrorFromApplyingDefault1", "%s")
-let ErrorFromApplyingDefault2E() = DeclareResourceString("ErrorFromApplyingDefault2", "")
-let ErrorsFromAddingSubsumptionConstraintE() = DeclareResourceString("ErrorsFromAddingSubsumptionConstraint", "%s%s%s")
-let UpperCaseIdentifierInPatternE() = DeclareResourceString("UpperCaseIdentifierInPattern", "")
-let NotUpperCaseConstructorE() = DeclareResourceString("NotUpperCaseConstructor", "")
-let PossibleOverloadE() = DeclareResourceString("PossibleOverload", "%s%s")
-let FunctionExpectedE() = DeclareResourceString("FunctionExpected", "")
-let BakedInMemberConstraintNameE() = DeclareResourceString("BakedInMemberConstraintName", "%s")
-let BadEventTransformationE() = DeclareResourceString("BadEventTransformation", "")
-let ParameterlessStructCtorE() = DeclareResourceString("ParameterlessStructCtor", "")
-let InterfaceNotRevealedE() = DeclareResourceString("InterfaceNotRevealed", "%s")
-let TyconBadArgsE() = DeclareResourceString("TyconBadArgs", "%s%d%d")
-let IndeterminateTypeE() = DeclareResourceString("IndeterminateType", "")
-let NameClash1E() = DeclareResourceString("NameClash1", "%s%s")
-let NameClash2E() = DeclareResourceString("NameClash2", "%s%s%s%s%s")
-let Duplicate1E() = DeclareResourceString("Duplicate1", "%s")
-let Duplicate2E() = DeclareResourceString("Duplicate2", "%s%s")
-let UndefinedName2E() = DeclareResourceString("UndefinedName2", "")
-let FieldNotMutableE() = DeclareResourceString("FieldNotMutable", "")
-let FieldsFromDifferentTypesE() = DeclareResourceString("FieldsFromDifferentTypes", "%s%s")
-let VarBoundTwiceE() = DeclareResourceString("VarBoundTwice", "%s")
-let RecursionE() = DeclareResourceString("Recursion", "%s%s%s%s")
-let InvalidRuntimeCoercionE() = DeclareResourceString("InvalidRuntimeCoercion", "%s%s%s")
-let IndeterminateRuntimeCoercionE() = DeclareResourceString("IndeterminateRuntimeCoercion", "%s%s")
-let IndeterminateStaticCoercionE() = DeclareResourceString("IndeterminateStaticCoercion", "%s%s")
-let StaticCoercionShouldUseBoxE() = DeclareResourceString("StaticCoercionShouldUseBox", "%s%s")
-let TypeIsImplicitlyAbstractE() = DeclareResourceString("TypeIsImplicitlyAbstract", "")
-let NonRigidTypar1E() = DeclareResourceString("NonRigidTypar1", "%s%s")
-let NonRigidTypar2E() = DeclareResourceString("NonRigidTypar2", "%s%s")
-let NonRigidTypar3E() = DeclareResourceString("NonRigidTypar3", "%s%s")
-let OBlockEndSentenceE() = DeclareResourceString("BlockEndSentence", "")
-let UnexpectedEndOfInputE() = DeclareResourceString("UnexpectedEndOfInput", "")
-let UnexpectedE() = DeclareResourceString("Unexpected", "%s")
-let NONTERM_interactionE() = DeclareResourceString("NONTERM.interaction", "")
-let NONTERM_hashDirectiveE() = DeclareResourceString("NONTERM.hashDirective", "")
-let NONTERM_fieldDeclE() = DeclareResourceString("NONTERM.fieldDecl", "")
-let NONTERM_unionCaseReprE() = DeclareResourceString("NONTERM.unionCaseRepr", "")
-let NONTERM_localBindingE() = DeclareResourceString("NONTERM.localBinding", "")
-let NONTERM_hardwhiteLetBindingsE() = DeclareResourceString("NONTERM.hardwhiteLetBindings", "")
-let NONTERM_classDefnMemberE() = DeclareResourceString("NONTERM.classDefnMember", "")
-let NONTERM_defnBindingsE() = DeclareResourceString("NONTERM.defnBindings", "")
-let NONTERM_classMemberSpfnE() = DeclareResourceString("NONTERM.classMemberSpfn", "")
-let NONTERM_valSpfnE() = DeclareResourceString("NONTERM.valSpfn", "")
-let NONTERM_tyconSpfnE() = DeclareResourceString("NONTERM.tyconSpfn", "")
-let NONTERM_anonLambdaExprE() = DeclareResourceString("NONTERM.anonLambdaExpr", "")
-let NONTERM_attrUnionCaseDeclE() = DeclareResourceString("NONTERM.attrUnionCaseDecl", "")
-let NONTERM_cPrototypeE() = DeclareResourceString("NONTERM.cPrototype", "")
-let NONTERM_objectImplementationMembersE() = DeclareResourceString("NONTERM.objectImplementationMembers", "")
-let NONTERM_ifExprCasesE() = DeclareResourceString("NONTERM.ifExprCases", "")
-let NONTERM_openDeclE() = DeclareResourceString("NONTERM.openDecl", "")
-let NONTERM_fileModuleSpecE() = DeclareResourceString("NONTERM.fileModuleSpec", "")
-let NONTERM_patternClausesE() = DeclareResourceString("NONTERM.patternClauses", "")
-let NONTERM_beginEndExprE() = DeclareResourceString("NONTERM.beginEndExpr", "")
-let NONTERM_recdExprE() = DeclareResourceString("NONTERM.recdExpr", "")
-let NONTERM_tyconDefnE() = DeclareResourceString("NONTERM.tyconDefn", "")
-let NONTERM_exconCoreE() = DeclareResourceString("NONTERM.exconCore", "")
-let NONTERM_typeNameInfoE() = DeclareResourceString("NONTERM.typeNameInfo", "")
-let NONTERM_attributeListE() = DeclareResourceString("NONTERM.attributeList", "")
-let NONTERM_quoteExprE() = DeclareResourceString("NONTERM.quoteExpr", "")
-let NONTERM_typeConstraintE() = DeclareResourceString("NONTERM.typeConstraint", "")
-let NONTERM_Category_ImplementationFileE() = DeclareResourceString("NONTERM.Category.ImplementationFile", "")
-let NONTERM_Category_DefinitionE() = DeclareResourceString("NONTERM.Category.Definition", "")
-let NONTERM_Category_SignatureFileE() = DeclareResourceString("NONTERM.Category.SignatureFile", "")
-let NONTERM_Category_PatternE() = DeclareResourceString("NONTERM.Category.Pattern", "")
-let NONTERM_Category_ExprE() = DeclareResourceString("NONTERM.Category.Expr", "")
-let NONTERM_Category_TypeE() = DeclareResourceString("NONTERM.Category.Type", "")
-let NONTERM_typeArgsActualE() = DeclareResourceString("NONTERM.typeArgsActual", "")
-let TokenName1E() = DeclareResourceString("TokenName1", "%s")
-let TokenName1TokenName2E() = DeclareResourceString("TokenName1TokenName2", "%s%s")
-let TokenName1TokenName2TokenName3E() = DeclareResourceString("TokenName1TokenName2TokenName3", "%s%s%s")
-let RuntimeCoercionSourceSealed1E() = DeclareResourceString("RuntimeCoercionSourceSealed1", "%s")
-let RuntimeCoercionSourceSealed2E() = DeclareResourceString("RuntimeCoercionSourceSealed2", "%s")
-let CoercionTargetSealedE() = DeclareResourceString("CoercionTargetSealed", "%s")
-let UpcastUnnecessaryE() = DeclareResourceString("UpcastUnnecessary", "")
-let TypeTestUnnecessaryE() = DeclareResourceString("TypeTestUnnecessary", "")
-let OverrideDoesntOverride1E() = DeclareResourceString("OverrideDoesntOverride1", "%s")
-let OverrideDoesntOverride2E() = DeclareResourceString("OverrideDoesntOverride2", "%s")
-let OverrideDoesntOverride3E() = DeclareResourceString("OverrideDoesntOverride3", "%s")
-let OverrideDoesntOverride4E() = DeclareResourceString("OverrideDoesntOverride4", "%s")
-let UnionCaseWrongArgumentsE() = DeclareResourceString("UnionCaseWrongArguments", "%d%d")
-let UnionPatternsBindDifferentNamesE() = DeclareResourceString("UnionPatternsBindDifferentNames", "")
-let RequiredButNotSpecifiedE() = DeclareResourceString("RequiredButNotSpecified", "%s%s%s")
-let UseOfAddressOfOperatorE() = DeclareResourceString("UseOfAddressOfOperator", "")
-let DefensiveCopyWarningE() = DeclareResourceString("DefensiveCopyWarning", "%s")
-let DeprecatedThreadStaticBindingWarningE() = DeclareResourceString("DeprecatedThreadStaticBindingWarning", "")
-let FunctionValueUnexpectedE() = DeclareResourceString("FunctionValueUnexpected", "%s")
-let UnitTypeExpectedE() = DeclareResourceString("UnitTypeExpected", "%s")
-let UnitTypeExpectedWithEqualityE() = DeclareResourceString("UnitTypeExpectedWithEquality", "%s")
-let UnitTypeExpectedWithPossiblePropertySetterE() = DeclareResourceString("UnitTypeExpectedWithPossiblePropertySetter", "%s%s%s")
-let UnitTypeExpectedWithPossibleAssignmentE() = DeclareResourceString("UnitTypeExpectedWithPossibleAssignment", "%s%s")
-let UnitTypeExpectedWithPossibleAssignmentToMutableE() = DeclareResourceString("UnitTypeExpectedWithPossibleAssignmentToMutable", "%s%s")
-let RecursiveUseCheckedAtRuntimeE() = DeclareResourceString("RecursiveUseCheckedAtRuntime", "")
-let LetRecUnsound1E() = DeclareResourceString("LetRecUnsound1", "%s")
-let LetRecUnsound2E() = DeclareResourceString("LetRecUnsound2", "%s%s")
-let LetRecUnsoundInnerE() = DeclareResourceString("LetRecUnsoundInner", "%s")
-let LetRecEvaluatedOutOfOrderE() = DeclareResourceString("LetRecEvaluatedOutOfOrder", "")
-let LetRecCheckedAtRuntimeE() = DeclareResourceString("LetRecCheckedAtRuntime", "")
-let SelfRefObjCtor1E() = DeclareResourceString("SelfRefObjCtor1", "")
-let SelfRefObjCtor2E() = DeclareResourceString("SelfRefObjCtor2", "")
-let VirtualAugmentationOnNullValuedTypeE() = DeclareResourceString("VirtualAugmentationOnNullValuedType", "")
-let NonVirtualAugmentationOnNullValuedTypeE() = DeclareResourceString("NonVirtualAugmentationOnNullValuedType", "")
-let NonUniqueInferredAbstractSlot1E() = DeclareResourceString("NonUniqueInferredAbstractSlot1", "%s")
-let NonUniqueInferredAbstractSlot2E() = DeclareResourceString("NonUniqueInferredAbstractSlot2", "")
-let NonUniqueInferredAbstractSlot3E() = DeclareResourceString("NonUniqueInferredAbstractSlot3", "%s%s")
-let NonUniqueInferredAbstractSlot4E() = DeclareResourceString("NonUniqueInferredAbstractSlot4", "")
-let Failure3E() = DeclareResourceString("Failure3", "%s")
-let Failure4E() = DeclareResourceString("Failure4", "%s")
-let FullAbstractionE() = DeclareResourceString("FullAbstraction", "%s")
-let MatchIncomplete1E() = DeclareResourceString("MatchIncomplete1", "")
-let MatchIncomplete2E() = DeclareResourceString("MatchIncomplete2", "%s")
-let MatchIncomplete3E() = DeclareResourceString("MatchIncomplete3", "%s")
-let MatchIncomplete4E() = DeclareResourceString("MatchIncomplete4", "")
-let RuleNeverMatchedE() = DeclareResourceString("RuleNeverMatched", "")
-let EnumMatchIncomplete1E() = DeclareResourceString("EnumMatchIncomplete1", "")
-let ValNotMutableE() = DeclareResourceString("ValNotMutable", "%s")
-let ValNotLocalE() = DeclareResourceString("ValNotLocal", "")
-let Obsolete1E() = DeclareResourceString("Obsolete1", "")
-let Obsolete2E() = DeclareResourceString("Obsolete2", "%s")
-let ExperimentalE() = DeclareResourceString("Experimental", "%s")
-let PossibleUnverifiableCodeE() = DeclareResourceString("PossibleUnverifiableCode", "")
-let DeprecatedE() = DeclareResourceString("Deprecated", "%s")
-let LibraryUseOnlyE() = DeclareResourceString("LibraryUseOnly", "")
-let MissingFieldsE() = DeclareResourceString("MissingFields", "%s")
-let ValueRestriction1E() = DeclareResourceString("ValueRestriction1", "%s%s%s")
-let ValueRestriction2E() = DeclareResourceString("ValueRestriction2", "%s%s%s")
-let ValueRestriction3E() = DeclareResourceString("ValueRestriction3", "%s")
-let ValueRestriction4E() = DeclareResourceString("ValueRestriction4", "%s%s%s")
-let ValueRestriction5E() = DeclareResourceString("ValueRestriction5", "%s%s%s")
-let RecoverableParseErrorE() = DeclareResourceString("RecoverableParseError", "")
-let ReservedKeywordE() = DeclareResourceString("ReservedKeyword", "%s")
-let IndentationProblemE() = DeclareResourceString("IndentationProblem", "%s")
-let OverrideInIntrinsicAugmentationE() = DeclareResourceString("OverrideInIntrinsicAugmentation", "")
-let OverrideInExtrinsicAugmentationE() = DeclareResourceString("OverrideInExtrinsicAugmentation", "")
-let IntfImplInIntrinsicAugmentationE() = DeclareResourceString("IntfImplInIntrinsicAugmentation", "")
-let IntfImplInExtrinsicAugmentationE() = DeclareResourceString("IntfImplInExtrinsicAugmentation", "")
-let UnresolvedReferenceNoRangeE() = DeclareResourceString("UnresolvedReferenceNoRange", "%s")
-let UnresolvedPathReferenceNoRangeE() = DeclareResourceString("UnresolvedPathReferenceNoRange", "%s%s")
-let HashIncludeNotAllowedInNonScriptE() = DeclareResourceString("HashIncludeNotAllowedInNonScript", "")
-let HashReferenceNotAllowedInNonScriptE() = DeclareResourceString("HashReferenceNotAllowedInNonScript", "")
-let HashDirectiveNotAllowedInNonScriptE() = DeclareResourceString("HashDirectiveNotAllowedInNonScript", "")
-let FileNameNotResolvedE() = DeclareResourceString("FileNameNotResolved", "%s%s")
-let AssemblyNotResolvedE() = DeclareResourceString("AssemblyNotResolved", "%s")
-let HashLoadedSourceHasIssues1E() = DeclareResourceString("HashLoadedSourceHasIssues1", "")
-let HashLoadedSourceHasIssues2E() = DeclareResourceString("HashLoadedSourceHasIssues2", "")
-let HashLoadedScriptConsideredSourceE() = DeclareResourceString("HashLoadedScriptConsideredSource", "")
-let InvalidInternalsVisibleToAssemblyName1E() = DeclareResourceString("InvalidInternalsVisibleToAssemblyName1", "%s%s")
-let InvalidInternalsVisibleToAssemblyName2E() = DeclareResourceString("InvalidInternalsVisibleToAssemblyName2", "%s")
-let LoadedSourceNotFoundIgnoringE() = DeclareResourceString("LoadedSourceNotFoundIgnoring", "%s")
-let MSBuildReferenceResolutionErrorE() = DeclareResourceString("MSBuildReferenceResolutionError", "%s%s")
-let TargetInvocationExceptionWrapperE() = DeclareResourceString("TargetInvocationExceptionWrapper", "%s")
-
-let getErrorString key = SR.GetString key
-
-let (|InvalidArgument|_|) (exn: exn) = match exn with :? ArgumentException as e -> Some e.Message | _ -> None
-
-let OutputPhasedErrorR (os: StringBuilder) (err: PhasedDiagnostic) (canSuggestNames: bool) =
-
- let suggestNames suggestionsF idText =
- if canSuggestNames then
- let buffer = ErrorResolutionHints.SuggestionBuffer idText
- if not buffer.Disabled then
- suggestionsF buffer.Add
- if not buffer.IsEmpty then
- os.Append " " |> ignore
- os.Append(FSComp.SR.undefinedNameSuggestionsIntro()) |> ignore
- for value in buffer do
- os.AppendLine() |> ignore
- os.Append " " |> ignore
- os.Append(DecompileOpName value) |> ignore
-
- let rec OutputExceptionR (os: StringBuilder) error =
-
- match error with
- | ConstraintSolverTupleDiffLengths(_, tl1, tl2, m, m2) ->
- os.Append(ConstraintSolverTupleDiffLengthsE().Format tl1.Length tl2.Length) |> ignore
- if m.StartLine <> m2.StartLine then
- os.Append(SeeAlsoE().Format (stringOfRange m)) |> ignore
-
- | ConstraintSolverInfiniteTypes(denv, contextInfo, t1, t2, m, m2) ->
- // REVIEW: consider if we need to show _cxs (the type parameter constraints)
- let t1, t2, _cxs = NicePrint.minimalStringsOfTwoTypes denv t1 t2
- os.Append(ConstraintSolverInfiniteTypesE().Format t1 t2) |> ignore
-
- match contextInfo with
- | ContextInfo.ReturnInComputationExpression ->
- os.Append(" " + FSComp.SR.returnUsedInsteadOfReturnBang()) |> ignore
- | ContextInfo.YieldInComputationExpression ->
- os.Append(" " + FSComp.SR.yieldUsedInsteadOfYieldBang()) |> ignore
- | _ -> ()
-
- if m.StartLine <> m2.StartLine then
- os.Append(SeeAlsoE().Format (stringOfRange m)) |> ignore
-
- | ConstraintSolverMissingConstraint(denv, tpr, tpc, m, m2) ->
- os.Append(ConstraintSolverMissingConstraintE().Format (NicePrint.stringOfTyparConstraint denv (tpr, tpc))) |> ignore
- if m.StartLine <> m2.StartLine then
- os.Append(SeeAlsoE().Format (stringOfRange m)) |> ignore
-
- | ConstraintSolverTypesNotInEqualityRelation(denv, (TType_measure _ as t1), (TType_measure _ as t2), m, m2, _) ->
- // REVIEW: consider if we need to show _cxs (the type parameter constraints)
- let t1, t2, _cxs = NicePrint.minimalStringsOfTwoTypes denv t1 t2
-
- os.Append(ConstraintSolverTypesNotInEqualityRelation1E().Format t1 t2 ) |> ignore
-
- if m.StartLine <> m2.StartLine then
- os.Append(SeeAlsoE().Format (stringOfRange m)) |> ignore
-
- | ConstraintSolverTypesNotInEqualityRelation(denv, t1, t2, m, m2, contextInfo) ->
- // REVIEW: consider if we need to show _cxs (the type parameter constraints)
- let t1, t2, _cxs = NicePrint.minimalStringsOfTwoTypes denv t1 t2
-
- match contextInfo with
- | ContextInfo.IfExpression range when Range.equals range m -> os.Append(FSComp.SR.ifExpression(t1, t2)) |> ignore
- | ContextInfo.CollectionElement (isArray, range) when Range.equals range m ->
- if isArray then
- os.Append(FSComp.SR.arrayElementHasWrongType(t1, t2)) |> ignore
- else
- os.Append(FSComp.SR.listElementHasWrongType(t1, t2)) |> ignore
- | ContextInfo.OmittedElseBranch range when Range.equals range m -> os.Append(FSComp.SR.missingElseBranch(t2)) |> ignore
- | ContextInfo.ElseBranchResult range when Range.equals range m -> os.Append(FSComp.SR.elseBranchHasWrongType(t1, t2)) |> ignore
- | ContextInfo.FollowingPatternMatchClause range when Range.equals range m -> os.Append(FSComp.SR.followingPatternMatchClauseHasWrongType(t1, t2)) |> ignore
- | ContextInfo.PatternMatchGuard range when Range.equals range m -> os.Append(FSComp.SR.patternMatchGuardIsNotBool(t2)) |> ignore
- | _ -> os.Append(ConstraintSolverTypesNotInEqualityRelation2E().Format t1 t2) |> ignore
- if m.StartLine <> m2.StartLine then
- os.Append(SeeAlsoE().Format (stringOfRange m)) |> ignore
-
- | ConstraintSolverTypesNotInSubsumptionRelation(denv, t1, t2, m, m2) ->
- // REVIEW: consider if we need to show _cxs (the type parameter constraints)
- let t1, t2, cxs = NicePrint.minimalStringsOfTwoTypes denv t1 t2
- os.Append(ConstraintSolverTypesNotInSubsumptionRelationE().Format t2 t1 cxs) |> ignore
- if m.StartLine <> m2.StartLine then
- os.Append(SeeAlsoE().Format (stringOfRange m2)) |> ignore
-
- | ConstraintSolverError(msg, m, m2) ->
- os.Append msg |> ignore
- if m.StartLine <> m2.StartLine then
- os.Append(SeeAlsoE().Format (stringOfRange m2)) |> ignore
-
- | ConstraintSolverRelatedInformation(fopt, _, e) ->
- match e with
- | ConstraintSolverError _ -> OutputExceptionR os e
- | _ -> ()
- fopt |> Option.iter (Printf.bprintf os " %s")
-
- | ErrorFromAddingTypeEquation(g, denv, t1, t2, ConstraintSolverTypesNotInEqualityRelation(_, t1', t2', m, _, contextInfo), _)
- when typeEquiv g t1 t1'
- && typeEquiv g t2 t2' ->
- let t1, t2, tpcs = NicePrint.minimalStringsOfTwoTypes denv t1 t2
- match contextInfo with
- | ContextInfo.IfExpression range when Range.equals range m -> os.Append(FSComp.SR.ifExpression(t1, t2)) |> ignore
- | ContextInfo.CollectionElement (isArray, range) when Range.equals range m ->
- if isArray then
- os.Append(FSComp.SR.arrayElementHasWrongType(t1, t2)) |> ignore
- else
- os.Append(FSComp.SR.listElementHasWrongType(t1, t2)) |> ignore
- | ContextInfo.OmittedElseBranch range when Range.equals range m -> os.Append(FSComp.SR.missingElseBranch(t2)) |> ignore
- | ContextInfo.ElseBranchResult range when Range.equals range m -> os.Append(FSComp.SR.elseBranchHasWrongType(t1, t2)) |> ignore
- | ContextInfo.FollowingPatternMatchClause range when Range.equals range m -> os.Append(FSComp.SR.followingPatternMatchClauseHasWrongType(t1, t2)) |> ignore
- | ContextInfo.PatternMatchGuard range when Range.equals range m -> os.Append(FSComp.SR.patternMatchGuardIsNotBool(t2)) |> ignore
- | ContextInfo.TupleInRecordFields ->
- os.Append(ErrorFromAddingTypeEquation1E().Format t2 t1 tpcs) |> ignore
- os.Append(System.Environment.NewLine + FSComp.SR.commaInsteadOfSemicolonInRecord()) |> ignore
- | _ when t2 = "bool" && t1.EndsWithOrdinal(" ref") ->
- os.Append(ErrorFromAddingTypeEquation1E().Format t2 t1 tpcs) |> ignore
- os.Append(System.Environment.NewLine + FSComp.SR.derefInsteadOfNot()) |> ignore
- | _ -> os.Append(ErrorFromAddingTypeEquation1E().Format t2 t1 tpcs) |> ignore
-
- | ErrorFromAddingTypeEquation(_, _, _, _, ((ConstraintSolverTypesNotInEqualityRelation (_, _, _, _, _, contextInfo) ) as e), _) when (match contextInfo with ContextInfo.NoContext -> false | _ -> true) ->
- OutputExceptionR os e
-
- | ErrorFromAddingTypeEquation(_, _, _, _, ((ConstraintSolverTypesNotInSubsumptionRelation _ | ConstraintSolverError _ ) as e), _) ->
- OutputExceptionR os e
-
- | ErrorFromAddingTypeEquation(g, denv, t1, t2, e, _) ->
- if not (typeEquiv g t1 t2) then
- let t1, t2, tpcs = NicePrint.minimalStringsOfTwoTypes denv t1 t2
- if t1<>t2 + tpcs then os.Append(ErrorFromAddingTypeEquation2E().Format t1 t2 tpcs) |> ignore
-
- OutputExceptionR os e
-
- | ErrorFromApplyingDefault(_, denv, _, defaultType, e, _) ->
- let defaultType = NicePrint.minimalStringOfType denv defaultType
- os.Append(ErrorFromApplyingDefault1E().Format defaultType) |> ignore
- OutputExceptionR os e
- os.Append(ErrorFromApplyingDefault2E().Format) |> ignore
-
- | ErrorsFromAddingSubsumptionConstraint(g, denv, t1, t2, e, contextInfo, _) ->
- match contextInfo with
- | ContextInfo.DowncastUsedInsteadOfUpcast isOperator ->
- let t1, t2, _ = NicePrint.minimalStringsOfTwoTypes denv t1 t2
- if isOperator then
- os.Append(FSComp.SR.considerUpcastOperator(t1, t2) |> snd) |> ignore
- else
- os.Append(FSComp.SR.considerUpcast(t1, t2) |> snd) |> ignore
- | _ ->
- if not (typeEquiv g t1 t2) then
- let t1, t2, tpcs = NicePrint.minimalStringsOfTwoTypes denv t1 t2
- if t1 <> (t2 + tpcs) then
- os.Append(ErrorsFromAddingSubsumptionConstraintE().Format t2 t1 tpcs) |> ignore
- else
- OutputExceptionR os e
- else
- OutputExceptionR os e
-
- | UpperCaseIdentifierInPattern(_) ->
- os.Append(UpperCaseIdentifierInPatternE().Format) |> ignore
-
- | NotUpperCaseConstructor(_) ->
- os.Append(NotUpperCaseConstructorE().Format) |> ignore
-
- | ErrorFromAddingConstraint(_, e, _) ->
- OutputExceptionR os e
-
-#if !NO_EXTENSIONTYPING
- | ExtensionTyping.ProvidedTypeResolutionNoRange e
-
- | ExtensionTyping.ProvidedTypeResolution(_, e) ->
- OutputExceptionR os e
-
- | :? TypeProviderError as e ->
- os.Append(e.ContextualErrorMessage) |> ignore
-#endif
-
- | UnresolvedOverloading(_, _, mtext, _) ->
- os.Append mtext |> ignore
-
- | UnresolvedConversionOperator(denv, fromTy, toTy, _) ->
- let t1, t2, _tpcs = NicePrint.minimalStringsOfTwoTypes denv fromTy toTy
- os.Append(FSComp.SR.csTypeDoesNotSupportConversion(t1, t2)) |> ignore
-
- | PossibleOverload(_, minfo, originalError, _) ->
- // print original error that describes reason why this overload was rejected
- let buf = new StringBuilder()
- OutputExceptionR buf originalError
-
- os.Append(PossibleOverloadE().Format minfo (buf.ToString())) |> ignore
-
- | FunctionExpected _ ->
- os.Append(FunctionExpectedE().Format) |> ignore
-
- | BakedInMemberConstraintName(nm, _) ->
- os.Append(BakedInMemberConstraintNameE().Format nm) |> ignore
-
- | StandardOperatorRedefinitionWarning(msg, _) ->
- os.Append msg |> ignore
-
- | BadEventTransformation(_) ->
- os.Append(BadEventTransformationE().Format) |> ignore
-
- | ParameterlessStructCtor(_) ->
- os.Append(ParameterlessStructCtorE().Format) |> ignore
-
- | InterfaceNotRevealed(denv, ity, _) ->
- os.Append(InterfaceNotRevealedE().Format (NicePrint.minimalStringOfType denv ity)) |> ignore
-
- | NotAFunctionButIndexer(_, _, name, _, _) ->
- match name with
- | Some name -> os.Append(FSComp.SR.notAFunctionButMaybeIndexerWithName name) |> ignore
- | _ -> os.Append(FSComp.SR.notAFunctionButMaybeIndexer()) |> ignore
-
- | NotAFunction(_, _, _, marg) ->
- if marg.StartColumn = 0 then
- os.Append(FSComp.SR.notAFunctionButMaybeDeclaration()) |> ignore
- else
- os.Append(FSComp.SR.notAFunction()) |> ignore
-
- | TyconBadArgs(_, tcref, d, _) ->
- let exp = tcref.TyparsNoRange.Length
- if exp = 0 then
- os.Append(FSComp.SR.buildUnexpectedTypeArgs(fullDisplayTextOfTyconRef tcref, d)) |> ignore
- else
- os.Append(TyconBadArgsE().Format (fullDisplayTextOfTyconRef tcref) exp d) |> ignore
-
- | IndeterminateType(_) ->
- os.Append(IndeterminateTypeE().Format) |> ignore
-
- | NameClash(nm, k1, nm1, _, k2, nm2, _) ->
- if nm = nm1 && nm1 = nm2 && k1 = k2 then
- os.Append(NameClash1E().Format k1 nm1) |> ignore
- else
- os.Append(NameClash2E().Format k1 nm1 nm k2 nm2) |> ignore
-
- | Duplicate(k, s, _) ->
- if k = "member" then
- os.Append(Duplicate1E().Format (DecompileOpName s)) |> ignore
- else
- os.Append(Duplicate2E().Format k (DecompileOpName s)) |> ignore
-
- | UndefinedName(_, k, id, suggestionsF) ->
- os.Append(k (DecompileOpName id.idText)) |> ignore
- suggestNames suggestionsF id.idText
-
- | InternalUndefinedItemRef(f, smr, ccuName, s) ->
- let _, errs = f(smr, ccuName, s)
- os.Append errs |> ignore
-
- | FieldNotMutable _ ->
- os.Append(FieldNotMutableE().Format) |> ignore
-
- | FieldsFromDifferentTypes (_, fref1, fref2, _) ->
- os.Append(FieldsFromDifferentTypesE().Format fref1.FieldName fref2.FieldName) |> ignore
-
- | VarBoundTwice id ->
- os.Append(VarBoundTwiceE().Format (DecompileOpName id.idText)) |> ignore
-
- | Recursion (denv, id, ty1, ty2, _) ->
- let t1, t2, tpcs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2
- os.Append(RecursionE().Format (DecompileOpName id.idText) t1 t2 tpcs) |> ignore
-
- | InvalidRuntimeCoercion(denv, ty1, ty2, _) ->
- let t1, t2, tpcs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2
- os.Append(InvalidRuntimeCoercionE().Format t1 t2 tpcs) |> ignore
-
- | IndeterminateRuntimeCoercion(denv, ty1, ty2, _) ->
- let t1, t2, _cxs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2
- os.Append(IndeterminateRuntimeCoercionE().Format t1 t2) |> ignore
-
- | IndeterminateStaticCoercion(denv, ty1, ty2, _) ->
- // REVIEW: consider if we need to show _cxs (the type parameter constraints)
- let t1, t2, _cxs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2
- os.Append(IndeterminateStaticCoercionE().Format t1 t2) |> ignore
-
- | StaticCoercionShouldUseBox(denv, ty1, ty2, _) ->
- // REVIEW: consider if we need to show _cxs (the type parameter constraints)
- let t1, t2, _cxs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2
- os.Append(StaticCoercionShouldUseBoxE().Format t1 t2) |> ignore
-
- | TypeIsImplicitlyAbstract(_) ->
- os.Append(TypeIsImplicitlyAbstractE().Format) |> ignore
-
- | NonRigidTypar(denv, tpnmOpt, typarRange, ty1, ty, _) ->
- // REVIEW: consider if we need to show _cxs (the type parameter constraints)
- let (ty1, ty), _cxs = PrettyTypes.PrettifyTypePair denv.g (ty1, ty)
- match tpnmOpt with
- | None ->
- os.Append(NonRigidTypar1E().Format (stringOfRange typarRange) (NicePrint.stringOfTy denv ty)) |> ignore
- | Some tpnm ->
- match ty1 with
- | TType_measure _ ->
- os.Append(NonRigidTypar2E().Format tpnm (NicePrint.stringOfTy denv ty)) |> ignore
- | _ ->
- os.Append(NonRigidTypar3E().Format tpnm (NicePrint.stringOfTy denv ty)) |> ignore
-
- | SyntaxError (ctxt, _) ->
- let ctxt = unbox>(ctxt)
-
- let (|EndOfStructuredConstructToken|_|) token =
- match token with
- | Parser.TOKEN_ODECLEND
- | Parser.TOKEN_OBLOCKSEP
- | Parser.TOKEN_OEND
- | Parser.TOKEN_ORIGHT_BLOCK_END
- | Parser.TOKEN_OBLOCKEND | Parser.TOKEN_OBLOCKEND_COMING_SOON | Parser.TOKEN_OBLOCKEND_IS_HERE -> Some()
- | _ -> None
-
- let tokenIdToText tid =
- match tid with
- | Parser.TOKEN_IDENT -> getErrorString("Parser.TOKEN.IDENT")
- | Parser.TOKEN_BIGNUM
- | Parser.TOKEN_INT8
- | Parser.TOKEN_UINT8
- | Parser.TOKEN_INT16
- | Parser.TOKEN_UINT16
- | Parser.TOKEN_INT32
- | Parser.TOKEN_UINT32
- | Parser.TOKEN_INT64
- | Parser.TOKEN_UINT64
- | Parser.TOKEN_UNATIVEINT
- | Parser.TOKEN_NATIVEINT -> getErrorString("Parser.TOKEN.INT")
- | Parser.TOKEN_IEEE32
- | Parser.TOKEN_IEEE64 -> getErrorString("Parser.TOKEN.FLOAT")
- | Parser.TOKEN_DECIMAL -> getErrorString("Parser.TOKEN.DECIMAL")
- | Parser.TOKEN_CHAR -> getErrorString("Parser.TOKEN.CHAR")
-
- | Parser.TOKEN_BASE -> getErrorString("Parser.TOKEN.BASE")
- | Parser.TOKEN_LPAREN_STAR_RPAREN -> getErrorString("Parser.TOKEN.LPAREN.STAR.RPAREN")
- | Parser.TOKEN_DOLLAR -> getErrorString("Parser.TOKEN.DOLLAR")
- | Parser.TOKEN_INFIX_STAR_STAR_OP -> getErrorString("Parser.TOKEN.INFIX.STAR.STAR.OP")
- | Parser.TOKEN_INFIX_COMPARE_OP -> getErrorString("Parser.TOKEN.INFIX.COMPARE.OP")
- | Parser.TOKEN_COLON_GREATER -> getErrorString("Parser.TOKEN.COLON.GREATER")
- | Parser.TOKEN_COLON_COLON ->getErrorString("Parser.TOKEN.COLON.COLON")
- | Parser.TOKEN_PERCENT_OP -> getErrorString("Parser.TOKEN.PERCENT.OP")
- | Parser.TOKEN_INFIX_AT_HAT_OP -> getErrorString("Parser.TOKEN.INFIX.AT.HAT.OP")
- | Parser.TOKEN_INFIX_BAR_OP -> getErrorString("Parser.TOKEN.INFIX.BAR.OP")
- | Parser.TOKEN_PLUS_MINUS_OP -> getErrorString("Parser.TOKEN.PLUS.MINUS.OP")
- | Parser.TOKEN_PREFIX_OP -> getErrorString("Parser.TOKEN.PREFIX.OP")
- | Parser.TOKEN_COLON_QMARK_GREATER -> getErrorString("Parser.TOKEN.COLON.QMARK.GREATER")
- | Parser.TOKEN_INFIX_STAR_DIV_MOD_OP -> getErrorString("Parser.TOKEN.INFIX.STAR.DIV.MOD.OP")
- | Parser.TOKEN_INFIX_AMP_OP -> getErrorString("Parser.TOKEN.INFIX.AMP.OP")
- | Parser.TOKEN_AMP -> getErrorString("Parser.TOKEN.AMP")
- | Parser.TOKEN_AMP_AMP -> getErrorString("Parser.TOKEN.AMP.AMP")
- | Parser.TOKEN_BAR_BAR -> getErrorString("Parser.TOKEN.BAR.BAR")
- | Parser.TOKEN_LESS -> getErrorString("Parser.TOKEN.LESS")
- | Parser.TOKEN_GREATER -> getErrorString("Parser.TOKEN.GREATER")
- | Parser.TOKEN_QMARK -> getErrorString("Parser.TOKEN.QMARK")
- | Parser.TOKEN_QMARK_QMARK -> getErrorString("Parser.TOKEN.QMARK.QMARK")
- | Parser.TOKEN_COLON_QMARK-> getErrorString("Parser.TOKEN.COLON.QMARK")
- | Parser.TOKEN_INT32_DOT_DOT -> getErrorString("Parser.TOKEN.INT32.DOT.DOT")
- | Parser.TOKEN_DOT_DOT -> getErrorString("Parser.TOKEN.DOT.DOT")
- | Parser.TOKEN_QUOTE -> getErrorString("Parser.TOKEN.QUOTE")
- | Parser.TOKEN_STAR -> getErrorString("Parser.TOKEN.STAR")
- | Parser.TOKEN_HIGH_PRECEDENCE_TYAPP -> getErrorString("Parser.TOKEN.HIGH.PRECEDENCE.TYAPP")
- | Parser.TOKEN_COLON -> getErrorString("Parser.TOKEN.COLON")
- | Parser.TOKEN_COLON_EQUALS -> getErrorString("Parser.TOKEN.COLON.EQUALS")
- | Parser.TOKEN_LARROW -> getErrorString("Parser.TOKEN.LARROW")
- | Parser.TOKEN_EQUALS -> getErrorString("Parser.TOKEN.EQUALS")
- | Parser.TOKEN_GREATER_BAR_RBRACK -> getErrorString("Parser.TOKEN.GREATER.BAR.RBRACK")
- | Parser.TOKEN_MINUS -> getErrorString("Parser.TOKEN.MINUS")
- | Parser.TOKEN_ADJACENT_PREFIX_OP -> getErrorString("Parser.TOKEN.ADJACENT.PREFIX.OP")
- | Parser.TOKEN_FUNKY_OPERATOR_NAME -> getErrorString("Parser.TOKEN.FUNKY.OPERATOR.NAME")
- | Parser.TOKEN_COMMA-> getErrorString("Parser.TOKEN.COMMA")
- | Parser.TOKEN_DOT -> getErrorString("Parser.TOKEN.DOT")
- | Parser.TOKEN_BAR-> getErrorString("Parser.TOKEN.BAR")
- | Parser.TOKEN_HASH -> getErrorString("Parser.TOKEN.HASH")
- | Parser.TOKEN_UNDERSCORE -> getErrorString("Parser.TOKEN.UNDERSCORE")
- | Parser.TOKEN_SEMICOLON -> getErrorString("Parser.TOKEN.SEMICOLON")
- | Parser.TOKEN_SEMICOLON_SEMICOLON-> getErrorString("Parser.TOKEN.SEMICOLON.SEMICOLON")
- | Parser.TOKEN_LPAREN-> getErrorString("Parser.TOKEN.LPAREN")
- | Parser.TOKEN_RPAREN | Parser.TOKEN_RPAREN_COMING_SOON | Parser.TOKEN_RPAREN_IS_HERE -> getErrorString("Parser.TOKEN.RPAREN")
- | Parser.TOKEN_LQUOTE -> getErrorString("Parser.TOKEN.LQUOTE")
- | Parser.TOKEN_LBRACK -> getErrorString("Parser.TOKEN.LBRACK")
- | Parser.TOKEN_LBRACE_BAR -> getErrorString("Parser.TOKEN.LBRACE.BAR")
- | Parser.TOKEN_LBRACK_BAR -> getErrorString("Parser.TOKEN.LBRACK.BAR")
- | Parser.TOKEN_LBRACK_LESS -> getErrorString("Parser.TOKEN.LBRACK.LESS")
- | Parser.TOKEN_LBRACE -> getErrorString("Parser.TOKEN.LBRACE")
- | Parser.TOKEN_BAR_RBRACK -> getErrorString("Parser.TOKEN.BAR.RBRACK")
- | Parser.TOKEN_BAR_RBRACE -> getErrorString("Parser.TOKEN.BAR.RBRACE")
- | Parser.TOKEN_GREATER_RBRACK -> getErrorString("Parser.TOKEN.GREATER.RBRACK")
- | Parser.TOKEN_RQUOTE_DOT _
- | Parser.TOKEN_RQUOTE -> getErrorString("Parser.TOKEN.RQUOTE")
- | Parser.TOKEN_RBRACK -> getErrorString("Parser.TOKEN.RBRACK")
- | Parser.TOKEN_RBRACE | Parser.TOKEN_RBRACE_COMING_SOON | Parser.TOKEN_RBRACE_IS_HERE -> getErrorString("Parser.TOKEN.RBRACE")
- | Parser.TOKEN_PUBLIC -> getErrorString("Parser.TOKEN.PUBLIC")
- | Parser.TOKEN_PRIVATE -> getErrorString("Parser.TOKEN.PRIVATE")
- | Parser.TOKEN_INTERNAL -> getErrorString("Parser.TOKEN.INTERNAL")
- | Parser.TOKEN_CONSTRAINT -> getErrorString("Parser.TOKEN.CONSTRAINT")
- | Parser.TOKEN_INSTANCE -> getErrorString("Parser.TOKEN.INSTANCE")
- | Parser.TOKEN_DELEGATE -> getErrorString("Parser.TOKEN.DELEGATE")
- | Parser.TOKEN_INHERIT -> getErrorString("Parser.TOKEN.INHERIT")
- | Parser.TOKEN_CONSTRUCTOR-> getErrorString("Parser.TOKEN.CONSTRUCTOR")
- | Parser.TOKEN_DEFAULT -> getErrorString("Parser.TOKEN.DEFAULT")
- | Parser.TOKEN_OVERRIDE-> getErrorString("Parser.TOKEN.OVERRIDE")
- | Parser.TOKEN_ABSTRACT-> getErrorString("Parser.TOKEN.ABSTRACT")
- | Parser.TOKEN_CLASS-> getErrorString("Parser.TOKEN.CLASS")
- | Parser.TOKEN_MEMBER -> getErrorString("Parser.TOKEN.MEMBER")
- | Parser.TOKEN_STATIC -> getErrorString("Parser.TOKEN.STATIC")
- | Parser.TOKEN_NAMESPACE-> getErrorString("Parser.TOKEN.NAMESPACE")
- | Parser.TOKEN_OBLOCKBEGIN -> getErrorString("Parser.TOKEN.OBLOCKBEGIN")
- | EndOfStructuredConstructToken -> getErrorString("Parser.TOKEN.OBLOCKEND")
- | Parser.TOKEN_THEN
- | Parser.TOKEN_OTHEN -> getErrorString("Parser.TOKEN.OTHEN")
- | Parser.TOKEN_ELSE
- | Parser.TOKEN_OELSE -> getErrorString("Parser.TOKEN.OELSE")
- | Parser.TOKEN_LET(_)
- | Parser.TOKEN_OLET(_) -> getErrorString("Parser.TOKEN.OLET")
- | Parser.TOKEN_OBINDER
- | Parser.TOKEN_BINDER -> getErrorString("Parser.TOKEN.BINDER")
- | Parser.TOKEN_ODO -> getErrorString("Parser.TOKEN.ODO")
- | Parser.TOKEN_OWITH -> getErrorString("Parser.TOKEN.OWITH")
- | Parser.TOKEN_OFUNCTION -> getErrorString("Parser.TOKEN.OFUNCTION")
- | Parser.TOKEN_OFUN -> getErrorString("Parser.TOKEN.OFUN")
- | Parser.TOKEN_ORESET -> getErrorString("Parser.TOKEN.ORESET")
- | Parser.TOKEN_ODUMMY -> getErrorString("Parser.TOKEN.ODUMMY")
- | Parser.TOKEN_DO_BANG
- | Parser.TOKEN_ODO_BANG -> getErrorString("Parser.TOKEN.ODO.BANG")
- | Parser.TOKEN_YIELD -> getErrorString("Parser.TOKEN.YIELD")
- | Parser.TOKEN_YIELD_BANG -> getErrorString("Parser.TOKEN.YIELD.BANG")
- | Parser.TOKEN_OINTERFACE_MEMBER-> getErrorString("Parser.TOKEN.OINTERFACE.MEMBER")
- | Parser.TOKEN_ELIF -> getErrorString("Parser.TOKEN.ELIF")
- | Parser.TOKEN_RARROW -> getErrorString("Parser.TOKEN.RARROW")
- | Parser.TOKEN_SIG -> getErrorString("Parser.TOKEN.SIG")
- | Parser.TOKEN_STRUCT -> getErrorString("Parser.TOKEN.STRUCT")
- | Parser.TOKEN_UPCAST -> getErrorString("Parser.TOKEN.UPCAST")
- | Parser.TOKEN_DOWNCAST -> getErrorString("Parser.TOKEN.DOWNCAST")
- | Parser.TOKEN_NULL -> getErrorString("Parser.TOKEN.NULL")
- | Parser.TOKEN_RESERVED -> getErrorString("Parser.TOKEN.RESERVED")
- | Parser.TOKEN_MODULE | Parser.TOKEN_MODULE_COMING_SOON | Parser.TOKEN_MODULE_IS_HERE -> getErrorString("Parser.TOKEN.MODULE")
- | Parser.TOKEN_AND -> getErrorString("Parser.TOKEN.AND")
- | Parser.TOKEN_AS -> getErrorString("Parser.TOKEN.AS")
- | Parser.TOKEN_ASSERT -> getErrorString("Parser.TOKEN.ASSERT")
- | Parser.TOKEN_OASSERT -> getErrorString("Parser.TOKEN.ASSERT")
- | Parser.TOKEN_ASR-> getErrorString("Parser.TOKEN.ASR")
- | Parser.TOKEN_DOWNTO -> getErrorString("Parser.TOKEN.DOWNTO")
- | Parser.TOKEN_EXCEPTION -> getErrorString("Parser.TOKEN.EXCEPTION")
- | Parser.TOKEN_FALSE -> getErrorString("Parser.TOKEN.FALSE")
- | Parser.TOKEN_FOR -> getErrorString("Parser.TOKEN.FOR")
- | Parser.TOKEN_FUN -> getErrorString("Parser.TOKEN.FUN")
- | Parser.TOKEN_FUNCTION-> getErrorString("Parser.TOKEN.FUNCTION")
- | Parser.TOKEN_FINALLY -> getErrorString("Parser.TOKEN.FINALLY")
- | Parser.TOKEN_LAZY -> getErrorString("Parser.TOKEN.LAZY")
- | Parser.TOKEN_OLAZY -> getErrorString("Parser.TOKEN.LAZY")
- | Parser.TOKEN_MATCH -> getErrorString("Parser.TOKEN.MATCH")
- | Parser.TOKEN_MATCH_BANG -> getErrorString("Parser.TOKEN.MATCH.BANG")
- | Parser.TOKEN_MUTABLE -> getErrorString("Parser.TOKEN.MUTABLE")
- | Parser.TOKEN_NEW -> getErrorString("Parser.TOKEN.NEW")
- | Parser.TOKEN_OF -> getErrorString("Parser.TOKEN.OF")
- | Parser.TOKEN_OPEN -> getErrorString("Parser.TOKEN.OPEN")
- | Parser.TOKEN_OR -> getErrorString("Parser.TOKEN.OR")
- | Parser.TOKEN_VOID -> getErrorString("Parser.TOKEN.VOID")
- | Parser.TOKEN_EXTERN-> getErrorString("Parser.TOKEN.EXTERN")
- | Parser.TOKEN_INTERFACE -> getErrorString("Parser.TOKEN.INTERFACE")
- | Parser.TOKEN_REC -> getErrorString("Parser.TOKEN.REC")
- | Parser.TOKEN_TO -> getErrorString("Parser.TOKEN.TO")
- | Parser.TOKEN_TRUE -> getErrorString("Parser.TOKEN.TRUE")
- | Parser.TOKEN_TRY -> getErrorString("Parser.TOKEN.TRY")
- | Parser.TOKEN_TYPE | Parser.TOKEN_TYPE_COMING_SOON | Parser.TOKEN_TYPE_IS_HERE -> getErrorString("Parser.TOKEN.TYPE")
- | Parser.TOKEN_VAL -> getErrorString("Parser.TOKEN.VAL")
- | Parser.TOKEN_INLINE -> getErrorString("Parser.TOKEN.INLINE")
- | Parser.TOKEN_WHEN -> getErrorString("Parser.TOKEN.WHEN")
- | Parser.TOKEN_WHILE -> getErrorString("Parser.TOKEN.WHILE")
- | Parser.TOKEN_WITH-> getErrorString("Parser.TOKEN.WITH")
- | Parser.TOKEN_IF -> getErrorString("Parser.TOKEN.IF")
- | Parser.TOKEN_DO -> getErrorString("Parser.TOKEN.DO")
- | Parser.TOKEN_GLOBAL -> getErrorString("Parser.TOKEN.GLOBAL")
- | Parser.TOKEN_DONE -> getErrorString("Parser.TOKEN.DONE")
- | Parser.TOKEN_IN | Parser.TOKEN_JOIN_IN -> getErrorString("Parser.TOKEN.IN")
- | Parser.TOKEN_HIGH_PRECEDENCE_PAREN_APP-> getErrorString("Parser.TOKEN.HIGH.PRECEDENCE.PAREN.APP")
- | Parser.TOKEN_HIGH_PRECEDENCE_BRACK_APP-> getErrorString("Parser.TOKEN.HIGH.PRECEDENCE.BRACK.APP")
- | Parser.TOKEN_BEGIN -> getErrorString("Parser.TOKEN.BEGIN")
- | Parser.TOKEN_END -> getErrorString("Parser.TOKEN.END")
- | Parser.TOKEN_HASH_LIGHT
- | Parser.TOKEN_HASH_LINE
- | Parser.TOKEN_HASH_IF
- | Parser.TOKEN_HASH_ELSE
- | Parser.TOKEN_HASH_ENDIF -> getErrorString("Parser.TOKEN.HASH.ENDIF")
- | Parser.TOKEN_INACTIVECODE -> getErrorString("Parser.TOKEN.INACTIVECODE")
- | Parser.TOKEN_LEX_FAILURE-> getErrorString("Parser.TOKEN.LEX.FAILURE")
- | Parser.TOKEN_WHITESPACE -> getErrorString("Parser.TOKEN.WHITESPACE")
- | Parser.TOKEN_COMMENT -> getErrorString("Parser.TOKEN.COMMENT")
- | Parser.TOKEN_LINE_COMMENT -> getErrorString("Parser.TOKEN.LINE.COMMENT")
- | Parser.TOKEN_STRING_TEXT -> getErrorString("Parser.TOKEN.STRING.TEXT")
- | Parser.TOKEN_BYTEARRAY -> getErrorString("Parser.TOKEN.BYTEARRAY")
- | Parser.TOKEN_STRING -> getErrorString("Parser.TOKEN.STRING")
- | Parser.TOKEN_KEYWORD_STRING -> getErrorString("Parser.TOKEN.KEYWORD_STRING")
- | Parser.TOKEN_EOF -> getErrorString("Parser.TOKEN.EOF")
- | Parser.TOKEN_CONST -> getErrorString("Parser.TOKEN.CONST")
- | Parser.TOKEN_FIXED -> getErrorString("Parser.TOKEN.FIXED")
- | unknown ->
- Debug.Assert(false, "unknown token tag")
- let result = sprintf "%+A" unknown
- Debug.Assert(false, result)
- result
-
- match ctxt.CurrentToken with
- | None -> os.Append(UnexpectedEndOfInputE().Format) |> ignore
- | Some token ->
- match (token |> Parser.tagOfToken |> Parser.tokenTagToTokenId), token with
- | EndOfStructuredConstructToken, _ -> os.Append(OBlockEndSentenceE().Format) |> ignore
- | Parser.TOKEN_LEX_FAILURE, Parser.LEX_FAILURE str -> Printf.bprintf os "%s" str (* Fix bug://2431 *)
- | token, _ -> os.Append(UnexpectedE().Format (token |> tokenIdToText)) |> ignore
-
- (* Search for a state producing a single recognized non-terminal in the states on the stack *)
- let foundInContext =
-
- (* Merge a bunch of expression non terminals *)
- let (|NONTERM_Category_Expr|_|) = function
- | Parser.NONTERM_argExpr|Parser.NONTERM_minusExpr|Parser.NONTERM_parenExpr|Parser.NONTERM_atomicExpr
- | Parser.NONTERM_appExpr|Parser.NONTERM_tupleExpr|Parser.NONTERM_declExpr|Parser.NONTERM_braceExpr|Parser.NONTERM_braceBarExpr
- | Parser.NONTERM_typedSeqExprBlock
- | Parser.NONTERM_interactiveExpr -> Some()
- | _ -> None
-
- (* Merge a bunch of pattern non terminals *)
- let (|NONTERM_Category_Pattern|_|) = function
- | Parser.NONTERM_constrPattern|Parser.NONTERM_parenPattern|Parser.NONTERM_atomicPattern -> Some()
- | _ -> None
-
- (* Merge a bunch of if/then/else non terminals *)
- let (|NONTERM_Category_IfThenElse|_|) = function
- | Parser.NONTERM_ifExprThen|Parser.NONTERM_ifExprElifs|Parser.NONTERM_ifExprCases -> Some()
- | _ -> None
-
- (* Merge a bunch of non terminals *)
- let (|NONTERM_Category_SignatureFile|_|) = function
- | Parser.NONTERM_signatureFile|Parser.NONTERM_moduleSpfn|Parser.NONTERM_moduleSpfns -> Some()
- | _ -> None
- let (|NONTERM_Category_ImplementationFile|_|) = function
- | Parser.NONTERM_implementationFile|Parser.NONTERM_fileNamespaceImpl|Parser.NONTERM_fileNamespaceImpls -> Some()
- | _ -> None
- let (|NONTERM_Category_Definition|_|) = function
- | Parser.NONTERM_fileModuleImpl|Parser.NONTERM_moduleDefn|Parser.NONTERM_interactiveDefns
- |Parser.NONTERM_moduleDefns|Parser.NONTERM_moduleDefnsOrExpr -> Some()
- | _ -> None
-
- let (|NONTERM_Category_Type|_|) = function
- | Parser.NONTERM_typ|Parser.NONTERM_tupleType -> Some()
- | _ -> None
-
- let (|NONTERM_Category_Interaction|_|) = function
- | Parser.NONTERM_interactiveItemsTerminator|Parser.NONTERM_interaction|Parser.NONTERM__startinteraction -> Some()
- | _ -> None
-
-
- // Canonicalize the categories and check for a unique category
- ctxt.ReducibleProductions |> List.exists (fun prods ->
- match prods
- |> List.map Parser.prodIdxToNonTerminal
- |> List.map (function
- | NONTERM_Category_Type -> Parser.NONTERM_typ
- | NONTERM_Category_Expr -> Parser.NONTERM_declExpr
- | NONTERM_Category_Pattern -> Parser.NONTERM_atomicPattern
- | NONTERM_Category_IfThenElse -> Parser.NONTERM_ifExprThen
- | NONTERM_Category_SignatureFile -> Parser.NONTERM_signatureFile
- | NONTERM_Category_ImplementationFile -> Parser.NONTERM_implementationFile
- | NONTERM_Category_Definition -> Parser.NONTERM_moduleDefn
- | NONTERM_Category_Interaction -> Parser.NONTERM_interaction
- | nt -> nt)
- |> Set.ofList
- |> Set.toList with
- | [Parser.NONTERM_interaction] -> os.Append(NONTERM_interactionE().Format) |> ignore; true
- | [Parser.NONTERM_hashDirective] -> os.Append(NONTERM_hashDirectiveE().Format) |> ignore; true
- | [Parser.NONTERM_fieldDecl] -> os.Append(NONTERM_fieldDeclE().Format) |> ignore; true
- | [Parser.NONTERM_unionCaseRepr] -> os.Append(NONTERM_unionCaseReprE().Format) |> ignore; true
- | [Parser.NONTERM_localBinding] -> os.Append(NONTERM_localBindingE().Format) |> ignore; true
- | [Parser.NONTERM_hardwhiteLetBindings] -> os.Append(NONTERM_hardwhiteLetBindingsE().Format) |> ignore; true
- | [Parser.NONTERM_classDefnMember] -> os.Append(NONTERM_classDefnMemberE().Format) |> ignore; true
- | [Parser.NONTERM_defnBindings] -> os.Append(NONTERM_defnBindingsE().Format) |> ignore; true
- | [Parser.NONTERM_classMemberSpfn] -> os.Append(NONTERM_classMemberSpfnE().Format) |> ignore; true
- | [Parser.NONTERM_valSpfn] -> os.Append(NONTERM_valSpfnE().Format) |> ignore; true
- | [Parser.NONTERM_tyconSpfn] -> os.Append(NONTERM_tyconSpfnE().Format) |> ignore; true
- | [Parser.NONTERM_anonLambdaExpr] -> os.Append(NONTERM_anonLambdaExprE().Format) |> ignore; true
- | [Parser.NONTERM_attrUnionCaseDecl] -> os.Append(NONTERM_attrUnionCaseDeclE().Format) |> ignore; true
- | [Parser.NONTERM_cPrototype] -> os.Append(NONTERM_cPrototypeE().Format) |> ignore; true
- | [Parser.NONTERM_objExpr|Parser.NONTERM_objectImplementationMembers] -> os.Append(NONTERM_objectImplementationMembersE().Format) |> ignore; true
- | [Parser.NONTERM_ifExprThen|Parser.NONTERM_ifExprElifs|Parser.NONTERM_ifExprCases] -> os.Append(NONTERM_ifExprCasesE().Format) |> ignore; true
- | [Parser.NONTERM_openDecl] -> os.Append(NONTERM_openDeclE().Format) |> ignore; true
- | [Parser.NONTERM_fileModuleSpec] -> os.Append(NONTERM_fileModuleSpecE().Format) |> ignore; true
- | [Parser.NONTERM_patternClauses] -> os.Append(NONTERM_patternClausesE().Format) |> ignore; true
- | [Parser.NONTERM_beginEndExpr] -> os.Append(NONTERM_beginEndExprE().Format) |> ignore; true
- | [Parser.NONTERM_recdExpr] -> os.Append(NONTERM_recdExprE().Format) |> ignore; true
- | [Parser.NONTERM_tyconDefn] -> os.Append(NONTERM_tyconDefnE().Format) |> ignore; true
- | [Parser.NONTERM_exconCore] -> os.Append(NONTERM_exconCoreE().Format) |> ignore; true
- | [Parser.NONTERM_typeNameInfo] -> os.Append(NONTERM_typeNameInfoE().Format) |> ignore; true
- | [Parser.NONTERM_attributeList] -> os.Append(NONTERM_attributeListE().Format) |> ignore; true
- | [Parser.NONTERM_quoteExpr] -> os.Append(NONTERM_quoteExprE().Format) |> ignore; true
- | [Parser.NONTERM_typeConstraint] -> os.Append(NONTERM_typeConstraintE().Format) |> ignore; true
- | [NONTERM_Category_ImplementationFile] -> os.Append(NONTERM_Category_ImplementationFileE().Format) |> ignore; true
- | [NONTERM_Category_Definition] -> os.Append(NONTERM_Category_DefinitionE().Format) |> ignore; true
- | [NONTERM_Category_SignatureFile] -> os.Append(NONTERM_Category_SignatureFileE().Format) |> ignore; true
- | [NONTERM_Category_Pattern] -> os.Append(NONTERM_Category_PatternE().Format) |> ignore; true
- | [NONTERM_Category_Expr] -> os.Append(NONTERM_Category_ExprE().Format) |> ignore; true
- | [NONTERM_Category_Type] -> os.Append(NONTERM_Category_TypeE().Format) |> ignore; true
- | [Parser.NONTERM_typeArgsActual] -> os.Append(NONTERM_typeArgsActualE().Format) |> ignore; true
- | _ ->
- false)
-
-#if DEBUG
- if not foundInContext then
- Printf.bprintf os ". (no 'in' context found: %+A)" (List.map (List.map Parser.prodIdxToNonTerminal) ctxt.ReducibleProductions)
-#else
- foundInContext |> ignore // suppress unused variable warning in RELEASE
-#endif
- let fix (s: string) = s.Replace(SR.GetString("FixKeyword"), "").Replace(SR.GetString("FixSymbol"), "").Replace(SR.GetString("FixReplace"), "")
- match (ctxt.ShiftTokens
- |> List.map Parser.tokenTagToTokenId
- |> List.filter (function Parser.TOKEN_error | Parser.TOKEN_EOF -> false | _ -> true)
- |> List.map tokenIdToText
- |> Set.ofList
- |> Set.toList) with
- | [tokenName1] -> os.Append(TokenName1E().Format (fix tokenName1)) |> ignore
- | [tokenName1;tokenName2] -> os.Append(TokenName1TokenName2E().Format (fix tokenName1) (fix tokenName2)) |> ignore
- | [tokenName1;tokenName2;tokenName3] -> os.Append(TokenName1TokenName2TokenName3E().Format (fix tokenName1) (fix tokenName2) (fix tokenName3)) |> ignore
- | _ -> ()
- (*
- Printf.bprintf os ".\n\n state = %A\n token = %A\n expect (shift) %A\n expect (reduce) %A\n prods=%A\n non terminals: %A"
- ctxt.StateStack
- ctxt.CurrentToken
- (List.map Parser.tokenTagToTokenId ctxt.ShiftTokens)
- (List.map Parser.tokenTagToTokenId ctxt.ReduceTokens)
- ctxt.ReducibleProductions
- (List.mapSquared Parser.prodIdxToNonTerminal ctxt.ReducibleProductions)
- *)
-
- | RuntimeCoercionSourceSealed(denv, ty, _) ->
- // REVIEW: consider if we need to show _cxs (the type parameter constraints)
- let ty, _cxs = PrettyTypes.PrettifyType denv.g ty
- if isTyparTy denv.g ty
- then os.Append(RuntimeCoercionSourceSealed1E().Format (NicePrint.stringOfTy denv ty)) |> ignore
- else os.Append(RuntimeCoercionSourceSealed2E().Format (NicePrint.stringOfTy denv ty)) |> ignore
-
- | CoercionTargetSealed(denv, ty, _) ->
- // REVIEW: consider if we need to show _cxs (the type parameter constraints)
- let ty, _cxs= PrettyTypes.PrettifyType denv.g ty
- os.Append(CoercionTargetSealedE().Format (NicePrint.stringOfTy denv ty)) |> ignore
-
- | UpcastUnnecessary(_) ->
- os.Append(UpcastUnnecessaryE().Format) |> ignore
-
- | TypeTestUnnecessary(_) ->
- os.Append(TypeTestUnnecessaryE().Format) |> ignore
-
- | QuotationTranslator.IgnoringPartOfQuotedTermWarning (msg, _) ->
- Printf.bprintf os "%s" msg
-
- | OverrideDoesntOverride(denv, impl, minfoVirtOpt, g, amap, m) ->
- let sig1 = DispatchSlotChecking.FormatOverride denv impl
- match minfoVirtOpt with
- | None ->
- os.Append(OverrideDoesntOverride1E().Format sig1) |> ignore
- | Some minfoVirt ->
- // https://github.com/Microsoft/visualfsharp/issues/35
- // Improve error message when attempting to override generic return type with unit:
- // we need to check if unit was used as a type argument
- let rec hasUnitTType_app (types: TType list) =
- match types with
- | TType_app (maybeUnit, []) :: ts ->
- match maybeUnit.TypeAbbrev with
- | Some ttype when Tastops.isUnitTy g ttype -> true
- | _ -> hasUnitTType_app ts
- | _ :: ts -> hasUnitTType_app ts
- | [] -> false
-
- match minfoVirt.ApparentEnclosingType with
- | TType_app (t, types) when t.IsFSharpInterfaceTycon && hasUnitTType_app types ->
- // match abstract member with 'unit' passed as generic argument
- os.Append(OverrideDoesntOverride4E().Format sig1) |> ignore
- | _ ->
- os.Append(OverrideDoesntOverride2E().Format sig1) |> ignore
- let sig2 = DispatchSlotChecking.FormatMethInfoSig g amap m denv minfoVirt
- if sig1 <> sig2 then
- os.Append(OverrideDoesntOverride3E().Format sig2) |> ignore
-
- | UnionCaseWrongArguments (_, n1, n2, _) ->
- os.Append(UnionCaseWrongArgumentsE().Format n2 n1) |> ignore
-
- | UnionPatternsBindDifferentNames _ ->
- os.Append(UnionPatternsBindDifferentNamesE().Format) |> ignore
-
- | ValueNotContained (denv, mref, implVal, sigVal, f) ->
- let text1, text2 = NicePrint.minimalStringsOfTwoValues denv implVal sigVal
- os.Append(f((fullDisplayTextOfModRef mref), text1, text2)) |> ignore
-
- | ConstrNotContained (denv, v1, v2, f) ->
- os.Append(f((NicePrint.stringOfUnionCase denv v1), (NicePrint.stringOfUnionCase denv v2))) |> ignore
-
- | ExnconstrNotContained (denv, v1, v2, f) ->
- os.Append(f((NicePrint.stringOfExnDef denv v1), (NicePrint.stringOfExnDef denv v2))) |> ignore
-
- | FieldNotContained (denv, v1, v2, f) ->
- os.Append(f((NicePrint.stringOfRecdField denv v1), (NicePrint.stringOfRecdField denv v2))) |> ignore
-
- | RequiredButNotSpecified (_, mref, k, name, _) ->
- let nsb = new System.Text.StringBuilder()
- name nsb;
- os.Append(RequiredButNotSpecifiedE().Format (fullDisplayTextOfModRef mref) k (nsb.ToString())) |> ignore
-
- | UseOfAddressOfOperator _ ->
- os.Append(UseOfAddressOfOperatorE().Format) |> ignore
-
- | DefensiveCopyWarning(s, _) -> os.Append(DefensiveCopyWarningE().Format s) |> ignore
-
- | DeprecatedThreadStaticBindingWarning(_) ->
- os.Append(DeprecatedThreadStaticBindingWarningE().Format) |> ignore
-
- | FunctionValueUnexpected (denv, ty, _) ->
- let ty, _cxs = PrettyTypes.PrettifyType denv.g ty
- let errorText = FunctionValueUnexpectedE().Format (NicePrint.stringOfTy denv ty)
- os.Append errorText |> ignore
-
- | UnitTypeExpected (denv, ty, _) ->
- let ty, _cxs = PrettyTypes.PrettifyType denv.g ty
- let warningText = UnitTypeExpectedE().Format (NicePrint.stringOfTy denv ty)
- os.Append warningText |> ignore
-
- | UnitTypeExpectedWithEquality (denv, ty, _) ->
- let ty, _cxs = PrettyTypes.PrettifyType denv.g ty
- let warningText = UnitTypeExpectedWithEqualityE().Format (NicePrint.stringOfTy denv ty)
- os.Append warningText |> ignore
-
- | UnitTypeExpectedWithPossiblePropertySetter (denv, ty, bindingName, propertyName, _) ->
- let ty, _cxs = PrettyTypes.PrettifyType denv.g ty
- let warningText = UnitTypeExpectedWithPossiblePropertySetterE().Format (NicePrint.stringOfTy denv ty) bindingName propertyName
- os.Append warningText |> ignore
-
- | UnitTypeExpectedWithPossibleAssignment (denv, ty, isAlreadyMutable, bindingName, _) ->
- let ty, _cxs = PrettyTypes.PrettifyType denv.g ty
- let warningText =
- if isAlreadyMutable then
- UnitTypeExpectedWithPossibleAssignmentToMutableE().Format (NicePrint.stringOfTy denv ty) bindingName
- else
- UnitTypeExpectedWithPossibleAssignmentE().Format (NicePrint.stringOfTy denv ty) bindingName
- os.Append warningText |> ignore
-
- | RecursiveUseCheckedAtRuntime _ ->
- os.Append(RecursiveUseCheckedAtRuntimeE().Format) |> ignore
-
- | LetRecUnsound (_, [v], _) ->
- os.Append(LetRecUnsound1E().Format v.DisplayName) |> ignore
-
- | LetRecUnsound (_, path, _) ->
- let bos = new System.Text.StringBuilder()
- (path.Tail @ [path.Head]) |> List.iter (fun (v: ValRef) -> bos.Append(LetRecUnsoundInnerE().Format v.DisplayName) |> ignore)
- os.Append(LetRecUnsound2E().Format (List.head path).DisplayName (bos.ToString())) |> ignore
-
- | LetRecEvaluatedOutOfOrder (_, _, _, _) ->
- os.Append(LetRecEvaluatedOutOfOrderE().Format) |> ignore
-
- | LetRecCheckedAtRuntime _ ->
- os.Append(LetRecCheckedAtRuntimeE().Format) |> ignore
-
- | SelfRefObjCtor(false, _) ->
- os.Append(SelfRefObjCtor1E().Format) |> ignore
-
- | SelfRefObjCtor(true, _) ->
- os.Append(SelfRefObjCtor2E().Format) |> ignore
-
- | VirtualAugmentationOnNullValuedType(_) ->
- os.Append(VirtualAugmentationOnNullValuedTypeE().Format) |> ignore
-
- | NonVirtualAugmentationOnNullValuedType(_) ->
- os.Append(NonVirtualAugmentationOnNullValuedTypeE().Format) |> ignore
-
- | NonUniqueInferredAbstractSlot(_, denv, bindnm, bvirt1, bvirt2, _) ->
- os.Append(NonUniqueInferredAbstractSlot1E().Format bindnm) |> ignore
- let ty1 = bvirt1.ApparentEnclosingType
- let ty2 = bvirt2.ApparentEnclosingType
- // REVIEW: consider if we need to show _cxs (the type parameter constraints)
- let t1, t2, _cxs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2
- os.Append(NonUniqueInferredAbstractSlot2E().Format) |> ignore
- if t1 <> t2 then
- os.Append(NonUniqueInferredAbstractSlot3E().Format t1 t2) |> ignore
- os.Append(NonUniqueInferredAbstractSlot4E().Format) |> ignore
-
- | Error ((_, s), _) -> os.Append s |> ignore
-
- | ErrorWithSuggestions ((_, s), _, idText, suggestionF) ->
- os.Append(DecompileOpName s) |> ignore
- suggestNames suggestionF idText
-
- | NumberedError ((_, s), _) -> os.Append s |> ignore
-
- | InternalError (s, _)
-
- | InvalidArgument s
-
- | Failure s as exn ->
- ignore exn // use the argument, even in non DEBUG
- let f1 = SR.GetString("Failure1")
- let f2 = SR.GetString("Failure2")
- match s with
- | f when f = f1 -> os.Append(Failure3E().Format s) |> ignore
- | f when f = f2 -> os.Append(Failure3E().Format s) |> ignore
- | _ -> os.Append(Failure4E().Format s) |> ignore
-#if DEBUG
- Printf.bprintf os "\nStack Trace\n%s\n" (exn.ToString())
- if !showAssertForUnexpectedException then
- System.Diagnostics.Debug.Assert(false, sprintf "Unexpected exception seen in compiler: %s\n%s" s (exn.ToString()))
-#endif
-
- | FullAbstraction(s, _) -> os.Append(FullAbstractionE().Format s) |> ignore
-
- | WrappedError (exn, _) -> OutputExceptionR os exn
-
- | PatternMatchCompilation.MatchIncomplete (isComp, cexOpt, _) ->
- os.Append(MatchIncomplete1E().Format) |> ignore
- match cexOpt with
- | None -> ()
- | Some (cex, false) -> os.Append(MatchIncomplete2E().Format cex) |> ignore
- | Some (cex, true) -> os.Append(MatchIncomplete3E().Format cex) |> ignore
- if isComp then
- os.Append(MatchIncomplete4E().Format) |> ignore
-
- | PatternMatchCompilation.EnumMatchIncomplete (isComp, cexOpt, _) ->
- os.Append(EnumMatchIncomplete1E().Format) |> ignore
- match cexOpt with
- | None -> ()
- | Some (cex, false) -> os.Append(MatchIncomplete2E().Format cex) |> ignore
- | Some (cex, true) -> os.Append(MatchIncomplete3E().Format cex) |> ignore
- if isComp then
- os.Append(MatchIncomplete4E().Format) |> ignore
-
- | PatternMatchCompilation.RuleNeverMatched _ -> os.Append(RuleNeverMatchedE().Format) |> ignore
-
- | ValNotMutable(_, valRef, _) -> os.Append(ValNotMutableE().Format(valRef.DisplayName)) |> ignore
-
- | ValNotLocal _ -> os.Append(ValNotLocalE().Format) |> ignore
-
- | ObsoleteError (s, _)
-
- | ObsoleteWarning (s, _) ->
- os.Append(Obsolete1E().Format) |> ignore
- if s <> "" then os.Append(Obsolete2E().Format s) |> ignore
-
- | Experimental (s, _) -> os.Append(ExperimentalE().Format s) |> ignore
-
- | PossibleUnverifiableCode _ -> os.Append(PossibleUnverifiableCodeE().Format) |> ignore
-
- | UserCompilerMessage (msg, _, _) -> os.Append msg |> ignore
-
- | Deprecated(s, _) -> os.Append(DeprecatedE().Format s) |> ignore
-
- | LibraryUseOnly(_) -> os.Append(LibraryUseOnlyE().Format) |> ignore
-
- | MissingFields(sl, _) -> os.Append(MissingFieldsE().Format (String.concat "," sl + ".")) |> ignore
-
- | ValueRestriction(denv, hassig, v, _, _) ->
- let denv = { denv with showImperativeTyparAnnotations=true }
- let tau = v.TauType
- if hassig then
- if isFunTy denv.g tau && (arityOfVal v).HasNoArgs then
- os.Append(ValueRestriction1E().Format
- v.DisplayName
- (NicePrint.stringOfQualifiedValOrMember denv v)
- v.DisplayName) |> ignore
- else
- os.Append(ValueRestriction2E().Format
- v.DisplayName
- (NicePrint.stringOfQualifiedValOrMember denv v)
- v.DisplayName) |> ignore
- else
- match v.MemberInfo with
- | Some membInfo when
- begin match membInfo.MemberFlags.MemberKind with
- | MemberKind.PropertyGet
- | MemberKind.PropertySet
- | MemberKind.Constructor -> true (* can't infer extra polymorphism *)
- | _ -> false (* can infer extra polymorphism *)
- end ->
- os.Append(ValueRestriction3E().Format (NicePrint.stringOfQualifiedValOrMember denv v)) |> ignore
- | _ ->
- if isFunTy denv.g tau && (arityOfVal v).HasNoArgs then
- os.Append(ValueRestriction4E().Format
- v.DisplayName
- (NicePrint.stringOfQualifiedValOrMember denv v)
- v.DisplayName) |> ignore
- else
- os.Append(ValueRestriction5E().Format
- v.DisplayName
- (NicePrint.stringOfQualifiedValOrMember denv v)
- v.DisplayName) |> ignore
-
-
- | Parsing.RecoverableParseError -> os.Append(RecoverableParseErrorE().Format) |> ignore
-
- | ReservedKeyword (s, _) -> os.Append(ReservedKeywordE().Format s) |> ignore
-
- | IndentationProblem (s, _) -> os.Append(IndentationProblemE().Format s) |> ignore
-
- | OverrideInIntrinsicAugmentation(_) -> os.Append(OverrideInIntrinsicAugmentationE().Format) |> ignore
-
- | OverrideInExtrinsicAugmentation(_) -> os.Append(OverrideInExtrinsicAugmentationE().Format) |> ignore
-
- | IntfImplInIntrinsicAugmentation(_) -> os.Append(IntfImplInIntrinsicAugmentationE().Format) |> ignore
-
- | IntfImplInExtrinsicAugmentation(_) -> os.Append(IntfImplInExtrinsicAugmentationE().Format) |> ignore
-
- | UnresolvedReferenceError(assemblyname, _)
-
- | UnresolvedReferenceNoRange assemblyname ->
- os.Append(UnresolvedReferenceNoRangeE().Format assemblyname) |> ignore
-
- | UnresolvedPathReference(assemblyname, pathname, _)
-
- | UnresolvedPathReferenceNoRange(assemblyname, pathname) ->
- os.Append(UnresolvedPathReferenceNoRangeE().Format pathname assemblyname) |> ignore
-
- | DeprecatedCommandLineOptionFull(fullText, _) ->
- os.Append fullText |> ignore
-
- | DeprecatedCommandLineOptionForHtmlDoc(optionName, _) ->
- os.Append(FSComp.SR.optsDCLOHtmlDoc optionName) |> ignore
-
- | DeprecatedCommandLineOptionSuggestAlternative(optionName, altOption, _) ->
- os.Append(FSComp.SR.optsDCLODeprecatedSuggestAlternative(optionName, altOption)) |> ignore
-
- | InternalCommandLineOption(optionName, _) ->
- os.Append(FSComp.SR.optsInternalNoDescription optionName) |> ignore
-
- | DeprecatedCommandLineOptionNoDescription(optionName, _) ->
- os.Append(FSComp.SR.optsDCLONoDescription optionName) |> ignore
-
- | HashIncludeNotAllowedInNonScript(_) ->
- os.Append(HashIncludeNotAllowedInNonScriptE().Format) |> ignore
-
- | HashReferenceNotAllowedInNonScript(_) ->
- os.Append(HashReferenceNotAllowedInNonScriptE().Format) |> ignore
-
- | HashDirectiveNotAllowedInNonScript(_) ->
- os.Append(HashDirectiveNotAllowedInNonScriptE().Format) |> ignore
-
- | FileNameNotResolved(filename, locations, _) ->
- os.Append(FileNameNotResolvedE().Format filename locations) |> ignore
-
- | AssemblyNotResolved(originalName, _) ->
- os.Append(AssemblyNotResolvedE().Format originalName) |> ignore
-
- | IllegalFileNameChar(fileName, invalidChar) ->
- os.Append(FSComp.SR.buildUnexpectedFileNameCharacter(fileName, string invalidChar)|>snd) |> ignore
-
- | HashLoadedSourceHasIssues(warnings, errors, _) ->
- let Emit(l: exn list) =
- OutputExceptionR os (List.head l)
- if errors=[] then
- os.Append(HashLoadedSourceHasIssues1E().Format) |> ignore
- Emit warnings
- else
- os.Append(HashLoadedSourceHasIssues2E().Format) |> ignore
- Emit errors
-
- | HashLoadedScriptConsideredSource(_) ->
- os.Append(HashLoadedScriptConsideredSourceE().Format) |> ignore
-
- | InvalidInternalsVisibleToAssemblyName(badName, fileNameOption) ->
- match fileNameOption with
- | Some file -> os.Append(InvalidInternalsVisibleToAssemblyName1E().Format badName file) |> ignore
- | None -> os.Append(InvalidInternalsVisibleToAssemblyName2E().Format badName) |> ignore
-
- | LoadedSourceNotFoundIgnoring(filename, _) ->
- os.Append(LoadedSourceNotFoundIgnoringE().Format filename) |> ignore
-
- | MSBuildReferenceResolutionWarning(code, message, _)
-
- | MSBuildReferenceResolutionError(code, message, _) ->
- os.Append(MSBuildReferenceResolutionErrorE().Format message code) |> ignore
-
- // Strip TargetInvocationException wrappers
- | :? System.Reflection.TargetInvocationException as e ->
- OutputExceptionR os e.InnerException
-
- | :? FileNotFoundException as e -> Printf.bprintf os "%s" e.Message
-
- | :? DirectoryNotFoundException as e -> Printf.bprintf os "%s" e.Message
-
- | :? System.ArgumentException as e -> Printf.bprintf os "%s" e.Message
-
- | :? System.NotSupportedException as e -> Printf.bprintf os "%s" e.Message
-
- | :? IOException as e -> Printf.bprintf os "%s" e.Message
-
- | :? System.UnauthorizedAccessException as e -> Printf.bprintf os "%s" e.Message
-
- | e ->
- os.Append(TargetInvocationExceptionWrapperE().Format e.Message) |> ignore
-#if DEBUG
- Printf.bprintf os "\nStack Trace\n%s\n" (e.ToString())
- if !showAssertForUnexpectedException then
- System.Diagnostics.Debug.Assert(false, sprintf "Unknown exception seen in compiler: %s" (e.ToString()))
-#endif
-
- OutputExceptionR os err.Exception
-
-
-// remove any newlines and tabs
-let OutputPhasedDiagnostic (os: System.Text.StringBuilder) (err: PhasedDiagnostic) (flattenErrors: bool) (canSuggestNames: bool) =
- let buf = new System.Text.StringBuilder()
-
- OutputPhasedErrorR buf err canSuggestNames
- let s = if flattenErrors then ErrorLogger.NormalizeErrorString (buf.ToString()) else buf.ToString()
-
- os.Append s |> ignore
-
-let SanitizeFileName fileName implicitIncludeDir =
- // The assert below is almost ok, but it fires in two cases:
- // - fsi.exe sometimes passes "stdin" as a dummy filename
- // - if you have a #line directive, e.g.
- // # 1000 "Line01.fs"
- // then it also asserts. But these are edge cases that can be fixed later, e.g. in bug 4651.
- //System.Diagnostics.Debug.Assert(FileSystem.IsPathRootedShim fileName, sprintf "filename should be absolute: '%s'" fileName)
- try
- let fullPath = FileSystem.GetFullPathShim fileName
- let currentDir = implicitIncludeDir
-
- // if the file name is not rooted in the current directory, return the full path
- if not(fullPath.StartsWithOrdinal currentDir) then
- fullPath
- // if the file name is rooted in the current directory, return the relative path
- else
- fullPath.Replace(currentDir+"\\", "")
- with _ ->
- fileName
-
-[]
-type DiagnosticLocation =
- { Range: range
- File: string
- TextRepresentation: string
- IsEmpty: bool }
-
-[]
-type DiagnosticCanonicalInformation =
- { ErrorNumber: int
- Subcategory: string
- TextRepresentation: string }
-
-[]
-type DiagnosticDetailedInfo =
- { Location: DiagnosticLocation option
- Canonical: DiagnosticCanonicalInformation
- Message: string }
-
-[]
-type Diagnostic =
- | Short of bool * string
- | Long of bool * DiagnosticDetailedInfo
-
-/// returns sequence that contains Diagnostic for the given error + Diagnostic for all related errors
-let CollectDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorStyle, isError, err: PhasedDiagnostic, canSuggestNames: bool) =
- let outputWhere (showFullPaths, errorStyle) m: DiagnosticLocation =
- if Range.equals m rangeStartup || Range.equals m rangeCmdArgs then
- { Range = m; TextRepresentation = ""; IsEmpty = true; File = "" }
- else
- let file = m.FileName
- let file = if showFullPaths then
- Filename.fullpath implicitIncludeDir file
- else
- SanitizeFileName file implicitIncludeDir
- let text, m, file =
- match errorStyle with
- | ErrorStyle.EmacsErrors ->
- let file = file.Replace("\\", "/")
- (sprintf "File \"%s\", line %d, characters %d-%d: " file m.StartLine m.StartColumn m.EndColumn), m, file
-
- // We're adjusting the columns here to be 1-based - both for parity with C# and for MSBuild, which assumes 1-based columns for error output
- | ErrorStyle.DefaultErrors ->
- let file = file.Replace('/', System.IO.Path.DirectorySeparatorChar)
- let m = mkRange m.FileName (mkPos m.StartLine (m.StartColumn + 1)) m.End
- (sprintf "%s(%d,%d): " file m.StartLine m.StartColumn), m, file
-
- // We may also want to change TestErrors to be 1-based
- | ErrorStyle.TestErrors ->
- let file = file.Replace("/", "\\")
- let m = mkRange m.FileName (mkPos m.StartLine (m.StartColumn + 1)) (mkPos m.EndLine (m.EndColumn + 1) )
- sprintf "%s(%d,%d-%d,%d): " file m.StartLine m.StartColumn m.EndLine m.EndColumn, m, file
-
- | ErrorStyle.GccErrors ->
- let file = file.Replace('/', System.IO.Path.DirectorySeparatorChar)
- let m = mkRange m.FileName (mkPos m.StartLine (m.StartColumn + 1)) (mkPos m.EndLine (m.EndColumn + 1) )
- sprintf "%s:%d:%d: " file m.StartLine m.StartColumn, m, file
-
- // Here, we want the complete range information so Project Systems can generate proper squiggles
- | ErrorStyle.VSErrors ->
- // Show prefix only for real files. Otherwise, we just want a truncated error like:
- // parse error FS0031: blah blah
- if not (Range.equals m range0) && not (Range.equals m rangeStartup) && not (Range.equals m rangeCmdArgs) then
- let file = file.Replace("/", "\\")
- let m = mkRange m.FileName (mkPos m.StartLine (m.StartColumn + 1)) (mkPos m.EndLine (m.EndColumn + 1) )
- sprintf "%s(%d,%d,%d,%d): " file m.StartLine m.StartColumn m.EndLine m.EndColumn, m, file
- else
- "", m, file
- { Range = m; TextRepresentation = text; IsEmpty = false; File = file }
-
- match err.Exception with
- | ReportedError _ ->
- assert ("" = "Unexpected ReportedError") // this should never happen
- Seq.empty
- | StopProcessing ->
- assert ("" = "Unexpected StopProcessing") // this should never happen
- Seq.empty
- | _ ->
- let errors = ResizeArray()
- let report err =
- let OutputWhere err =
- match GetRangeOfDiagnostic err with
- | Some m -> Some(outputWhere (showFullPaths, errorStyle) m)
- | None -> None
-
- let OutputCanonicalInformation(subcategory, errorNumber) : DiagnosticCanonicalInformation =
- let text =
- match errorStyle with
- // Show the subcategory for --vserrors so that we can fish it out in Visual Studio and use it to determine error stickiness.
- | ErrorStyle.VSErrors -> sprintf "%s %s FS%04d: " subcategory (if isError then "error" else "warning") errorNumber
- | _ -> sprintf "%s FS%04d: " (if isError then "error" else "warning") errorNumber
- { ErrorNumber = errorNumber; Subcategory = subcategory; TextRepresentation = text}
-
- let mainError, relatedErrors = SplitRelatedDiagnostics err
- let where = OutputWhere mainError
- let canonical = OutputCanonicalInformation(err.Subcategory(), GetDiagnosticNumber mainError)
- let message =
- let os = System.Text.StringBuilder()
- OutputPhasedDiagnostic os mainError flattenErrors canSuggestNames
- os.ToString()
-
- let entry: DiagnosticDetailedInfo = { Location = where; Canonical = canonical; Message = message }
-
- errors.Add ( Diagnostic.Long(isError, entry ) )
-
- let OutputRelatedError(err: PhasedDiagnostic) =
- match errorStyle with
- // Give a canonical string when --vserror.
- | ErrorStyle.VSErrors ->
- let relWhere = OutputWhere mainError // mainError?
- let relCanonical = OutputCanonicalInformation(err.Subcategory(), GetDiagnosticNumber mainError) // Use main error for code
- let relMessage =
- let os = System.Text.StringBuilder()
- OutputPhasedDiagnostic os err flattenErrors canSuggestNames
- os.ToString()
-
- let entry: DiagnosticDetailedInfo = { Location = relWhere; Canonical = relCanonical; Message = relMessage}
- errors.Add( Diagnostic.Long (isError, entry) )
-
- | _ ->
- let os = System.Text.StringBuilder()
- OutputPhasedDiagnostic os err flattenErrors canSuggestNames
- errors.Add( Diagnostic.Short(isError, os.ToString()) )
-
- relatedErrors |> List.iter OutputRelatedError
-
- match err with
-#if !NO_EXTENSIONTYPING
- | {Exception = (:? TypeProviderError as tpe)} ->
- tpe.Iter (fun e ->
- let newErr = {err with Exception = e}
- report newErr
- )
-#endif
- | x -> report x
-
- errors:> seq<_>
-
-/// used by fsc.exe and fsi.exe, but not by VS
-/// prints error and related errors to the specified StringBuilder
-let rec OutputDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorStyle, isError) os (err: PhasedDiagnostic) =
-
- // 'true' for "canSuggestNames" is passed last here because we want to report suggestions in fsc.exe and fsi.exe, just not in regular IDE usage.
- let errors = CollectDiagnostic (implicitIncludeDir, showFullPaths, flattenErrors, errorStyle, isError, err, true)
- for e in errors do
- Printf.bprintf os "\n"
- match e with
- | Diagnostic.Short(_, txt) ->
- os.Append txt |> ignore
- | Diagnostic.Long(_, details) ->
- match details.Location with
- | Some l when not l.IsEmpty -> os.Append l.TextRepresentation |> ignore
- | _ -> ()
- os.Append( details.Canonical.TextRepresentation ) |> ignore
- os.Append( details.Message ) |> ignore
-
-let OutputDiagnosticContext prefix fileLineFn os err =
- match GetRangeOfDiagnostic err with
- | None -> ()
- | Some m ->
- let filename = m.FileName
- let lineA = m.StartLine
- let lineB = m.EndLine
- let line = fileLineFn filename lineA
- if line<>"" then
- let iA = m.StartColumn
- let iB = m.EndColumn
- let iLen = if lineA = lineB then max (iB - iA) 1 else 1
- Printf.bprintf os "%s%s\n" prefix line
- Printf.bprintf os "%s%s%s\n" prefix (String.make iA '-') (String.make iLen '^')
-
-let (++) x s = x @ [s]
-
-//--------------------------------------------------------------------------
-// General file name resolver
-//--------------------------------------------------------------------------
-
-/// Will return None if the filename is not found.
-let TryResolveFileUsingPaths(paths, m, name) =
- let () =
- try FileSystem.IsPathRootedShim name |> ignore
- with :? System.ArgumentException as e -> error(Error(FSComp.SR.buildProblemWithFilename(name, e.Message), m))
- if FileSystem.IsPathRootedShim name && FileSystem.SafeExists name
- then Some name
- else
- let res = paths |> List.tryPick (fun path ->
- let n = Path.Combine (path, name)
- if FileSystem.SafeExists n then Some n
- else None)
- res
-
-/// Will raise FileNameNotResolved if the filename was not found
-let ResolveFileUsingPaths(paths, m, name) =
- match TryResolveFileUsingPaths(paths, m, name) with
- | Some res -> res
- | None ->
- let searchMessage = String.concat "\n " paths
- raise (FileNameNotResolved(name, searchMessage, m))
-
-let GetWarningNumber(m, s: string) =
- try
- // Okay so ...
- // #pragma strips FS of the #pragma "FS0004" and validates the warning number
- // therefore if we have warning id that starts with a numeric digit we convert it to Some (int32)
- // anything else is ignored None
- if Char.IsDigit(s.[0]) then Some (int32 s)
- elif s.StartsWithOrdinal("FS") = true then raise (new ArgumentException())
- else None
- with err ->
- warning(Error(FSComp.SR.buildInvalidWarningNumber s, m))
- None
-
-let ComputeMakePathAbsolute implicitIncludeDir (path: string) =
- try
- // remove any quotation marks from the path first
- let path = path.Replace("\"", "")
- if not (FileSystem.IsPathRootedShim path)
- then Path.Combine (implicitIncludeDir, path)
- else path
- with
- :? System.ArgumentException -> path
-
-//----------------------------------------------------------------------------
-// Configuration
-//----------------------------------------------------------------------------
-
-[]
-type CompilerTarget =
- | WinExe
- | ConsoleExe
- | Dll
- | Module
- member x.IsExe = (match x with ConsoleExe | WinExe -> true | _ -> false)
-
-[]
-type ResolveAssemblyReferenceMode = Speculative | ReportErrors
-
-[]
-type CopyFSharpCoreFlag = Yes | No
-
-/// Represents the file or string used for the --version flag
-type VersionFlag =
- | VersionString of string
- | VersionFile of string
- | VersionNone
- member x.GetVersionInfo implicitIncludeDir =
- let vstr = x.GetVersionString implicitIncludeDir
- try
- IL.parseILVersion vstr
- with _ -> errorR(Error(FSComp.SR.buildInvalidVersionString vstr, rangeStartup)); IL.parseILVersion "0.0.0.0"
-
- member x.GetVersionString implicitIncludeDir =
- match x with
- | VersionString s -> s
- | VersionFile s ->
- let s = if FileSystem.IsPathRootedShim s then s else Path.Combine(implicitIncludeDir, s)
- if not(FileSystem.SafeExists s) then
- errorR(Error(FSComp.SR.buildInvalidVersionFile s, rangeStartup)); "0.0.0.0"
- else
- use is = System.IO.File.OpenText s
- is.ReadLine()
- | VersionNone -> "0.0.0.0"
-
-
-/// Represents a reference to an assembly. May be backed by a real assembly on disk, or a cross-project
-/// reference backed by information generated by the the compiler service.
-type IRawFSharpAssemblyData =
- /// The raw list AutoOpenAttribute attributes in the assembly
- abstract GetAutoOpenAttributes: ILGlobals -> string list
- /// The raw list InternalsVisibleToAttribute attributes in the assembly
- abstract GetInternalsVisibleToAttributes: ILGlobals -> string list
- /// The raw IL module definition in the assembly, if any. This is not present for cross-project references
- /// in the language service
- abstract TryGetILModuleDef: unit -> ILModuleDef option
- /// The raw F# signature data in the assembly, if any
- abstract GetRawFSharpSignatureData: range * ilShortAssemName: string * fileName: string -> (string * (unit -> byte[])) list
- /// The raw F# optimization data in the assembly, if any
- abstract GetRawFSharpOptimizationData: range * ilShortAssemName: string * fileName: string -> (string * (unit -> byte[])) list
- /// The table of type forwarders in the assembly
- abstract GetRawTypeForwarders: unit -> ILExportedTypesAndForwarders
- /// The identity of the module
- abstract ILScopeRef: ILScopeRef
- abstract ILAssemblyRefs: ILAssemblyRef list
- abstract ShortAssemblyName: string
- abstract HasAnyFSharpSignatureDataAttribute: bool
- abstract HasMatchingFSharpSignatureDataAttribute: ILGlobals -> bool
-
-/// Cache of time stamps as we traverse a project description
-type TimeStampCache(defaultTimeStamp: DateTime) =
- let files = Dictionary()
- let projects = Dictionary(HashIdentity.Reference)
- member cache.GetFileTimeStamp fileName =
- let ok, v = files.TryGetValue fileName
- if ok then v else
- let v =
- try
- FileSystem.GetLastWriteTimeShim fileName
- with
- | :? FileNotFoundException ->
- defaultTimeStamp
- files.[fileName] <- v
- v
-
- member cache.GetProjectReferenceTimeStamp (pr: IProjectReference, ctok) =
- let ok, v = projects.TryGetValue pr
- if ok then v else
- let v = defaultArg (pr.TryGetLogicalTimeStamp (cache, ctok)) defaultTimeStamp
- projects.[pr] <- v
- v
-
-and IProjectReference =
- /// The name of the assembly file generated by the project
- abstract FileName: string
-
- /// Evaluate raw contents of the assembly file generated by the project
- abstract EvaluateRawContents: CompilationThreadToken -> Cancellable
-
- /// Get the logical timestamp that would be the timestamp of the assembly file generated by the project
- ///
- /// For project references this is maximum of the timestamps of all dependent files.
- /// The project is not actually built, nor are any assemblies read, but the timestamps for each dependent file
- /// are read via the FileSystem. If the files don't exist, then a default timestamp is used.
- ///
- /// The operation returns None only if it is not possible to create an IncrementalBuilder for the project at all, e.g. if there
- /// are fatal errors in the options for the project.
- abstract TryGetLogicalTimeStamp: TimeStampCache * CompilationThreadToken -> System.DateTime option
-
-type AssemblyReference =
- | AssemblyReference of range * string * IProjectReference option
-
- member x.Range = (let (AssemblyReference(m, _, _)) = x in m)
-
- member x.Text = (let (AssemblyReference(_, text, _)) = x in text)
-
- member x.ProjectReference = (let (AssemblyReference(_, _, contents)) = x in contents)
-
- member x.SimpleAssemblyNameIs name =
- (String.Compare(fileNameWithoutExtensionWithValidate false x.Text, name, StringComparison.OrdinalIgnoreCase) = 0) ||
- (let text = x.Text.ToLowerInvariant()
- not (text.Contains "/") && not (text.Contains "\\") && not (text.Contains ".dll") && not (text.Contains ".exe") &&
- try let aname = System.Reflection.AssemblyName x.Text in aname.Name = name
- with _ -> false)
-
- override x.ToString() = sprintf "AssemblyReference(%s)" x.Text
-
-type UnresolvedAssemblyReference = UnresolvedAssemblyReference of string * AssemblyReference list
-#if !NO_EXTENSIONTYPING
-type ResolvedExtensionReference = ResolvedExtensionReference of string * AssemblyReference list * Tainted list
-#endif
-
-/// The thread in which compilation calls will be enqueued and done work on.
-/// Note: This is currently only used when disposing of type providers and will be extended to all the other type provider calls when compilations can be done in parallel.
-/// Right now all calls in FCS to type providers are single-threaded through use of the reactor thread.
-type ICompilationThread =
-
- /// Enqueue work to be done on a compilation thread.
- abstract EnqueueWork: (CompilationThreadToken -> unit) -> unit
-
-type ImportedBinary =
- { FileName: string
- RawMetadata: IRawFSharpAssemblyData
-#if !NO_EXTENSIONTYPING
- ProviderGeneratedAssembly: System.Reflection.Assembly option
- IsProviderGenerated: bool
- ProviderGeneratedStaticLinkMap: ProvidedAssemblyStaticLinkingMap option
-#endif
- ILAssemblyRefs: ILAssemblyRef list
- ILScopeRef: ILScopeRef }
-
-type ImportedAssembly =
- { ILScopeRef: ILScopeRef
- FSharpViewOfMetadata: CcuThunk
- AssemblyAutoOpenAttributes: string list
- AssemblyInternalsVisibleToAttributes: string list
-#if !NO_EXTENSIONTYPING
- IsProviderGenerated: bool
- mutable TypeProviders: Tainted list
-#endif
- FSharpOptimizationData: Microsoft.FSharp.Control.Lazy