diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000000..07354ce197e6f
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,56 @@
+# Contributing to Roslyn
+
+Guidelines for contributing to the Roslyn repo.
+
+## Submitting Pull Requests
+
+- **DO** ensure submissions pass all Jenkins legs and are merge conflict free.
+- **DO** follow the [.editorconfig](http://editorconfig.org/) settings for each directory.
+- **DO** submit language feature requests as issues in the [C# language](https://github.com/dotnet/csharplang#discussion) / [VB language](https://github.com/dotnet/vblang) repos. Once a feature is championed and validated by LDM a developer will be assigned to help begin a prototype on this repo inside a feature branch.
+- **DO NOT** submit language features as PRs to this repo first, or they will likely be declined.
+- **DO** submit issues for other features. This facilitates discussion of a feature separately from its implementation, and increases the acceptance rates for pull requests.
+- **DO NOT** submit large code formatting changes without discussing with the team first.
+
+When you are ready to proceed with making a change, get set up to [build](https://github.com/dotnet/roslyn/blob/master/docs/contributing/Building%2C%20Debugging%2C%20and%20Testing%20on%20Windows.md) the code and familiarize yourself with our developer workflow.
+
+These two blogs posts on contributing code to open source projects are good too: [Open Source Contribution Etiquette](http://tirania.org/blog/archive/2010/Dec-31.html) by Miguel de Icaza and [Don’t “Push” Your Pull Requests](https://www.igvita.com/2011/12/19/dont-push-your-pull-requests/) by Ilya Grigorik.
+
+## Creating Issues
+
+- **DO** use a descriptive title that identifies the issue to be addressed or the requested feature. For example when describing an issue where the compiler is not behaving as expected, write your bug title in terms of what the compiler should do rather than what it is doing – “C# compiler should report CS1234 when Xyz is used in Abcd.”
+- **DO** specify a detailed description of the issue or requested feature.
+- **DO** provide the following for bug reports
+ - Describe the expected behavior and the actual behavior. If it is not self-evident such as in the case of a crash, provide an explanation for why the expected behavior is expected.
+ - Provide example code that reproduces the issue.
+ - Specify any relevant exception messages and stack traces.
+- **DO** subscribe to notifications for the created issue in case there are any follow up questions.
+
+## Coding Style
+
+The Roslyn project is a member of the [.NET Foundation](https://github.com/orgs/dotnet) and follow the same [developer guide](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md). The repo also includes [.editorconfig](http://editorconfig.org) files to help enforce this convention. Contributors should ensure they follow these guidelines when making submissions.
+
+### CSharp
+
+- **DO** use the coding style outlined in the [.NET Foundation Coding Guidelines](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md)
+- **DO** use plain code to validate parameters at public boundaries. Do not use Contracts or magic helpers.
+
+```csharp
+if (argument == null)
+{
+ throw new ArgumentNullException(nameof(argument));
+}
+```
+
+- **DO** use `Debug.Assert()` for checks not needed in retail builds. Always include a “message” string in your assert to identify failure conditions. Add assertions to document assumptions on non-local program state or parameter values, e.g. “At this point in parsing the scanner should have been advanced to a ‘.’ token by the caller”.
+- **DO** avoid allocations in compiler hot paths:
+ - Avoid LINQ.
+ - Avoid using `foreach` over collections that do not have a `struct` enumerator.
+ - Consider using an object pool. There are many usages of object pools in the compiler to see an example.
+
+### Visual Basic Conventions
+
+- **DO** apply the spirit of C# guidelines to Visual Basic when there are natural analogs.
+- **DO** place all field declarations at the beginning of a type definition
+
+### Tips 'n' Tricks
+Our team finds using [this enhanced source view](http://source.roslyn.io/) of Roslyn helpful when developing.
\ No newline at end of file
diff --git a/Makefile b/Makefile
index c407143699ef2..c00e72729f700 100644
--- a/Makefile
+++ b/Makefile
@@ -43,8 +43,8 @@ bootstrap: restore
$(BUILD_CMD) src/Compilers/CSharp/CscCore && \
$(BUILD_CMD) src/Compilers/VisualBasic/VbcCore && \
mkdir -p $(BOOTSTRAP_PATH)/csc && mkdir -p $(BOOTSTRAP_PATH)/vbc && \
- dotnet publish -r $(RUNTIME_ID) src/Compilers/CSharp/CscCore -o $(BOOTSTRAP_PATH)/csc && \
- dotnet publish -r $(RUNTIME_ID) src/Compilers/VisualBasic/VbcCore -o $(BOOTSTRAP_PATH)/vbc
+ dotnet publish -c $(BUILD_CONFIGURATION) -r $(RUNTIME_ID) src/Compilers/CSharp/CscCore -o $(BOOTSTRAP_PATH)/csc && \
+ dotnet publish -c $(BUILD_CONFIGURATION) -r $(RUNTIME_ID) src/Compilers/VisualBasic/VbcCore -o $(BOOTSTRAP_PATH)/vbc
rm -rf Binaries/$(BUILD_CONFIGURATION)
test:
diff --git a/NuGet.Config b/NuGet.Config
index 43d2539f28212..0ea90a3391db9 100644
--- a/NuGet.Config
+++ b/NuGet.Config
@@ -19,6 +19,7 @@
+
diff --git a/Roslyn.sln b/Roslyn.sln
index c865f2080720b..d84b0ca587bd8 100644
--- a/Roslyn.sln
+++ b/Roslyn.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.26228.4
+VisualStudioVersion = 15.0.26507.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{A41D1B99-F489-4C43-BBDF-96D61B19A6B9}"
EndProject
diff --git a/build/NuGetAdditionalFiles/Microsoft.Net.Compilers.props b/build/NuGetAdditionalFiles/Microsoft.Net.Compilers.props
index 769370f3a3252..d65f4c022464d 100644
--- a/build/NuGetAdditionalFiles/Microsoft.Net.Compilers.props
+++ b/build/NuGetAdditionalFiles/Microsoft.Net.Compilers.props
@@ -23,6 +23,8 @@
AssemblyFile="$(MSBuildThisFileDirectory)..\tools\Microsoft.Build.Tasks.CodeAnalysis.dll" />
+
false
diff --git a/build/Targets/Packages.props b/build/Targets/Packages.props
index d359d97267662..877de7a25362b 100644
--- a/build/Targets/Packages.props
+++ b/build/Targets/Packages.props
@@ -36,9 +36,9 @@
0.8.31-beta
1.0.35
1.1.0
- 1.0.0-beta1-61618-01
- 1.5.0
- 1.2.0
+ 1.0.0-beta1-61708-01
+ 1.6.0-beta2-25304
+ 1.3.0-beta1-61619-01
4.7.1-alpha-00001
3.13.8
15.0.26201-alpha
@@ -47,7 +47,7 @@
8.0.0.0-alpha
2.0.1
2.0.0-rc2-61102-09
- 1.2.0-beta2
+ 2.0.0-beta1-61628-06
1.1.0
2.3.0-dev-56735-00
5.0.0
@@ -221,6 +221,7 @@
12.0.4
8.0.0.0-alpha
2.2.0-beta4-build3444
+ 2.2.0-beta4-build3444
1.0.2-prerelease-00104
2.2.0-beta4-build3444
2.2.0-beta4-build1194
diff --git a/build/Targets/Settings.props b/build/Targets/Settings.props
index f0933dfe67e3a..9e4567f567f03 100644
--- a/build/Targets/Settings.props
+++ b/build/Targets/Settings.props
@@ -14,7 +14,7 @@
$(RepoRoot)build\ToolsetPackages\
RoslynTools.Microsoft.VSIXExpInstaller
0.2.1-beta
- 2.0.0-beta1-61628-06
+ $(MicrosoftNetRoslynDiagnosticsVersion)
$(NuGetPackageRoot)\Microsoft.Net.RoslynDiagnostics\$(RoslynDiagnosticsNugetPackageVersion)\build\Microsoft.Net.RoslynDiagnostics.props
$(NuGetPackageRoot)\Roslyn.Build.Util\0.9.4-portable\lib\dotnet\Roslyn.MSBuild.Util.dll
win7-x64
@@ -239,6 +239,7 @@
$(InitialDefineConstants)
+ On
$(NoWarn);1591
diff --git a/build/scripts/test-determinism.ps1 b/build/scripts/test-determinism.ps1
index 74f497ebe9e65..c087c9510729a 100644
--- a/build/scripts/test-determinism.ps1
+++ b/build/scripts/test-determinism.ps1
@@ -46,7 +46,7 @@ function Run-Build() {
}
Write-Host "Building the Solution"
- Exec-Command $msbuild "/nologo /v:m /nodeReuse:false /m /p:DebugDeterminism=true /p:BootstrapBuildPath=$script:bootstrapDir /p:Features=`"debug-determinism;pdb-path-determinism`" /p:UseRoslynAnalyzers=false $pathMapBuildOption $sln"
+ Exec-Command $msbuild "/nologo /v:m /nodeReuse:false /m /p:DebugDeterminism=true /p:BootstrapBuildPath=$script:bootstrapDir /p:Features=`"debug-determinism`" /p:UseRoslynAnalyzers=false $pathMapBuildOption $sln"
}
finally {
Pop-Location
diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md
index ab18ef653b598..4ad73499c3690 100644
--- a/docs/Language Feature Status.md
+++ b/docs/Language Feature Status.md
@@ -10,11 +10,11 @@ efforts behind them.
| Feature | Branch | State | Developers | Reviewer | LDM Champ |
| ------- | ------ | ----- | ---------- | -------- | --------- |
-| [Async Main](https://github.com/dotnet/csharplang/blob/master/proposals/async-main.md) | [async-main](https://github.com/dotnet/roslyn/tree/features/async-main) | Prototype | [tyoverby](https://github.com/tyoverby) | [vsadov](https://github.com/vsadov) | [stephentoub](https://github.com/stephentoub) |
+| [Async Main](https://github.com/dotnet/csharplang/blob/master/proposals/async-main.md) | master | Merged | [tyoverby](https://github.com/tyoverby) | [vsadov](https://github.com/vsadov) | [stephentoub](https://github.com/stephentoub) |
| [Default Expressions](https://github.com/dotnet/csharplang/blob/master/proposals/target-typed-default.md) | master | Merged | [jcouv](https://github.com/jcouv) | [cston](https://github.com/cston) | [jcouv](https://github.com/jcouv) |
-| [Ref Assemblies](https://github.com/dotnet/roslyn/blob/features/refout/docs/features/refout.md) | [refout](https://github.com/dotnet/roslyn/tree/features/refout) | Integration & validation | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | N/A |
-| [Infer tuple names](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/infer-tuple-names.md) | master | Merged | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | [jcouv](https://github.com/jcouv) |
-| [Pattern-matching with generics](https://github.com/dotnet/csharplang/blob/master/proposals/generics-pattern-match.md) | https://github.com/dotnet/roslyn/pull/18784 | Implementation | [gafter](https://github.com/gafter) | [agocke](https://github.com/agocke) | [gafter](https://github.com/gafter) |
+| [Ref Assemblies](https://github.com/dotnet/roslyn/blob/master/docs/features/refout.md) | master | Merged (MSBuild integration ongoing) | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | N/A |
+| [Infer tuple names](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/infer-tuple-names.md) | master | Merged | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | [jcouv](https://github.com/jcouv) |
+| [Pattern-matching with generics](https://github.com/dotnet/csharplang/blob/master/proposals/generics-pattern-match.md) | master | Merged | [gafter](https://github.com/gafter) | [agocke](https://github.com/agocke) | [gafter](https://github.com/gafter) |
# C# 7.2
diff --git a/docs/compilers/CSharp/CommandLine.md b/docs/compilers/CSharp/CommandLine.md
index 8244ce7bfc71e..79c30791229c9 100644
--- a/docs/compilers/CSharp/CommandLine.md
+++ b/docs/compilers/CSharp/CommandLine.md
@@ -4,6 +4,7 @@
| ---- | ---- |
| **OUTPUT FILES** |
| `/out:`*file* | Specify output file name (default: base name of file with main class or first file)
+| `/refout:`*file* | Specify the reference assembly's output file name
| `/target:exe` | Build a console executable (default) (Short form: `/t:exe`)
| `/target:winexe` | Build a Windows executable (Short form: `/t:winexe` )
| `/target:library` | Build a library (Short form: `/t:library`)
@@ -29,9 +30,14 @@
| `/linkresource`:*resinfo* | Link the specified resource to this assembly (Short form: `/linkres`) Where the *resinfo* format is *file*{`,`*string name*{`,``public``|``private`}}
| **CODE GENERATION**
| `/debug`{`+`|`-`} | Emit (or do not Emit) debugging information
-| `/debug`:{`full`|`pdbonly`|`portable`} | Specify debugging type (`full` is default, and enables attaching a debugger to a running program. `portable` is a cross-platform format)
+| `/debug`:`full` | Emit debugging information to .pdb file using default format for the current platform: _Windows PDB_ on Windows, _Portable PDB_ on other systems
+| `/debug`:`pdbonly` | Same as `/debug:full`. For backward compatibility.
+| `/debug`:`portable` | Emit debugging information to to .pdb file using cross-platform [Portable PDB format](https://github.com/dotnet/core/blob/master/Documentation/diagnostics/portable_pdb.md)
+| `/debug`:`embedded` | Emit debugging information into the .dll/.exe itself (.pdb file is not produced) using [Portable PDB format](https://github.com/dotnet/core/blob/master/Documentation/diagnostics/portable_pdb.md).
+| `/sourcelink`:*file* | [Source link](https://github.com/dotnet/core/blob/master/Documentation/diagnostics/source_link.md) info to embed into PDB.
| `/optimize`{`+`|`-`} | Enable optimizations (Short form: `/o`)
| `/deterministic` | Produce a deterministic assembly (including module version GUID and timestamp)
+| `/refonly | Produce a reference assembly, instead of a full assembly, as the primary output
| **ERRORS AND WARNINGS**
| `/warnaserror`{`+`|`-`} | Report all warnings as errors
| `/warnaserror`{`+`|`-`}`:`*warn list* | Report specific warnings as errors
diff --git a/docs/compilers/Visual Basic/CommandLine.md b/docs/compilers/Visual Basic/CommandLine.md
index 0a7afcefd67da..052da8442d06c 100644
--- a/docs/compilers/Visual Basic/CommandLine.md
+++ b/docs/compilers/Visual Basic/CommandLine.md
@@ -4,6 +4,7 @@
| ---- | ---- |
| **OUTPUT FILE**
| `/out:`*file* | Specifies the output file name.
+| `/refout:`*file* | Specify the reference assembly's output file name
| `/target:exe` | Create a console application (default). (Short form: `/t`)
| `/target:winexe` | Create a Windows application.
| `/target:library` | Create a library assembly.
@@ -27,13 +28,19 @@
| `/win32manifest:`*file* | The provided file is embedded in the manifest section of the output PE.
| `/win32resource:`*file* | Specifies a Win32 resource file (.res).
| **CODE GENERATION**
+| `/debug`{`+`|`-`} | Emit debugging information.
+| `/debug`:`full` | Emit debugging information to .pdb file using default format for the current platform: _Windows PDB_ on Windows, _Portable PDB_ on other systems
+| `/debug`:`pdbonly` | Same as `/debug:full`. For backward compatibility.
+| `/debug`:`portable` | Emit debugging information to to .pdb file using cross-platform [Portable PDB format](https://github.com/dotnet/core/blob/master/Documentation/diagnostics/portable_pdb.md)
+| `/debug`:`embedded` | Emit debugging information into the .dll/.exe itself (.pdb file is not produced) using [Portable PDB format](https://github.com/dotnet/core/blob/master/Documentation/diagnostics/portable_pdb.md).
+| `/sourcelink`:*file* | [Source link](https://github.com/dotnet/core/blob/master/Documentation/diagnostics/source_link.md) info to embed into PDB.
| `/optimize`{`+`|`-`} | Enable optimizations.
| `/removeintchecks`{`+`|`-`} | Remove integer checks. Default off.
-| `/debug`{`+`|`-`} | Emit debugging information.
| `/debug:full` | Emit full debugging information (default).
| `/debug:portable` | Emit debugging information in the portable format.
| `/debug:pdbonly` | Emit PDB file only.
| `/deterministic` | Produce a deterministic assembly (including module version GUID and timestamp)
+| `/refonly | Produce a reference assembly, instead of a full assembly, as the primary output
| **ERRORS AND WARNINGS**
| `/nowarn` | Disable all warnings.
| `/nowarn:`*number_list* | Disable a list of individual warnings.
diff --git a/docs/contributing/Building, Debugging, and Testing on Unix.md b/docs/contributing/Building, Debugging, and Testing on Unix.md
index 1ea526cdcc90e..cb2b21c691309 100644
--- a/docs/contributing/Building, Debugging, and Testing on Unix.md
+++ b/docs/contributing/Building, Debugging, and Testing on Unix.md
@@ -10,4 +10,4 @@ After building run `make test` in order to run the unit tests.
# Contributing
-Please see [Contributing Code](https://github.com/dotnet/roslyn/wiki/Contributing-Code) for details on contributing changes back to the code.
+Please see [Contributing Code](https://github.com/dotnet/roslyn/blob/master/CONTRIBUTING.md) for details on contributing changes back to the code.
diff --git a/docs/contributing/Building, Debugging, and Testing on Windows.md b/docs/contributing/Building, Debugging, and Testing on Windows.md
index 14b8af173cd45..0148f02cb3386 100644
--- a/docs/contributing/Building, Debugging, and Testing on Windows.md
+++ b/docs/contributing/Building, Debugging, and Testing on Windows.md
@@ -119,4 +119,4 @@ csc and vbc inside it. You can check the cibuild.cmd and see how it is used.
## Contributing
-Please see [Contributing Code](https://github.com/dotnet/roslyn/wiki/Contributing-Code) for details on contributing changes back to the code.
+Please see [Contributing Code](https://github.com/dotnet/roslyn/blob/master/CONTRIBUTING.md)) for details on contributing changes back to the code.
diff --git a/docs/features/async-main.md b/docs/features/async-main.md
new file mode 100644
index 0000000000000..b98068cd8c603
--- /dev/null
+++ b/docs/features/async-main.md
@@ -0,0 +1,12 @@
+# Async Task Main
+## [dotnet/csharplang proposal](https://github.com/dotnet/csharplang/blob/master/proposals/async-main.md)
+
+## Technical Details
+
+* The compiler must recognize `Task` and `Task` as valid entrypoint return types in addition to `void` and `int`.
+* The compiler must allow `async` to be placed on a main method that returns a `Task` or a `Task` (but not void).
+* The compiler must generate a shim method `$EntrypointMain` that mimics the arguments of the user-defined main.
+ * `static async Task Main(...)` -> `static void $EntrypointMain(...)`
+ * `static async Task Main(...)` -> `static int $EntrypointMain(...)`
+ * The parameters between the user-defined main and the generated main should match exactly.
+* The body of the generated main should be `return Main(args...).GetAwaiter().GetResult();`
\ No newline at end of file
diff --git a/docs/features/async-main.test.md b/docs/features/async-main.test.md
new file mode 100644
index 0000000000000..9b4a51467e559
--- /dev/null
+++ b/docs/features/async-main.test.md
@@ -0,0 +1,99 @@
+Main areas to test:
+* Signature acceptance / rejection
+* Method body creation
+
+# Signature acceptance / rejection
+
+## Single Mains
+Classes that contain only a single "main" method
+
+### Single legal main
+* Past: Ok
+* New 7: Ok
+* New 7.1 Ok
+
+### Single async (void) main
+* Past: ERR (Async can't be main)
+* New 7: ERR (Update to get this to work)
+* New 7.1: Ok
+
+### Single async (Task) main
+* Past: ERR (No entrypoints found), WARN (has the wrong signature to be an entry point)
+* New 7: ERR (Update to get this to work)
+* New 7.1 Ok
+
+### Single async (Task) main
+* Past: ERR (No entrypoints found), WARN (has the wrong signature)
+* New 7: ERR (Update to get this to work)
+* New 7.1: Ok
+
+## Multiple Mains
+Classes that contain more than one main
+
+### Multiple legal mains
+* Past: Err
+* New 7: Err
+* New 7.1: Err
+
+### Single legal main, single async (void) main
+* Past: Err (an entrypoint cannot be marked with async)
+* New 7: Err (new error here?)
+* New 7.1: Err (new error here? "void is not an acceptable async return type")
+
+### Single legal main, single legal Task main
+* Past: Ok (warning: task main has wrong signature)
+* New 7: Ok (new warning here)
+* New 7.1: Ok (new warning here?)
+
+### Single legal main, single legal Task main
+* Past: Ok (warning: task main has wrong signature)
+* New 7: Ok (new warning here)
+* New 7.1: Ok (new warning here?)
+
+# Method body creation
+
+* Inspect IL for correct codegen.
+* Make sure that attributes are correctly applied to the synthesized mains.
+
+## Broken methods on Task and Task
+
+* GetAwatier or GetResult are missing
+* GetAwaiter or GetResult don't have the required signature
+* Has the right shape, but types are missing
+
+## Task or Task is missing
+
+This will be caught during entrypoint detection, should be a binding error.
+
+## Void or int is missing
+
+If Task can be found, but void or int can't be found, then the compiler should behave gracefully.
+
+# Vlad Test Plan
+
+## Public interface of compiler APIs
+ -N/A?
+
+## General functionality
+- `Task` and `Task` returns are allowed. Do we require `async`.
+- Multiple valid/invalid async candidates.
+- process exit code on success (void and int) and on exception
+- `/main:` cmd switch is still functional
+
+## Old versions, compat
+- langver
+- when both async and regular Main avaialble. With old/new compiler versions.
+- async void Main. With old.new langver. With another applicable Main present.
+
+## Type and members
+- Access modifiers (public, protected, internal, protected internal, private), static modifier
+- Parameter modifiers (ref, out, params)
+- STA attribute
+- Partial method
+- Named and optional parameters
+- `Task`
+- Task-Like types
+
+## Debug
+- F11 works
+- stepping through Main
diff --git a/docs/features/refout.md b/docs/features/refout.md
new file mode 100644
index 0000000000000..9231dd37ee3f9
--- /dev/null
+++ b/docs/features/refout.md
@@ -0,0 +1,78 @@
+# Reference assemblies
+
+Reference assemblies are metadata-only assemblies with the minimum amount of metadata to preserve the compile-time behavior of consumers (diagnostics may be affected, though).
+The compiler may choose to remove more metadata in later versions, if it is determined to be safe (ie. respects the principle above).
+
+## Scenarios
+There are 4 scenarios:
+
+1. The traditional one, where an assembly is emitted as the primary output (`/out` command-line parameter, or `peStream` parameter in `Compilation.Emit` APIs).
+2. The IDE scenario, where the metadata-only assembly is emitted (via `Emit` API), still as the primary output. Later on, the IDE is interested to get metadata-only assemblies even when there are errors in the compilation.
+3. The CoreFX scenario, where only the ref assembly is emitted, still as the primary output (`/refonly` command-line parameter)
+4. The MSBuild scenario, which is the new scenario, where both a real assembly is emitted as the primary output, and a ref assembly is emitted as the secondary output (`/refout` command-line parameter, or `metadataPeStream` parameter in `Emit`).
+
+
+## Definition of ref assemblies
+Metadata-only assembly have their method bodies replaced with a single `throw null` body, but include all members except anonymous types. The reason for using `throw null` bodies (as opposed to no bodies) is so that PEVerify could run and pass (thus validating the completeness of the metadata).
+Ref assemblies will include an assembly-level `ReferenceAssembly` attribute. This attribute may be specified in source (then we won't need to synthesize it). Because of this attribute, runtimes will refuse to load ref assemblies for execution (but they can still be loaded Reflection-only mode).
+Ref assemblies further remove metadata (private members) from metadata-only assemblies:
+
+- A ref assembly will only have references for what it needs in the API surface. The real assembly may have additional references related to specific implementations. For instance, the ref assembly for `class C { private void M() { dynamic d = 1; ... } }` will not reference any types required for `dynamic`.
+- Private function-members (methods, properties and events) will be removed. If there are no `InternalsVisibleTo` attributes, do the same for internal function-members
+- But all types (including private or nested types) must be kept in ref assemblies. All attributes must be kept (even internal ones).
+- All virtual methods will be kept. Explicit interface implementations will be kept.
+- All fields of a struct will be kept. (This is a candidate for post-C#-7.1 refinement)
+
+## API changes
+
+### Command-line
+Two mutually exclusive command-line parameters will be added to `csc.exe` and `vbc.exe`:
+- `/refout`
+- `/refonly`
+
+The `/refout` parameter specifies a file path where the ref assembly should be output. This translates to `metadataPeStream` in the `Emit` API (see details below). The filename for the ref assembly should generally match that of the primary assembly (we will warn when they don't match). The recommended convention (used by MSBuild) is to place the ref assembly in a "ref/" sub-folder relative to the primary assembly.
+
+The `/refonly` parameter is a flag that indicates that a ref assembly should be output instead of an implementation assembly, as the primary output.
+The `/refonly` parameter is not allowed together with the `/refout` parameter, as it doesn't make sense to have both the primary and secondary outputs be ref assemblies. Also, the `/refonly` parameter silently disables outputting PDBs, as ref assemblies cannot be executed.
+The `/refonly` parameter translates to `EmitMetadataOnly` being `true`, and `IncludePrivateMembers` being `false` in the `Emit` API (see details below).
+Neither `/refonly` nor `/refout` are permitted with net modules (`/target:module`, `/addmodule` options).
+
+The compilation from the command-line will either produce both assemblies (implementation and ref) or neither. There is no "partial success" scenario.
+When the compiler produces documentation, it is un-affected by either the `/refonly` or `/refout` parameters. This may change in the future.
+The main purpose of the `/refout` option is to speed up incremental build scenarios. The current implementation for this flag can produce a ref assembly with more metadata than `/refonly` (for instance, anonymous types). This is a candidate for post-C#-7.1 refinement.
+
+### CscTask/CoreCompile
+The `CoreCompile` target will support a new output, called `IntermediateRefAssembly`, which parallels the existing `IntermediateAssembly`.
+The `Csc` task will support a new output, called `OutputRefAssembly`, which parallels the existing `OutputAssembly`.
+Both of those basically map to the `/refout` command-line parameter.
+
+An additional task, called `CopyRefAssembly`, will be provided along with the existing `Csc` task. It takes a `SourcePath` and a `DestinationPath` and generally copies the file from the source over to the destination. But if it can determine that the contents of those two files match (by comparing their MVIDs, see details below), then the destination file is left untouched.
+
+As a side-note, `CopyRefAssembly` uses the same assembly resolution/redirection trick as `Csc` and `Vbc`, to avoid type loading problems with `System.IO.FileSystem`.
+
+### CodeAnalysis APIs
+It is already possible to produce metadata-only assemblies by using `EmitOptions.EmitMetadataOnly`, which is used in IDE scenarios with cross-language dependencies.
+The compiler will be updated to honour the `EmitOptions.IncludePrivateMembers` flag as well. When combined with `EmitMetadataOnly` or a `metadataPeStream` in `Emit`, a ref assembly will be produced.
+The diagnostic check for emitting methods lacking a body (`void M();`) will be filtered from declaration diagnostics, so that code will successfully emit with `EmitMetadataOnly`.
+Later on, the `EmitOptions.TolerateErrors` flag will allow emitting error types as well.
+`Emit` is also modified to produce a new PE section called ".mvid" containing a copy of the MVID, when producing ref assemblies. This makes it easy for `CopyRefAssembly` to extract and compare MVIDs from ref assemblies.
+
+Going back to the 4 driving scenarios:
+1. For a regular compilation, `EmitMetadataOnly` is left to `false` and no `metadataPeStream` is passed into `Emit`.
+2. For the IDE scenario, `EmitMetadataOnly` is set to `true`, but `IncludePrivateMembers` is left to `true`.
+3. For the CoreFX scenario, ref assembly source code is used as input, `EmitMetadataOnly` is set to `true`, and `IncludePrivateMembers` is set to `false`.
+4. For the MSBuild scenario, `EmitMetadataOnly` is left to `false`, a `metadataPeStream` is passed in and `IncludePrivateMembers` is set to `false`.
+
+## Future
+As mentioned above, there may be further refinements after C# 7.1:
+- Further reduce the metadata in ref assemblies produced by `/refout`, to match those produced by `/refonly`.
+- Controlling internals (producing public ref assemblies)
+- Produce ref assemblies even when there are errors outside method bodies (emitting error types when `EmitOptions.TolerateErrors` is set)
+- When the compiler produces documentation, the contents produced could be filtered down to match the APIs that go into the primary output. In other words, the documentation could be filtered down when using the `/refonly` parameter.
+
+## Open questions
+
+## Related issues
+- Produce ref assemblies from command-line and msbuild (https://github.com/dotnet/roslyn/issues/2184)
+- Refine what is in reference assemblies and what diagnostics prevent generating one (https://github.com/dotnet/roslyn/issues/17612)
+- [Are private members part of the API surface?](http://blog.paranoidcoding.com/2016/02/15/are-private-members-api-surface.html)
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs
index 371874bcdeae1..61611318c2954 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs
@@ -29,7 +29,7 @@ private BoundExpression BindAwait(BoundExpression expression, SyntaxNode node, D
bool hasErrors =
ReportBadAwaitWithoutAsync(node, diagnostics) |
ReportBadAwaitContext(node, diagnostics) |
- !GetAwaitableExpressionInfo(expression, out getAwaiter, out isCompleted, out getResult, node, diagnostics);
+ !GetAwaitableExpressionInfo(expression, out getAwaiter, out isCompleted, out getResult, out _, node, diagnostics);
// Spec 7.7.7.2:
// The expression await t is classified the same way as the expression (t).GetAwaiter().GetResult(). Thus,
@@ -209,17 +209,19 @@ private bool ReportBadAwaitContext(SyntaxNode node, DiagnosticBag diagnostics)
/// Finds and validates the required members of an awaitable expression, as described in spec 7.7.7.1.
///
/// True if the expression is awaitable; false otherwise.
- private bool GetAwaitableExpressionInfo(
+ internal bool GetAwaitableExpressionInfo(
BoundExpression expression,
out MethodSymbol getAwaiter,
out PropertySymbol isCompleted,
out MethodSymbol getResult,
+ out BoundExpression getAwaiterGetResultCall,
SyntaxNode node,
DiagnosticBag diagnostics)
{
getAwaiter = null;
isCompleted = null;
getResult = null;
+ getAwaiterGetResultCall = null;
if (!ValidateAwaitedExpression(expression, node, diagnostics))
{
@@ -231,7 +233,8 @@ private bool GetAwaitableExpressionInfo(
return true;
}
- if (!GetGetAwaiterMethod(expression, node, diagnostics, out getAwaiter))
+ BoundExpression getAwaiterCall = null;
+ if (!GetGetAwaiterMethod(expression, node, diagnostics, out getAwaiter, out getAwaiterCall))
{
return false;
}
@@ -239,7 +242,7 @@ private bool GetAwaitableExpressionInfo(
TypeSymbol awaiterType = getAwaiter.ReturnType;
return GetIsCompletedProperty(awaiterType, node, expression.Type, diagnostics, out isCompleted)
&& AwaiterImplementsINotifyCompletion(awaiterType, node, diagnostics)
- && GetGetResultMethod(awaiterType, node, expression.Type, diagnostics, out getResult);
+ && GetGetResultMethod(getAwaiterCall, node, expression.Type, diagnostics, out getResult, out getAwaiterGetResultCall);
}
///
@@ -273,19 +276,21 @@ private static bool ValidateAwaitedExpression(BoundExpression expression, Syntax
/// NOTE: this is an error in the spec. An extension method of the form
/// Awaiter<T> GetAwaiter<T>(this Task<T>) may be used.
///
- private bool GetGetAwaiterMethod(BoundExpression expression, SyntaxNode node, DiagnosticBag diagnostics, out MethodSymbol getAwaiterMethod)
+ private bool GetGetAwaiterMethod(BoundExpression expression, SyntaxNode node, DiagnosticBag diagnostics, out MethodSymbol getAwaiterMethod, out BoundExpression getAwaiterCall)
{
if (expression.Type.SpecialType == SpecialType.System_Void)
{
Error(diagnostics, ErrorCode.ERR_BadAwaitArgVoidCall, node);
getAwaiterMethod = null;
+ getAwaiterCall = null;
return false;
}
- var getAwaiterCall = MakeInvocationExpression(node, expression, WellKnownMemberNames.GetAwaiter, ImmutableArray.Empty, diagnostics);
+ getAwaiterCall = MakeInvocationExpression(node, expression, WellKnownMemberNames.GetAwaiter, ImmutableArray.Empty, diagnostics);
if (getAwaiterCall.HasAnyErrors) // && !expression.HasAnyErrors?
{
getAwaiterMethod = null;
+ getAwaiterCall = null;
return false;
}
@@ -293,6 +298,7 @@ private bool GetGetAwaiterMethod(BoundExpression expression, SyntaxNode node, Di
{
Error(diagnostics, ErrorCode.ERR_BadAwaitArg, node, expression.Type);
getAwaiterMethod = null;
+ getAwaiterCall = null;
return false;
}
@@ -303,6 +309,7 @@ private bool GetGetAwaiterMethod(BoundExpression expression, SyntaxNode node, Di
{
Error(diagnostics, ErrorCode.ERR_BadAwaitArg, node, expression.Type);
getAwaiterMethod = null;
+ getAwaiterCall = null;
return false;
}
@@ -383,28 +390,31 @@ private bool AwaiterImplementsINotifyCompletion(TypeSymbol awaiterType, SyntaxNo
/// Spec 7.7.7.1:
/// An Awaiter A has an accessible instance method GetResult with no parameters and no type parameters.
///
- private bool GetGetResultMethod(TypeSymbol awaiterType, SyntaxNode node, TypeSymbol awaitedExpressionType, DiagnosticBag diagnostics, out MethodSymbol getResultMethod)
+ private bool GetGetResultMethod(BoundExpression awaiterExpression, SyntaxNode node, TypeSymbol awaitedExpressionType, DiagnosticBag diagnostics, out MethodSymbol getResultMethod, out BoundExpression getAwaiterGetResultCall)
{
- var receiver = new BoundLiteral(node, ConstantValue.Null, awaiterType);
- var getResultCall = MakeInvocationExpression(node, receiver, WellKnownMemberNames.GetResult, ImmutableArray.Empty, diagnostics);
- if (getResultCall.HasAnyErrors)
+ var awaiterType = awaiterExpression.Type;
+ getAwaiterGetResultCall = MakeInvocationExpression(node, awaiterExpression, WellKnownMemberNames.GetResult, ImmutableArray.Empty, diagnostics);
+ if (getAwaiterGetResultCall.HasAnyErrors)
{
getResultMethod = null;
+ getAwaiterGetResultCall = null;
return false;
}
- if (getResultCall.Kind != BoundKind.Call)
+ if (getAwaiterGetResultCall.Kind != BoundKind.Call)
{
Error(diagnostics, ErrorCode.ERR_NoSuchMember, node, awaiterType, WellKnownMemberNames.GetResult);
getResultMethod = null;
+ getAwaiterGetResultCall = null;
return false;
}
- getResultMethod = ((BoundCall)getResultCall).Method;
+ getResultMethod = ((BoundCall)getAwaiterGetResultCall).Method;
if (getResultMethod.IsExtensionMethod)
{
Error(diagnostics, ErrorCode.ERR_NoSuchMember, node, awaiterType, WellKnownMemberNames.GetResult);
getResultMethod = null;
+ getAwaiterGetResultCall = null;
return false;
}
@@ -412,6 +422,7 @@ private bool GetGetResultMethod(TypeSymbol awaiterType, SyntaxNode node, TypeSym
{
Error(diagnostics, ErrorCode.ERR_BadAwaiterPattern, node, awaiterType, awaitedExpressionType);
getResultMethod = null;
+ getAwaiterGetResultCall = null;
return false;
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
index 42648bd0353c2..9a72799ed7212 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
@@ -1,12 +1,11 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
-using Roslyn.Utilities;
-using System.Collections.Immutable;
-using System;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
@@ -114,40 +113,13 @@ protected BoundExpression CreateConversion(
syntax,
source,
conversion,
- IsCheckedConversion(source.Type, destination),
+ @checked: CheckOverflowAtRuntime,
explicitCastInCode: isCast && !wasCompilerGenerated,
constantValueOpt: constantValue,
type: destination)
{ WasCompilerGenerated = wasCompilerGenerated };
}
- private bool IsCheckedConversion(TypeSymbol source, TypeSymbol target)
- {
- Debug.Assert((object)target != null);
-
- if ((object)source == null || !CheckOverflowAtRuntime)
- {
- return false;
- }
-
- if (source.IsDynamic())
- {
- return true;
- }
-
- SpecialType sourceST = source.StrippedType().EnumUnderlyingType().SpecialType;
- SpecialType targetST = target.StrippedType().EnumUnderlyingType().SpecialType;
-
- // integral to double or float is never checked, but float/double to integral
- // may be checked.
- bool sourceIsNumeric = SpecialType.System_Char <= sourceST && sourceST <= SpecialType.System_Double;
- bool targetIsNumeric = SpecialType.System_Char <= targetST && targetST <= SpecialType.System_UInt64;
-
- return
- sourceIsNumeric && (targetIsNumeric || target.IsPointerType()) ||
- targetIsNumeric && source.IsPointerType();
- }
-
protected BoundExpression CreateUserDefinedConversion(SyntaxNode syntax, BoundExpression source, Conversion conversion, bool isCast, TypeSymbol destination, DiagnosticBag diagnostics)
{
if (!conversion.IsValid)
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
index b1ad911ea2e27..4703735b71f37 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
@@ -3433,6 +3433,7 @@ private BoundExpression BindConstructorInitializerCore(
invokedAsExtensionMethod: false,
argsToParamsOpt: memberResolutionResult.Result.ArgsToParamsOpt,
resultKind: LookupResultKind.Viable,
+ binderOpt: this,
type: constructorReturnType,
hasErrors: hasErrors)
{ WasCompilerGenerated = initializerArgumentListOpt == null };
@@ -4526,6 +4527,7 @@ protected BoundExpression BindClassCreationExpression(
memberResolutionResult.Result.ArgsToParamsOpt,
constantValueOpt,
boundInitializerOpt,
+ this,
type,
hasError);
@@ -4665,7 +4667,7 @@ private BoundExpression BindComImportCoClassCreationExpression(ObjectCreationExp
var creation = (BoundObjectCreationExpression)classCreation;
return creation.Update(creation.Constructor, creation.ConstructorsGroup, creation.Arguments, creation.ArgumentNamesOpt,
creation.ArgumentRefKindsOpt, creation.Expanded, creation.ArgsToParamsOpt, creation.ConstantValueOpt,
- creation.InitializerExpressionOpt, interfaceType);
+ creation.InitializerExpressionOpt, creation.BinderOpt, interfaceType);
case BoundKind.BadExpression:
var bad = (BoundBadExpression)classCreation;
@@ -6829,6 +6831,8 @@ private BoundExpression BindIndexerOrIndexedPropertyAccess(
argumentRefKinds,
isExpanded,
argsToParams,
+ this,
+ false,
property.Type,
gotError);
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
index 01444f1e0d683..19d872a4142fd 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
@@ -982,7 +982,7 @@ private BoundCall BindInvocationExpressionContinued(
{
return new BoundCall(node, receiver, method, args, argNames, argRefKinds, isDelegateCall: true,
expanded: expanded, invokedAsExtensionMethod: invokedAsExtensionMethod,
- argsToParamsOpt: argsToParams, resultKind: LookupResultKind.Viable, type: returnType, hasErrors: gotError);
+ argsToParamsOpt: argsToParams, resultKind: LookupResultKind.Viable, binderOpt: this, type: returnType, hasErrors: gotError);
}
else
{
@@ -1003,7 +1003,7 @@ private BoundCall BindInvocationExpressionContinued(
return new BoundCall(node, receiver, method, args, argNames, argRefKinds, isDelegateCall: false,
expanded: expanded, invokedAsExtensionMethod: invokedAsExtensionMethod,
- argsToParamsOpt: argsToParams, resultKind: LookupResultKind.Viable, type: returnType, hasErrors: gotError);
+ argsToParamsOpt: argsToParams, resultKind: LookupResultKind.Viable, binderOpt: this, type: returnType, hasErrors: gotError);
}
}
@@ -1124,7 +1124,7 @@ private BoundCall CreateBadCall(
args = BuildArgumentsForErrorRecovery(analyzedArguments, methods);
var argNames = analyzedArguments.GetNames();
var argRefKinds = analyzedArguments.RefKinds.ToImmutableOrNull();
- return BoundCall.ErrorCall(node, receiver, method, args, argNames, argRefKinds, isDelegate, invokedAsExtensionMethod: invokedAsExtensionMethod, originalMethods: methods, resultKind: resultKind);
+ return BoundCall.ErrorCall(node, receiver, method, args, argNames, argRefKinds, isDelegate, invokedAsExtensionMethod: invokedAsExtensionMethod, originalMethods: methods, resultKind: resultKind, binder: this);
}
private static bool IsUnboundGeneric(MethodSymbol method)
@@ -1330,7 +1330,7 @@ private BoundCall CreateBadCall(
var argRefKinds = analyzedArguments.RefKinds.ToImmutableOrNull();
var originalMethods = (expr.Kind == BoundKind.MethodGroup) ? ((BoundMethodGroup)expr).Methods : ImmutableArray.Empty;
- return BoundCall.ErrorCall(node, expr, method, args, argNames, argRefKinds, isDelegateCall: false, invokedAsExtensionMethod: false, originalMethods: originalMethods, resultKind: resultKind);
+ return BoundCall.ErrorCall(node, expr, method, args, argNames, argRefKinds, isDelegateCall: false, invokedAsExtensionMethod: false, originalMethods: originalMethods, resultKind: resultKind, binder: this);
}
private static TypeSymbol GetCommonTypeOrReturnType(ImmutableArray members)
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs
index 7a540dfa613b3..6267ce3077e6e 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs
@@ -224,7 +224,7 @@ private static BoundCall ReverseLastTwoParameterOrder(BoundCall result)
return result.Update(
result.ReceiverOpt, result.Method, arguments.ToImmutableAndFree(), default(ImmutableArray),
default(ImmutableArray), result.IsDelegateCall, result.Expanded, result.InvokedAsExtensionMethod,
- argsToParams.ToImmutableAndFree(), result.ResultKind, result.Type);
+ argsToParams.ToImmutableAndFree(), result.ResultKind, result.BinderOpt, result.Type);
}
private void ReduceQuery(QueryTranslationState state, DiagnosticBag diagnostics)
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
index af58cb970d4e1..9668fc0da4d63 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
@@ -1153,8 +1153,6 @@ static private ErrorCode GetThisLvalueError(BindValueKind kind)
return ErrorCode.ERR_AddrOnReadOnlyLocal;
case BindValueKind.IncrementDecrement:
return ErrorCode.ERR_IncrementLvalueExpected;
- case BindValueKind.RefReturn:
- return ErrorCode.ERR_RefReturnStructThis;
}
}
@@ -1578,9 +1576,15 @@ private bool CheckIsVariable(SyntaxNode node, BoundExpression expr, BindValueKin
var thisref = expr as BoundThisReference;
if (thisref != null)
{
+ if (kind == BindValueKind.RefReturn)
+ {
+ Error(diagnostics, thisref.Type.IsValueType ? ErrorCode.ERR_RefReturnStructThis : ErrorCode.ERR_RefReadonlyLocal, node, ThisParameterSymbol.SymbolName);
+ return false;
+ }
+
// We will already have given an error for "this" used outside of a constructor,
// instance method, or instance accessor. Assume that "this" is a variable if it is in a struct.
- if (!thisref.Type.IsValueType || kind == BindValueKind.RefReturn)
+ if (!thisref.Type.IsValueType)
{
// CONSIDER: the Dev10 name has angle brackets (i.e. "")
Error(diagnostics, GetThisLvalueError(kind), node, ThisParameterSymbol.SymbolName);
@@ -1744,7 +1748,7 @@ private BoundExpression InferTypeForDiscardAssignment(BoundDiscardExpression op1
}
private BoundAssignmentOperator BindAssignment(SyntaxNode node, BoundExpression op1, BoundExpression op2, DiagnosticBag diagnostics)
- {
+ {
Debug.Assert(op1 != null);
Debug.Assert(op2 != null);
@@ -1773,7 +1777,7 @@ private BoundAssignmentOperator BindAssignment(SyntaxNode node, BoundExpression
{
// Event assignment is a call to void WindowsRuntimeMarshal.AddEventHandler().
type = this.GetSpecialType(SpecialType.System_Void, diagnostics, node);
- }
+ }
else
{
type = op1.Type;
@@ -1933,6 +1937,25 @@ private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind
GetNonMethodMemberType(otherSymbol));
}
}
+ else if (expr.Kind == BoundKind.IndexerAccess)
+ {
+ // Assigning to an non ref return indexer needs to set 'useSetterForDefaultArgumentGeneration' to true.
+ // This is for IOperation purpose.
+ var indexerAccess = (BoundIndexerAccess)expr;
+ if (valueKind == BindValueKind.Assignment && !indexerAccess.Indexer.ReturnsByRef)
+ {
+ expr = indexerAccess.Update(indexerAccess.ReceiverOpt,
+ indexerAccess.Indexer,
+ indexerAccess.Arguments,
+ indexerAccess.ArgumentNamesOpt,
+ indexerAccess.ArgumentRefKindsOpt,
+ indexerAccess.Expanded,
+ indexerAccess.ArgsToParamsOpt,
+ indexerAccess.BinderOpt,
+ useSetterForDefaultArgumentGeneration: true,
+ type: indexerAccess.Type);
+ }
+ }
if (!hasResolutionErrors && CheckValueKind(expr, valueKind, diagnostics) ||
expr.HasAnyErrors && valueKind == BindValueKind.RValueOrMethodGroup)
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
index d02e32d22e28e..2cc61856e9e13 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
@@ -2060,12 +2060,12 @@ private AssemblySymbol GetForwardedToAssembly(string fullName, int arity, Diagno
return null;
}
- internal static void CheckFeatureAvailability(SyntaxNode syntax, MessageID feature, DiagnosticBag diagnostics, Location locationOpt = null)
+ internal static bool CheckFeatureAvailability(SyntaxNode syntax, MessageID feature, DiagnosticBag diagnostics, Location locationOpt = null)
{
var options = (CSharpParseOptions)syntax.SyntaxTree.Options;
if (options.IsFeatureEnabled(feature))
{
- return;
+ return true;
}
var location = locationOpt ?? syntax.GetLocation();
@@ -2073,7 +2073,7 @@ internal static void CheckFeatureAvailability(SyntaxNode syntax, MessageID featu
if (requiredFeature != null)
{
diagnostics.Add(ErrorCode.ERR_FeatureIsExperimental, location, feature.Localize(), requiredFeature);
- return;
+ return false;
}
LanguageVersion availableVersion = options.LanguageVersion;
@@ -2081,7 +2081,10 @@ internal static void CheckFeatureAvailability(SyntaxNode syntax, MessageID featu
if (requiredVersion > availableVersion)
{
diagnostics.Add(availableVersion.GetErrorCode(), location, feature.Localize(), new CSharpRequiredLanguageVersion(requiredVersion));
+ return false;
}
+
+ return true;
}
}
}
\ No newline at end of file
diff --git a/src/Compilers/CSharp/Portable/Binder/PatternSwitchBinder.cs b/src/Compilers/CSharp/Portable/Binder/PatternSwitchBinder.cs
index aa86e537ce024..b5551b2f52be0 100644
--- a/src/Compilers/CSharp/Portable/Binder/PatternSwitchBinder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/PatternSwitchBinder.cs
@@ -64,7 +64,7 @@ internal override BoundStatement BindSwitchExpressionAndSections(SwitchStatement
BoundPatternSwitchLabel defaultLabel;
bool isComplete;
ImmutableArray switchSections =
- BindPatternSwitchSections(boundSwitchExpression, node.Sections, originalBinder, out defaultLabel, out isComplete, diagnostics);
+ BindPatternSwitchSections(originalBinder, out defaultLabel, out isComplete, diagnostics);
var locals = GetDeclaredLocalsForScope(node);
var functions = GetDeclaredLocalFunctionsForScope(node);
return new BoundPatternSwitchStatement(
@@ -101,8 +101,6 @@ internal override void BindPatternSwitchLabelForInference(CasePatternSwitchLabel
/// the decision tree.
///
private ImmutableArray BindPatternSwitchSections(
- BoundExpression boundSwitchExpression,
- SyntaxList sections,
Binder originalBinder,
out BoundPatternSwitchLabel defaultLabel,
out bool isComplete,
@@ -115,11 +113,11 @@ private ImmutableArray BindPatternSwitchSections(
// Bind match sections
var boundPatternSwitchSectionsBuilder = ArrayBuilder.GetInstance();
- SubsumptionDiagnosticBuilder subsumption = new SubsumptionDiagnosticBuilder(ContainingMemberOrLambda, this.Conversions, boundSwitchExpression);
- foreach (var sectionSyntax in sections)
+ SubsumptionDiagnosticBuilder subsumption = new SubsumptionDiagnosticBuilder(ContainingMemberOrLambda, SwitchSyntax, this.Conversions, SwitchGoverningExpression);
+ foreach (var sectionSyntax in SwitchSyntax.Sections)
{
boundPatternSwitchSectionsBuilder.Add(BindPatternSwitchSection(
- boundSwitchExpression, sectionSyntax, originalBinder, ref defaultLabel, ref someValueMatched, subsumption, diagnostics));
+ SwitchGoverningExpression, sectionSyntax, originalBinder, ref defaultLabel, ref someValueMatched, subsumption, diagnostics));
}
isComplete = defaultLabel != null || subsumption.IsComplete || someValueMatched;
diff --git a/src/Compilers/CSharp/Portable/Binder/SubsumptionDiagnosticBuilder.cs b/src/Compilers/CSharp/Portable/Binder/SubsumptionDiagnosticBuilder.cs
index f1695a0bda40c..4496196c67e24 100644
--- a/src/Compilers/CSharp/Portable/Binder/SubsumptionDiagnosticBuilder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/SubsumptionDiagnosticBuilder.cs
@@ -20,11 +20,12 @@ internal class SubsumptionDiagnosticBuilder : DecisionTreeBuilder
private readonly DecisionTree _subsumptionTree;
internal SubsumptionDiagnosticBuilder(Symbol enclosingSymbol,
- Conversions conversions,
- BoundExpression expression)
- : base(enclosingSymbol, conversions)
+ SyntaxNode syntax,
+ Conversions conversions,
+ BoundExpression expression)
+ : base(enclosingSymbol, syntax, conversions)
{
- _subsumptionTree = DecisionTree.Create(expression, expression.Type, enclosingSymbol);
+ _subsumptionTree = CreateEmptyDecisionTree(expression);
}
///
diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs
index f02545f32360b..0101123611edc 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs
@@ -424,6 +424,7 @@ internal BoundObjectCreationExpression UpdateArgumentsAndInitializer(
argsToParamsOpt: default(ImmutableArray),
constantValueOpt: ConstantValueOpt,
initializerExpressionOpt: newInitializerExpression,
+ binderOpt: BinderOpt,
type: changeTypeOpt ?? Type);
}
}
diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
index e4962d7696bee..fca8f89687e1d 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
+++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
@@ -1201,6 +1201,9 @@
+
+
+
@@ -1246,6 +1249,9 @@
+
+
+
@@ -1491,6 +1497,10 @@
+
+
+
+
diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundObjectCreationExpression.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundObjectCreationExpression.cs
index 98b6b588d0232..082c447e850f8 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/BoundObjectCreationExpression.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/BoundObjectCreationExpression.cs
@@ -7,13 +7,13 @@ namespace Microsoft.CodeAnalysis.CSharp
{
internal partial class BoundObjectCreationExpression
{
- public BoundObjectCreationExpression(SyntaxNode syntax, MethodSymbol constructor, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool expanded, ImmutableArray argsToParamsOpt, ConstantValue constantValueOpt, BoundExpression initializerExpressionOpt, TypeSymbol type, bool hasErrors = false)
- : this(syntax, constructor, ImmutableArray.Empty, arguments, argumentNamesOpt, argumentRefKindsOpt, expanded, argsToParamsOpt, constantValueOpt, initializerExpressionOpt, type, hasErrors)
+ public BoundObjectCreationExpression(SyntaxNode syntax, MethodSymbol constructor, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool expanded, ImmutableArray argsToParamsOpt, ConstantValue constantValueOpt, BoundExpression initializerExpressionOpt, Binder binderOpt, TypeSymbol type, bool hasErrors = false)
+ : this(syntax, constructor, ImmutableArray.Empty, arguments, argumentNamesOpt, argumentRefKindsOpt, expanded, argsToParamsOpt, constantValueOpt, initializerExpressionOpt, binderOpt, type, hasErrors)
{ }
- public BoundObjectCreationExpression Update(MethodSymbol constructor, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool expanded, ImmutableArray argsToParamsOpt, ConstantValue constantValueOpt, BoundExpression initializerExpressionOpt, TypeSymbol type)
+ public BoundObjectCreationExpression Update(MethodSymbol constructor, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool expanded, ImmutableArray argsToParamsOpt, ConstantValue constantValueOpt, BoundExpression initializerExpressionOpt, Binder binderOpt, TypeSymbol type)
{
- return this.Update(constructor, ImmutableArray.Empty, arguments, argumentNamesOpt, argumentRefKindsOpt, expanded, argsToParamsOpt, constantValueOpt, initializerExpressionOpt, type);
+ return this.Update(constructor, ImmutableArray.Empty, arguments, argumentNamesOpt, argumentRefKindsOpt, expanded, argsToParamsOpt, constantValueOpt, initializerExpressionOpt, binderOpt, type);
}
}
}
diff --git a/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs b/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs
index 6f7d940def080..a200b5636c2cd 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs
@@ -75,7 +75,8 @@ public static BoundCall ErrorCall(
bool isDelegateCall,
bool invokedAsExtensionMethod,
ImmutableArray originalMethods,
- LookupResultKind resultKind)
+ LookupResultKind resultKind,
+ Binder binder)
{
if (!originalMethods.IsEmpty)
resultKind = resultKind.WorseResultKind(LookupResultKind.OverloadResolutionFailure);
@@ -84,14 +85,14 @@ public static BoundCall ErrorCall(
var call = new BoundCall(node, receiverOpt, method, arguments, namedArguments,
refKinds, isDelegateCall: isDelegateCall, expanded: false, invokedAsExtensionMethod: invokedAsExtensionMethod, argsToParamsOpt: default(ImmutableArray),
- resultKind: resultKind, type: method.ReturnType, hasErrors: true);
+ resultKind: resultKind, binderOpt: binder, type: method.ReturnType, hasErrors: true);
call.OriginalMethodsOpt = originalMethods;
return call;
}
public BoundCall Update(BoundExpression receiverOpt, MethodSymbol method, ImmutableArray arguments)
{
- return this.Update(receiverOpt, method, arguments, ArgumentNamesOpt, ArgumentRefKindsOpt, IsDelegateCall, Expanded, InvokedAsExtensionMethod, ArgsToParamsOpt, ResultKind, Type);
+ return this.Update(receiverOpt, method, arguments, ArgumentNamesOpt, ArgumentRefKindsOpt, IsDelegateCall, Expanded, InvokedAsExtensionMethod, ArgsToParamsOpt, ResultKind, BinderOpt, Type);
}
public static BoundCall Synthesized(SyntaxNode syntax, BoundExpression receiverOpt, MethodSymbol method)
@@ -122,6 +123,7 @@ public static BoundCall Synthesized(SyntaxNode syntax, BoundExpression receiverO
invokedAsExtensionMethod: false,
argsToParamsOpt: default(ImmutableArray),
resultKind: LookupResultKind.Viable,
+ binderOpt: null,
type: method.ReturnType,
hasErrors: method.OriginalDefinition is ErrorMethodSymbol
)
@@ -131,12 +133,12 @@ public static BoundCall Synthesized(SyntaxNode syntax, BoundExpression receiverO
internal sealed partial class BoundObjectCreationExpression
{
- public BoundObjectCreationExpression(SyntaxNode syntax, MethodSymbol constructor, params BoundExpression[] arguments)
- : this(syntax, constructor, ImmutableArray.Create(arguments), default(ImmutableArray), default(ImmutableArray), false, default(ImmutableArray), null, null, constructor.ContainingType)
+ public BoundObjectCreationExpression(SyntaxNode syntax, MethodSymbol constructor, Binder binderOpt, params BoundExpression[] arguments)
+ : this(syntax, constructor, ImmutableArray.Create(arguments), default(ImmutableArray), default(ImmutableArray), false, default(ImmutableArray), null, null, binderOpt, constructor.ContainingType)
{
}
- public BoundObjectCreationExpression(SyntaxNode syntax, MethodSymbol constructor, ImmutableArray arguments)
- : this(syntax, constructor, arguments, default(ImmutableArray), default(ImmutableArray), false, default(ImmutableArray), null, null, constructor.ContainingType)
+ public BoundObjectCreationExpression(SyntaxNode syntax, MethodSymbol constructor, Binder binderOpt, ImmutableArray arguments)
+ : this(syntax, constructor, arguments, default(ImmutableArray), default(ImmutableArray), false, default(ImmutableArray), null, null, binderOpt, constructor.ContainingType)
{
}
}
@@ -161,6 +163,8 @@ public static BoundIndexerAccess ErrorAccess(
refKinds,
expanded: false,
argsToParamsOpt: default(ImmutableArray),
+ binderOpt: null,
+ useSetterForDefaultArgumentGeneration: false,
type: indexer.Type,
hasErrors: true)
{
diff --git a/src/Compilers/CSharp/Portable/BoundTree/DecisionTree.cs b/src/Compilers/CSharp/Portable/BoundTree/DecisionTree.cs
index e030bc16cb558..c6d95ca94f611 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/DecisionTree.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/DecisionTree.cs
@@ -78,36 +78,6 @@ public DecisionTree(BoundExpression expression, TypeSymbol type, LocalSymbol tem
Debug.Assert(this.Type != null);
}
- ///
- /// Create a fresh decision tree for the given input expression of the given type.
- ///
- public static DecisionTree Create(BoundExpression expression, TypeSymbol type, Symbol enclosingSymbol)
- {
- Debug.Assert(expression.Type == type);
- LocalSymbol temp = null;
- if (expression.ConstantValue == null)
- {
- // Unless it is a constant, the decision tree acts on a copy of the input expression.
- // We create a temp to represent that copy. Lowering will assign into this temp.
- temp = new SynthesizedLocal(enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatching, expression.Syntax, false, RefKind.None);
- expression = new BoundLocal(expression.Syntax, temp, null, type);
- }
-
- if (type.CanContainNull() || type.SpecialType == SpecialType.None)
- {
- // We need the ByType decision tree to separate null from non-null values.
- // Note that, for the purpose of the decision tree (and subsumption), we
- // ignore the fact that the input may be a constant, and therefore always
- // or never null.
- return new ByType(expression, type, temp);
- }
- else
- {
- // If it is a (e.g. builtin) value type, we can switch on its (constant) values.
- return new ByValue(expression, type, temp);
- }
- }
-
///
/// A decision tree node that branches based on (1) whether the input value is null, (2) the runtime
/// type of the input expression, and finally (3) a default decision tree if nothing in the previous
diff --git a/src/Compilers/CSharp/Portable/BoundTree/DecisionTreeBuilder.cs b/src/Compilers/CSharp/Portable/BoundTree/DecisionTreeBuilder.cs
index 6e72bb9566008..703dffcf48a03 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/DecisionTreeBuilder.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/DecisionTreeBuilder.cs
@@ -26,17 +26,63 @@ internal abstract class DecisionTreeBuilder
protected readonly Symbol _enclosingSymbol;
protected readonly Conversions _conversions;
protected HashSet _useSiteDiagnostics = new HashSet();
+ private Dictionary localByType = new Dictionary();
protected DecisionTreeBuilder(
Symbol enclosingSymbol,
+ SyntaxNode syntax,
Conversions conversions)
{
this._enclosingSymbol = enclosingSymbol;
+ this.Syntax = syntax;
this._conversions = conversions;
}
protected SyntaxNode Syntax { private get; set; }
+ private LocalSymbol PatternMatchingTemp(TypeSymbol type)
+ {
+ LocalSymbol temp;
+ if (!localByType.TryGetValue(type, out temp))
+ {
+ temp = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatching, Syntax);
+ localByType.Add(type, temp);
+ }
+
+ return temp;
+ }
+
+ ///
+ /// Create a fresh decision tree for the given input expression of the given type.
+ ///
+ protected DecisionTree CreateEmptyDecisionTree(BoundExpression expression)
+ {
+ var type = expression.Type;
+
+ LocalSymbol temp = null;
+ if (expression.ConstantValue == null)
+ {
+ // Unless it is a constant, the decision tree acts on a copy of the input expression.
+ // We create a temp to represent that copy. Lowering will assign into this temp.
+ temp = PatternMatchingTemp(type);
+ expression = new BoundLocal(expression.Syntax, temp, null, type);
+ }
+
+ if (type.CanContainNull() || type.SpecialType == SpecialType.None)
+ {
+ // We need the ByType decision tree to separate null from non-null values.
+ // Note that, for the purpose of the decision tree (and subsumption), we
+ // ignore the fact that the input may be a constant, and therefore always
+ // or never null.
+ return new DecisionTree.ByType(expression, type, temp);
+ }
+ else
+ {
+ // If it is a (e.g. builtin) value type, we can switch on its (constant) values.
+ return new DecisionTree.ByValue(expression, type, temp);
+ }
+ }
+
protected DecisionTree AddToDecisionTree(DecisionTree decisionTree, SyntaxNode sectionSyntax, BoundPatternSwitchLabel label)
{
var pattern = label.Pattern;
@@ -237,7 +283,7 @@ private DecisionTree AddByValue(DecisionTree.ByType byType, BoundConstantPattern
if (forType == null)
{
var type = value.Value.Type;
- var localSymbol = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatching, Syntax, false, RefKind.None);
+ var localSymbol = PatternMatchingTemp(type);
var narrowedExpression = new BoundLocal(Syntax, localSymbol, null, type);
forType = new DecisionTree.ByValue(narrowedExpression, value.Value.Type.TupleUnderlyingTypeOrSelf(), localSymbol);
byType.TypeAndDecision.Add(new KeyValuePair(value.Value.Type, forType));
@@ -338,7 +384,7 @@ private DecisionTree AddByType(DecisionTree.ByType byType, TypeSymbol type, Deci
if (result == null)
{
- var localSymbol = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatching, Syntax, false, RefKind.None);
+ var localSymbol = PatternMatchingTemp(type);
var expression = new BoundLocal(Syntax, localSymbol, null, type);
result = makeDecision(expression, type);
Debug.Assert(result.Temp == null);
diff --git a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs
index 605ada05830fa..7283f4640b5ab 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Runtime.CompilerServices;
@@ -59,7 +60,7 @@ internal partial class BoundCall : IInvocationExpression
!this.ReceiverOpt.SuppressVirtualCalls;
ImmutableArray IHasArgumentsExpression.ArgumentsInEvaluationOrder
- => DeriveArguments(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Method.Parameters, this.Syntax);
+ => DeriveArguments(this, this.BinderOpt, this.Method, this.Method, this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Method.Parameters, this.Expanded, this.Syntax, this.InvokedAsExtensionMethod);
protected override OperationKind ExpressionKind => OperationKind.InvocationExpression;
@@ -73,219 +74,69 @@ public override TResult Accept(OperationVisitor DeriveArguments(ImmutableArray boundArguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentsToParametersOpt, ImmutableArray argumentRefKindsOpt, ImmutableArray parameters, SyntaxNode invocationSyntax)
- {
- ArrayBuilder arguments = ArrayBuilder.GetInstance(boundArguments.Length);
- for (int parameterIndex = 0; parameterIndex < parameters.Length; parameterIndex++)
- {
- int argumentIndex = -1;
- if (argumentsToParametersOpt.IsDefault)
- {
- argumentIndex = parameterIndex;
- }
- else
- {
- argumentIndex = argumentsToParametersOpt.IndexOf(parameterIndex);
- }
-
- if ((uint)argumentIndex >= (uint)boundArguments.Length)
- {
- // No argument has been supplied for the parameter at `parameterIndex`:
- // 1. `argumentIndex == -1' when the arguments are specified out of parameter order, and no argument is provided for parameter corresponding to `parameters[parameterIndex]`.
- // 2. `argumentIndex >= boundArguments.Length` when the arguments are specified in parameter order, and no argument is provided at `parameterIndex`.
-
- Symbols.ParameterSymbol parameter = parameters[parameterIndex];
- if (parameter.HasExplicitDefaultValue)
- {
- // The parameter is optional with a default value.
- arguments.Add(new Argument(ArgumentKind.DefaultValue, parameter, new LiteralExpression(parameter.ExplicitDefaultConstantValue, parameter.Type, invocationSyntax)));
- }
- else
- {
- // If the invocation is semantically valid, the parameter will be a params array and an empty array will be provided.
- // If the argument is otherwise omitted for a parameter with no default value, the invocation is not valid and a null argument will be provided.
- arguments.Add(DeriveArgument(parameterIndex, boundArguments.Length, boundArguments, argumentNamesOpt, argumentRefKindsOpt, parameters, invocationSyntax));
- }
- }
- else
- {
- arguments.Add(DeriveArgument(parameterIndex, argumentIndex, boundArguments, argumentNamesOpt, argumentRefKindsOpt, parameters, invocationSyntax));
- }
- }
-
- return arguments.ToImmutableAndFree();
- }
-
- private static readonly ConditionalWeakTable s_argumentMappings = new ConditionalWeakTable();
-
- private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, ImmutableArray boundArguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, ImmutableArray parameters, SyntaxNode invocationSyntax)
- {
- if ((uint)argumentIndex >= (uint)boundArguments.Length)
+ private static readonly ConditionalWeakTable> s_callToArgumentsMappings
+ = new ConditionalWeakTable>();
+
+ internal static IArgument CreateArgumentOperation(ArgumentKind kind, IParameterSymbol parameter, IOperation value)
+ {
+ return new Argument(kind,
+ parameter,
+ value,
+ inConversion: null,
+ outConversion: null,
+ isInvalid: parameter == null || value.IsInvalid,
+ syntax: value.Syntax,
+ type: value.Type,
+ constantValue: default(Optional
public new CSharpCompilation WithAssemblyName(string assemblyName)
{
- // Can't reuse references since the source assembly name changed and the referenced symbols might
- // have internals-visible-to relationship with this compilation or they might had a circular reference
+ // Can't reuse references since the source assembly name changed and the referenced symbols might
+ // have internals-visible-to relationship with this compilation or they might had a circular reference
// to this compilation.
return new CSharpCompilation(
@@ -429,9 +430,9 @@ private CSharpCompilation Update(
/// Creates a new compilation with the specified references.
///
///
- /// The new will query the given for the underlying
- /// metadata as soon as the are needed.
- ///
+ /// The new will query the given for the underlying
+ /// metadata as soon as the are needed.
+ ///
/// The new compilation uses whatever metadata is currently being provided by the .
/// E.g. if the current compilation references a metadata file that has changed since the creation of the compilation
/// the new compilation is going to use the updated version, while the current compilation will be using the previous (it doesn't change).
@@ -684,7 +685,7 @@ internal override bool HasSubmissionResult()
///
/// Creates a new compilation without the specified syntax trees. Preserves metadata info for use with trees
- /// added later.
+ /// added later.
///
public new CSharpCompilation RemoveSyntaxTrees(params SyntaxTree[] trees)
{
@@ -693,7 +694,7 @@ internal override bool HasSubmissionResult()
///
/// Creates a new compilation without the specified syntax trees. Preserves metadata info for use with trees
- /// added later.
+ /// added later.
///
public new CSharpCompilation RemoveSyntaxTrees(IEnumerable trees)
{
@@ -746,7 +747,7 @@ internal override bool HasSubmissionResult()
///
/// Creates a new compilation without any syntax trees. Preserves metadata info
- /// from this compilation for use with trees added later.
+ /// from this compilation for use with trees added later.
///
public new CSharpCompilation RemoveAllSyntaxTrees()
{
@@ -805,7 +806,7 @@ internal override bool HasSubmissionResult()
}
// TODO(tomat): Consider comparing #r's of the old and the new tree. If they are exactly the same we could still reuse.
- // This could be a perf win when editing a script file in the IDE. The services create a new compilation every keystroke
+ // This could be a perf win when editing a script file in the IDE. The services create a new compilation every keystroke
// that replaces the tree with a new one.
var reuseReferenceManager = !oldTree.HasReferenceOrLoadDirectives() && !newTree.HasReferenceOrLoadDirectives();
syntaxAndDeclarations = syntaxAndDeclarations.ReplaceSyntaxTree(oldTree, newTree);
@@ -872,7 +873,7 @@ internal IEnumerable ExternAliases
///
/// or corresponding to the given reference or null if there is none.
///
- /// Uses object identity when comparing two references.
+ /// Uses object identity when comparing two references.
///
internal new Symbol GetAssemblyOrModuleSymbol(MetadataReference reference)
{
@@ -976,7 +977,7 @@ public MetadataReference GetDirectiveReference(ReferenceDirectiveTriviaSyntax di
///
/// Get all modules in this compilation, including the source module, added modules, and all
/// modules of referenced assemblies that do not come from an assembly with an extern alias.
- /// Metadata imported from aliased assemblies is not visible at the source level except through
+ /// Metadata imported from aliased assemblies is not visible at the source level except through
/// the use of an extern alias directive. So exclude them from this list which is used to construct
/// the global namespace.
///
@@ -1017,7 +1018,7 @@ internal void GetUnaliasedReferencedAssemblies(ArrayBuilder asse
}
///
- /// Gets the that corresponds to the assembly symbol.
+ /// Gets the that corresponds to the assembly symbol.
///
public new MetadataReference GetMetadataReference(IAssemblySymbol assemblySymbol)
{
@@ -1065,7 +1066,7 @@ internal SourceAssemblySymbol SourceAssembly
}
///
- /// Gets the root namespace that contains all namespaces and types defined in source code or in
+ /// Gets the root namespace that contains all namespaces and types defined in source code or in
/// referenced metadata, merged into a single namespace hierarchy.
///
internal new NamespaceSymbol GlobalNamespace
@@ -1075,7 +1076,7 @@ internal SourceAssemblySymbol SourceAssembly
if ((object)_lazyGlobalNamespace == null)
{
// Get the root namespace from each module, and merge them all together
- // Get all modules in this compilation, ones referenced directly by the compilation
+ // Get all modules in this compilation, ones referenced directly by the compilation
// as well as those referenced by all referenced assemblies.
var modules = ArrayBuilder.GetInstance();
@@ -1369,7 +1370,7 @@ internal bool DeclaresTheObjectClass
internal new MethodSymbol GetEntryPoint(CancellationToken cancellationToken)
{
EntryPoint entryPoint = GetEntryPointAndDiagnostics(cancellationToken);
- return entryPoint == null ? null : entryPoint.MethodSymbol;
+ return entryPoint?.MethodSymbol;
}
internal EntryPoint GetEntryPointAndDiagnostics(CancellationToken cancellationToken)
@@ -1452,38 +1453,100 @@ private MethodSymbol FindEntryPoint(CancellationToken cancellationToken, out Imm
}
}
- DiagnosticBag warnings = DiagnosticBag.GetInstance();
- var viableEntryPoints = ArrayBuilder.GetInstance();
- foreach (var candidate in entryPointCandidates)
+ // Validity and diagnostics are also tracked because they must be conditionally handled
+ // if there are not any "traditional" entrypoints found.
+ var taskEntryPoints = ArrayBuilder<(bool IsValid, MethodSymbol Candidate, DiagnosticBag SpecificDiagnostics)>.GetInstance();
+
+ // These diagnostics (warning only) are added to the compilation only if
+ // there were not any main methods found.
+ DiagnosticBag noMainFoundDiagnostics = DiagnosticBag.GetInstance();
+
+ bool CheckValid(MethodSymbol candidate, bool isCandidate, DiagnosticBag specificDiagnostics)
{
- if (!candidate.HasEntryPointSignature())
+ if (!isCandidate)
{
- // a single error for partial methods:
- warnings.Add(ErrorCode.WRN_InvalidMainSig, candidate.Locations.First(), candidate);
- continue;
+ noMainFoundDiagnostics.Add(ErrorCode.WRN_InvalidMainSig, candidate.Locations.First(), candidate);
+ noMainFoundDiagnostics.AddRange(specificDiagnostics);
+ return false;
}
if (candidate.IsGenericMethod || candidate.ContainingType.IsGenericType)
{
// a single error for partial methods:
- warnings.Add(ErrorCode.WRN_MainCantBeGeneric, candidate.Locations.First(), candidate);
- continue;
+ noMainFoundDiagnostics.Add(ErrorCode.WRN_MainCantBeGeneric, candidate.Locations.First(), candidate);
+ return false;
}
+ return true;
+ }
- if (candidate.IsAsync)
+ var viableEntryPoints = ArrayBuilder.GetInstance();
+
+ foreach (var candidate in entryPointCandidates)
+ {
+ var perCandidateBag = DiagnosticBag.GetInstance();
+ var (IsCandidate, IsTaskLike) = HasEntryPointSignature(candidate, perCandidateBag);
+
+ if (IsTaskLike)
+ {
+ taskEntryPoints.Add((IsCandidate, candidate, perCandidateBag));
+ }
+ else
{
- diagnostics.Add(ErrorCode.ERR_MainCantBeAsync, candidate.Locations.First(), candidate);
+ if (CheckValid(candidate, IsCandidate, perCandidateBag))
+ {
+ if (candidate.IsAsync)
+ {
+ diagnostics.Add(ErrorCode.ERR_NonTaskMainCantBeAsync, candidate.Locations.First(), candidate);
+ }
+ else
+ {
+ diagnostics.AddRange(perCandidateBag);
+ viableEntryPoints.Add(candidate);
+ }
+ }
+ perCandidateBag.Free();
}
+ }
- viableEntryPoints.Add(candidate);
+ if (viableEntryPoints.Count == 0)
+ {
+ foreach (var (IsValid, Candidate, SpecificDiagnostics) in taskEntryPoints)
+ {
+ if (CheckValid(Candidate, IsValid, SpecificDiagnostics) &&
+ CheckFeatureAvailability(Candidate.ExtractReturnTypeSyntax(), MessageID.IDS_FeatureAsyncMain, diagnostics))
+ {
+ diagnostics.AddRange(SpecificDiagnostics);
+ viableEntryPoints.Add(Candidate);
+ }
+ }
}
- if ((object)mainType == null || viableEntryPoints.Count == 0)
+ foreach (var (_, _, SpecificDiagnostics) in taskEntryPoints)
{
- diagnostics.AddRange(warnings);
+ SpecificDiagnostics.Free();
}
- warnings.Free();
+ if (viableEntryPoints.Count == 0)
+ {
+ diagnostics.AddRange(noMainFoundDiagnostics);
+ }
+ else if ((object)mainType == null)
+ {
+ // Filters out diagnostics so that only InvalidMainSig and MainCant'BeGeneric are left.
+ // The reason that Error diagnostics can end up in `noMainFoundDiagnostics` is when
+ // HasEntryPointSignature yields some Error Diagnostics when people implement Task or Task incorrectly.
+ //
+ // We can't add those Errors to the general diagnostics bag because it would break previously-working programs.
+ // The fact that these warnings are not added when csc is invoked with /main is possibly a bug, and is tracked at
+ // https://github.com/dotnet/roslyn/issues/18964
+ foreach (var diagnostic in noMainFoundDiagnostics.AsEnumerable())
+ {
+ if (diagnostic.Code == (int)ErrorCode.WRN_InvalidMainSig || diagnostic.Code == (int)ErrorCode.WRN_MainCantBeGeneric)
+ {
+ diagnostics.Add(diagnostic);
+ }
+ }
+ }
MethodSymbol entryPoint = null;
if (viableEntryPoints.Count == 0)
@@ -1513,7 +1576,9 @@ private MethodSymbol FindEntryPoint(CancellationToken cancellationToken, out Imm
entryPoint = viableEntryPoints[0];
}
+ taskEntryPoints.Free();
viableEntryPoints.Free();
+ noMainFoundDiagnostics.Free();
return entryPoint;
}
finally
@@ -1523,6 +1588,92 @@ private MethodSymbol FindEntryPoint(CancellationToken cancellationToken, out Imm
}
}
+ internal bool ReturnsAwaitableToVoidOrInt(MethodSymbol method, DiagnosticBag diagnostics)
+ {
+ // Common case optimization
+ if (method.ReturnType.SpecialType == SpecialType.System_Void || method.ReturnType.SpecialType == SpecialType.System_Int32)
+ {
+ return false;
+ }
+
+ if (!(method.ReturnType is NamedTypeSymbol namedType))
+ {
+ return false;
+ }
+
+ // Early bail so we only even check things that are System.Threading.Tasks.Task()
+ if (!(namedType.ConstructedFrom == GetWellKnownType(WellKnownType.System_Threading_Tasks_Task) ||
+ namedType.ConstructedFrom == GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T)))
+ {
+ return false;
+ }
+
+ var syntax = method.ExtractReturnTypeSyntax();
+ var dumbInstance = new BoundLiteral(syntax, ConstantValue.Null, method.ReturnType);
+ var binder = GetBinder(syntax);
+ BoundExpression result;
+ var success = binder.GetAwaitableExpressionInfo(dumbInstance, out _, out _, out _, out result, syntax, diagnostics);
+
+ return success &&
+ (result.Type.SpecialType == SpecialType.System_Void || result.Type.SpecialType == SpecialType.System_Int32);
+ }
+
+ ///
+ /// Checks if the method has an entry point compatible signature, i.e.
+ /// - the return type is either void, int, or returns a ,
+ /// or where the return type of GetAwaiter().GetResult()
+ /// is either void or int.
+ /// - has either no parameter or a single parameter of type string[]
+ ///
+ private (bool IsCandidate, bool IsTaskLike) HasEntryPointSignature(MethodSymbol method, DiagnosticBag bag)
+ {
+ if (method.IsVararg)
+ {
+ return (false, false);
+ }
+
+ TypeSymbol returnType = method.ReturnType;
+ bool returnsTaskOrTaskOfInt = false;
+ if (returnType.SpecialType != SpecialType.System_Int32 && returnType.SpecialType != SpecialType.System_Void)
+ {
+ // Never look for ReturnsAwaitableToVoidOrInt on int32 or void
+ returnsTaskOrTaskOfInt = ReturnsAwaitableToVoidOrInt(method, bag);
+ if (!returnsTaskOrTaskOfInt)
+ {
+ return (false, false);
+ }
+ }
+
+ if (method.RefKind != RefKind.None)
+ {
+ return (false, returnsTaskOrTaskOfInt);
+ }
+
+ if (method.Parameters.Length == 0)
+ {
+ return (true, returnsTaskOrTaskOfInt);
+ }
+
+ if (method.Parameters.Length > 1)
+ {
+ return (false, returnsTaskOrTaskOfInt);
+ }
+
+ if (!method.ParameterRefKinds.IsDefault)
+ {
+ return (false, returnsTaskOrTaskOfInt);
+ }
+
+ var firstType = method.Parameters[0].Type;
+ if (firstType.TypeKind != TypeKind.Array)
+ {
+ return (false, returnsTaskOrTaskOfInt);
+ }
+
+ var array = (ArrayTypeSymbol)firstType;
+ return (array.IsSZArray && array.ElementType.SpecialType == SpecialType.System_String, returnsTaskOrTaskOfInt);
+ }
+
internal override bool IsUnreferencedAssemblyIdentityDiagnosticCode(int code)
=> code == (int)ErrorCode.ERR_NoTypeDef;
@@ -2017,7 +2168,8 @@ private void GetDiagnosticsForAllMethodBodies(DiagnosticBag diagnostics, Cancell
MethodCompiler.CompileMethodBodies(
compilation: this,
moduleBeingBuiltOpt: null,
- generateDebugInfo: false,
+ emittingPdb: false,
+ emitTestCoverageData: false,
hasDeclarationErrors: false,
diagnostics: diagnostics,
filterOpt: null,
@@ -2059,7 +2211,8 @@ private ImmutableArray GetDiagnosticsForMethodBodiesInTree(SyntaxTre
MethodCompiler.CompileMethodBodies(
compilation: this,
moduleBeingBuiltOpt: null,
- generateDebugInfo: false,
+ emittingPdb: false,
+ emitTestCoverageData: false,
hasDeclarationErrors: false,
diagnostics: diagnostics,
filterOpt: s => IsDefinedOrImplementedInSourceTree(s, tree, span),
@@ -2171,8 +2324,8 @@ internal ImmutableArray GetDiagnosticsForSyntaxTree(
{
//remove some errors that don't have locations in the tree, like "no suitable main method."
//Members in trees other than the one being examined are not compiled. This includes field
- //initializers which can result in 'field is never initialized' warnings for fields in partial
- //types when the field is in a different source file than the one for which we're getting diagnostics.
+ //initializers which can result in 'field is never initialized' warnings for fields in partial
+ //types when the field is in a different source file than the one for which we're getting diagnostics.
//For that reason the bag must be also filtered by tree.
IEnumerable methodBodyDiagnostics = GetDiagnosticsForMethodBodiesInTree(syntaxTree, filterSpanWithinTree, cancellationToken);
@@ -2301,21 +2454,29 @@ internal override CommonPEModuleBuilder CreateModuleBuilder(
internal override bool CompileMethods(
CommonPEModuleBuilder moduleBuilder,
bool emittingPdb,
+ bool emitMetadataOnly,
+ bool emitTestCoverageData,
DiagnosticBag diagnostics,
Predicate filterOpt,
CancellationToken cancellationToken)
{
// The diagnostics should include syntax and declaration errors. We insert these before calling Emitter.Emit, so that the emitter
// does not attempt to emit if there are declaration errors (but we do insert all errors from method body binding...)
- bool hasDeclarationErrors = !FilterAndAppendDiagnostics(diagnostics, GetDiagnostics(CompilationStage.Declare, true, cancellationToken));
+ PooledHashSet excludeDiagnostics = null;
+ if (emitMetadataOnly)
+ {
+ excludeDiagnostics = PooledHashSet.GetInstance();
+ excludeDiagnostics.Add((int)ErrorCode.ERR_ConcreteMissingBody);
+ }
+ bool hasDeclarationErrors = !FilterAndAppendDiagnostics(diagnostics, GetDiagnostics(CompilationStage.Declare, true, cancellationToken), excludeDiagnostics);
+ excludeDiagnostics?.Free();
// TODO (tomat): NoPIA:
// EmbeddedSymbolManager.MarkAllDeferredSymbolsAsReferenced(this)
var moduleBeingBuilt = (PEModuleBuilder)moduleBuilder;
- var emitOptions = moduleBeingBuilt.EmitOptions;
- if (emitOptions.EmitMetadataOnly)
+ if (emitMetadataOnly)
{
if (hasDeclarationErrors)
{
@@ -2333,7 +2494,7 @@ internal override bool CompileMethods(
}
else
{
- if ((emittingPdb || emitOptions.EmitTestCoverageData) &&
+ if ((emittingPdb || emitTestCoverageData) &&
!CreateDebugDocuments(moduleBeingBuilt.DebugDocumentsBuilder, moduleBeingBuilt.EmbeddedTexts, diagnostics))
{
return false;
@@ -2349,6 +2510,7 @@ internal override bool CompileMethods(
this,
moduleBeingBuilt,
emittingPdb,
+ emitTestCoverageData,
hasDeclarationErrors,
diagnostics: methodBodyDiagnosticBag,
filterOpt: filterOpt,
@@ -2369,11 +2531,10 @@ internal override bool GenerateResourcesAndDocumentationComments(
CommonPEModuleBuilder moduleBuilder,
Stream xmlDocStream,
Stream win32Resources,
+ string outputNameOverride,
DiagnosticBag diagnostics,
CancellationToken cancellationToken)
{
- Debug.Assert(!moduleBuilder.EmitOptions.EmitMetadataOnly);
-
// Use a temporary bag so we don't have to refilter pre-existing diagnostics.
var resourceDiagnostics = DiagnosticBag.GetInstance();
@@ -2395,7 +2556,7 @@ internal override bool GenerateResourcesAndDocumentationComments(
// Use a temporary bag so we don't have to refilter pre-existing diagnostics.
var xmlDiagnostics = DiagnosticBag.GetInstance();
- string assemblyName = FileNameUtilities.ChangeExtension(moduleBuilder.EmitOptions.OutputNameOverride, extension: null);
+ string assemblyName = FileNameUtilities.ChangeExtension(outputNameOverride, extension: null);
DocumentationCommentCompiler.WriteDocumentationCommentXml(this, assemblyName, xmlDocStream, xmlDiagnostics, cancellationToken);
return FilterAndAppendAndFreeDiagnostics(diagnostics, ref xmlDiagnostics);
@@ -2730,15 +2891,15 @@ protected override INamedTypeSymbol CommonCreateTupleTypeSymbol(
return TupleTypeSymbol.Create(
locationOpt: null, // no location for the type declaration
elementTypes: typesBuilder.ToImmutableAndFree(),
- elementLocations: elementLocations,
- elementNames: elementNames,
+ elementLocations: elementLocations,
+ elementNames: elementNames,
compilation: this,
shouldCheckConstraints: false,
errorPositions: default(ImmutableArray));
}
protected override INamedTypeSymbol CommonCreateTupleTypeSymbol(
- INamedTypeSymbol underlyingType,
+ INamedTypeSymbol underlyingType,
ImmutableArray elementNames,
ImmutableArray elementLocations)
{
@@ -2758,7 +2919,7 @@ protected override INamedTypeSymbol CommonCreateTupleTypeSymbol(
}
protected override INamedTypeSymbol CommonCreateAnonymousTypeSymbol(
- ImmutableArray memberTypes,
+ ImmutableArray memberTypes,
ImmutableArray memberNames,
ImmutableArray memberLocations,
ImmutableArray memberIsReadOnly)
@@ -2856,7 +3017,7 @@ internal override int CompareSourceLocations(Location loc1, Location loc2)
#endregion
///
- /// Returns if the compilation has all of the members necessary to emit metadata about
+ /// Returns if the compilation has all of the members necessary to emit metadata about
/// dynamic types.
///
///
@@ -2912,7 +3073,7 @@ internal bool EnableEnumArrayBlockInitialization
return sustainedLowLatency != null && sustainedLowLatency.ContainingAssembly == Assembly.CorLibrary;
}
}
-
+
internal override bool IsIOperationFeatureEnabled()
{
var options = (CSharpParseOptions)this.SyntaxTrees.FirstOrDefault()?.Options;
diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.cs b/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.cs
index 76cefa256a37c..ef370c3b732c8 100644
--- a/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.cs
+++ b/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.cs
@@ -47,6 +47,7 @@ internal static ImmutableArray ConstructScriptConstructorBody(
invokedAsExtensionMethod: false,
argsToParamsOpt: ImmutableArray.Empty,
resultKind: LookupResultKind.Viable,
+ binderOpt: null,
type: objectType)
{ WasCompilerGenerated = true })
{ WasCompilerGenerated = true };
diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs
index 1ab8e15f9f059..5e67a121110a7 100644
--- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs
+++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs
@@ -23,6 +23,7 @@ internal sealed class MethodCompiler : CSharpSymbolVisitor filterOpt, CancellationToken cancellationToken)
{
Debug.Assert(compilation != null);
@@ -90,16 +91,19 @@ internal MethodCompiler(CSharpCompilation compilation, PEModuleBuilder moduleBei
_hasDeclarationErrors = hasDeclarationErrors;
SetGlobalErrorIfTrue(hasDeclarationErrors);
- if (emittingPdb || moduleBeingBuiltOpt?.EmitOptions.EmitTestCoverageData == true)
+ if (emittingPdb || emitTestCoverageData)
{
_debugDocumentProvider = (path, basePath) => moduleBeingBuiltOpt.DebugDocumentsBuilder.GetOrAddDebugDocument(path, basePath, CreateDebugDocumentForFile);
}
+
+ _emitTestCoverageData = emitTestCoverageData;
}
public static void CompileMethodBodies(
CSharpCompilation compilation,
PEModuleBuilder moduleBeingBuiltOpt,
- bool generateDebugInfo,
+ bool emittingPdb,
+ bool emitTestCoverageData,
bool hasDeclarationErrors,
DiagnosticBag diagnostics,
Predicate filterOpt,
@@ -122,7 +126,8 @@ public static void CompileMethodBodies(
MethodCompiler methodCompiler = new MethodCompiler(
compilation,
moduleBeingBuiltOpt,
- generateDebugInfo,
+ emittingPdb,
+ emitTestCoverageData,
hasDeclarationErrors,
diagnostics,
filterOpt,
@@ -184,6 +189,8 @@ public static void CompileMethodBodies(
}
}
+ // Returns the MethodSymbol for the assembly entrypoint. If the user has a Task returning main,
+ // this function returns the synthesized Main MethodSymbol.
private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuilt, bool hasDeclarationErrors, DiagnosticBag diagnostics, CancellationToken cancellationToken)
{
var entryPointAndDiagnostics = compilation.GetEntryPointAndDiagnostics(cancellationToken);
@@ -194,21 +201,69 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul
Debug.Assert(!entryPointAndDiagnostics.Diagnostics.IsDefault);
diagnostics.AddRange(entryPointAndDiagnostics.Diagnostics);
-
var entryPoint = entryPointAndDiagnostics.MethodSymbol;
- var synthesizedEntryPoint = entryPoint as SynthesizedEntryPointSymbol;
+
+ if ((object)entryPoint == null)
+ {
+ Debug.Assert(entryPointAndDiagnostics.Diagnostics.HasAnyErrors() || !compilation.Options.Errors.IsDefaultOrEmpty);
+ return null;
+ }
+
+ // entryPoint can be a SynthesizedEntryPointSymbol if a script is being compiled.
+ SynthesizedEntryPointSymbol synthesizedEntryPoint = entryPoint as SynthesizedEntryPointSymbol;
+ if ((object)synthesizedEntryPoint == null && (entryPoint.ReturnType.IsGenericTaskType(compilation) || entryPoint.ReturnType.IsNonGenericTaskType(compilation)))
+ {
+ synthesizedEntryPoint = new SynthesizedEntryPointSymbol.AsyncForwardEntryPoint(compilation, entryPoint.ContainingType, entryPoint);
+ entryPoint = synthesizedEntryPoint;
+ if ((object)moduleBeingBuilt != null)
+ {
+ moduleBeingBuilt.AddSynthesizedDefinition(entryPoint.ContainingType, synthesizedEntryPoint);
+ }
+ }
+
if (((object)synthesizedEntryPoint != null) &&
(moduleBeingBuilt != null) &&
!hasDeclarationErrors &&
!diagnostics.HasAnyErrors())
{
- var body = synthesizedEntryPoint.CreateBody();
+ BoundStatement body = synthesizedEntryPoint.CreateBody();
+
+ var dynamicAnalysisSpans = ImmutableArray.Empty;
+ VariableSlotAllocator lazyVariableSlotAllocator = null;
+ var lambdaDebugInfoBuilder = ArrayBuilder.GetInstance();
+ var closureDebugInfoBuilder = ArrayBuilder.GetInstance();
+ StateMachineTypeSymbol stateMachineTypeOpt = null;
const int methodOrdinal = -1;
+
+ var loweredBody = LowerBodyOrInitializer(
+ synthesizedEntryPoint,
+ methodOrdinal,
+ body,
+ null,
+ new TypeCompilationState(synthesizedEntryPoint.ContainingType, compilation, moduleBeingBuilt),
+ false,
+ null,
+ ref dynamicAnalysisSpans,
+ diagnostics,
+ ref lazyVariableSlotAllocator,
+ lambdaDebugInfoBuilder,
+ closureDebugInfoBuilder,
+ out stateMachineTypeOpt);
+
+ Debug.Assert((object)lazyVariableSlotAllocator == null);
+ Debug.Assert((object)stateMachineTypeOpt == null);
+ Debug.Assert(dynamicAnalysisSpans.IsEmpty);
+ Debug.Assert(lambdaDebugInfoBuilder.IsEmpty());
+ Debug.Assert(closureDebugInfoBuilder.IsEmpty());
+
+ lambdaDebugInfoBuilder.Free();
+ closureDebugInfoBuilder.Free();
+
var emittedBody = GenerateMethodBody(
moduleBeingBuilt,
synthesizedEntryPoint,
methodOrdinal,
- body,
+ loweredBody,
ImmutableArray.Empty,
ImmutableArray.Empty,
stateMachineTypeOpt: null,
@@ -217,11 +272,11 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul
debugDocumentProvider: null,
importChainOpt: null,
emittingPdb: false,
+ emitTestCoverageData: false,
dynamicAnalysisSpans: ImmutableArray.Empty);
moduleBeingBuilt.SetMethodBody(synthesizedEntryPoint, emittedBody);
}
- Debug.Assert((object)entryPoint != null || entryPointAndDiagnostics.Diagnostics.HasAnyErrors() || !compilation.Options.Errors.IsDefaultOrEmpty);
return entryPoint;
}
@@ -546,7 +601,7 @@ private void CompileSynthesizedMethods(PrivateImplementationDetails privateImplC
Debug.Assert(_moduleBeingBuiltOpt != null);
var compilationState = new TypeCompilationState(null, _compilation, _moduleBeingBuiltOpt);
- foreach (MethodSymbol method in privateImplClass.GetMethods(new EmitContext(_moduleBeingBuiltOpt, null, diagnostics)))
+ foreach (MethodSymbol method in privateImplClass.GetMethods(new EmitContext(_moduleBeingBuiltOpt, null, diagnostics, metadataOnly: false, includePrivateMembers: true)))
{
Debug.Assert(method.SynthesizesLoweredBoundBody);
method.GenerateMethodBody(compilationState, diagnostics);
@@ -594,74 +649,75 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState)
var importChain = methodWithBody.ImportChainOpt;
compilationState.CurrentImportChain = importChain;
- // We make sure that an asynchronous mutation to the diagnostic bag does not
- // confuse the method body generator by making a fresh bag and then loading
- // any diagnostics emitted into it back into the main diagnostic bag.
- var diagnosticsThisMethod = DiagnosticBag.GetInstance();
+ // We make sure that an asynchronous mutation to the diagnostic bag does not
+ // confuse the method body generator by making a fresh bag and then loading
+ // any diagnostics emitted into it back into the main diagnostic bag.
+ var diagnosticsThisMethod = DiagnosticBag.GetInstance();
var method = methodWithBody.Method;
- var lambda = method as SynthesizedLambdaMethod;
- var variableSlotAllocatorOpt = ((object)lambda != null) ?
- _moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(lambda, lambda.TopLevelMethod, diagnosticsThisMethod) :
- _moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(method, method, diagnosticsThisMethod);
-
- // Synthesized methods have no ordinal stored in custom debug information (only user-defined methods have ordinals).
- // In case of async lambdas, which synthesize a state machine type during the following rewrite, the containing method has already been uniquely named,
- // so there is no need to produce a unique method ordinal for the corresponding state machine type, whose name includes the (unique) containing method name.
- const int methodOrdinal = -1;
- MethodBody emittedBody = null;
+ var lambda = method as SynthesizedLambdaMethod;
+ var variableSlotAllocatorOpt = ((object)lambda != null) ?
+ _moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(lambda, lambda.TopLevelMethod, diagnosticsThisMethod) :
+ _moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(method, method, diagnosticsThisMethod);
- try
- {
- // Local functions can be iterators as well as be async (lambdas can only be async), so we need to lower both iterators and async
- IteratorStateMachine iteratorStateMachine;
- BoundStatement loweredBody = IteratorRewriter.Rewrite(methodWithBody.Body, method, methodOrdinal, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out iteratorStateMachine);
- StateMachineTypeSymbol stateMachine = iteratorStateMachine;
+ // Synthesized methods have no ordinal stored in custom debug information (only user-defined methods have ordinals).
+ // In case of async lambdas, which synthesize a state machine type during the following rewrite, the containing method has already been uniquely named,
+ // so there is no need to produce a unique method ordinal for the corresponding state machine type, whose name includes the (unique) containing method name.
+ const int methodOrdinal = -1;
+ MethodBody emittedBody = null;
- if (!loweredBody.HasErrors)
+ try
{
- AsyncStateMachine asyncStateMachine;
- loweredBody = AsyncRewriter.Rewrite(loweredBody, method, methodOrdinal, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out asyncStateMachine);
+ // Local functions can be iterators as well as be async (lambdas can only be async), so we need to lower both iterators and async
+ IteratorStateMachine iteratorStateMachine;
+ BoundStatement loweredBody = IteratorRewriter.Rewrite(methodWithBody.Body, method, methodOrdinal, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out iteratorStateMachine);
+ StateMachineTypeSymbol stateMachine = iteratorStateMachine;
- Debug.Assert(iteratorStateMachine == null || asyncStateMachine == null);
- stateMachine = stateMachine ?? asyncStateMachine;
- }
+ if (!loweredBody.HasErrors)
+ {
+ AsyncStateMachine asyncStateMachine;
+ loweredBody = AsyncRewriter.Rewrite(loweredBody, method, methodOrdinal, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out asyncStateMachine);
- if (!diagnosticsThisMethod.HasAnyErrors() && !_globalHasErrors)
- {
- emittedBody = GenerateMethodBody(
- _moduleBeingBuiltOpt,
- method,
- methodOrdinal,
- loweredBody,
- ImmutableArray.Empty,
- ImmutableArray.Empty,
- stateMachine,
- variableSlotAllocatorOpt,
- diagnosticsThisMethod,
- _debugDocumentProvider,
+ Debug.Assert(iteratorStateMachine == null || asyncStateMachine == null);
+ stateMachine = stateMachine ?? asyncStateMachine;
+ }
+
+ if (!diagnosticsThisMethod.HasAnyErrors() && !_globalHasErrors)
+ {
+ emittedBody = GenerateMethodBody(
+ _moduleBeingBuiltOpt,
+ method,
+ methodOrdinal,
+ loweredBody,
+ ImmutableArray.Empty,
+ ImmutableArray.Empty,
+ stateMachine,
+ variableSlotAllocatorOpt,
+ diagnosticsThisMethod,
+ _debugDocumentProvider,
method.GenerateDebugInfo ? importChain : null,
- emittingPdb: _emittingPdb,
- dynamicAnalysisSpans: ImmutableArray.Empty);
+ emittingPdb: _emittingPdb,
+ emitTestCoverageData: _emitTestCoverageData,
+ dynamicAnalysisSpans: ImmutableArray.Empty);
+ }
+ }
+ catch (BoundTreeVisitor.CancelledByStackGuardException ex)
+ {
+ ex.AddAnError(_diagnostics);
}
- }
- catch (BoundTreeVisitor.CancelledByStackGuardException ex)
- {
- ex.AddAnError(_diagnostics);
- }
- _diagnostics.AddRange(diagnosticsThisMethod);
- diagnosticsThisMethod.Free();
+ _diagnostics.AddRange(diagnosticsThisMethod);
+ diagnosticsThisMethod.Free();
- // error while generating IL
- if (emittedBody == null)
- {
- break;
- }
+ // error while generating IL
+ if (emittedBody == null)
+ {
+ break;
+ }
- _moduleBeingBuiltOpt.SetMethodBody(method, emittedBody);
+ _moduleBeingBuiltOpt.SetMethodBody(method, emittedBody);
+ }
}
- }
finally
{
compilationState.CurrentImportChain = oldImportChain;
@@ -747,6 +803,7 @@ private void CompileFieldLikeEventAccessor(SourceEventSymbol eventSymbol, bool i
debugDocumentProvider: _debugDocumentProvider,
importChainOpt: null,
emittingPdb: false,
+ emitTestCoverageData: _emitTestCoverageData,
dynamicAnalysisSpans: ImmutableArray.Empty);
_moduleBeingBuiltOpt.SetMethodBody(accessor, emittedBody);
@@ -818,7 +875,6 @@ private void CompileMethod(
}
ImportChain oldImportChain = compilationState.CurrentImportChain;
- bool instrumentForDynamicAnalysis = _moduleBeingBuiltOpt?.EmitOptions.EmitTestCoverageData == true;
// In order to avoid generating code for methods with errors, we create a diagnostic bag just for this method.
DiagnosticBag diagsForCurrentMethod = DiagnosticBag.GetInstance();
@@ -887,9 +943,9 @@ private void CompileMethod(
analyzedInitializers = InitializerRewriter.RewriteConstructor(processedInitializers.BoundInitializers, methodSymbol);
processedInitializers.HasErrors = processedInitializers.HasErrors || analyzedInitializers.HasAnyErrors;
- if (body != null && ((methodSymbol.ContainingType.IsStructType() && !methodSymbol.IsImplicitConstructor) || instrumentForDynamicAnalysis))
+ if (body != null && ((methodSymbol.ContainingType.IsStructType() && !methodSymbol.IsImplicitConstructor) || _emitTestCoverageData))
{
- if (instrumentForDynamicAnalysis && methodSymbol.IsImplicitConstructor)
+ if (_emitTestCoverageData && methodSymbol.IsImplicitConstructor)
{
// Flow analysis over the initializers is necessary in order to find assignments to fields.
// Bodies of implicit constructors do not get flow analysis later, so the initializers
@@ -1004,7 +1060,7 @@ private void CompileMethod(
flowAnalyzedBody,
previousSubmissionFields,
compilationState,
- instrumentForDynamicAnalysis,
+ _emitTestCoverageData,
_debugDocumentProvider,
ref dynamicAnalysisSpans,
diagsForCurrentMethod,
@@ -1046,7 +1102,7 @@ private void CompileMethod(
{
// For dynamic analysis, field initializers are instrumented as part of constructors,
// and so are never instrumented here.
- Debug.Assert(!instrumentForDynamicAnalysis);
+ Debug.Assert(!_emitTestCoverageData);
StateMachineTypeSymbol initializerStateMachineTypeOpt;
BoundStatement lowered = LowerBodyOrInitializer(
@@ -1055,7 +1111,7 @@ private void CompileMethod(
analyzedInitializers,
previousSubmissionFields,
compilationState,
- instrumentForDynamicAnalysis,
+ _emitTestCoverageData,
_debugDocumentProvider,
ref dynamicAnalysisSpans,
diagsForCurrentMethod,
@@ -1087,7 +1143,7 @@ private void CompileMethod(
{
if (processedInitializers.LoweredInitializers.Kind == BoundKind.StatementList)
{
- BoundStatementList lowered = (BoundStatementList) processedInitializers.LoweredInitializers;
+ BoundStatementList lowered = (BoundStatementList)processedInitializers.LoweredInitializers;
boundStatements = boundStatements.Concat(lowered.Statements);
}
else
@@ -1119,6 +1175,7 @@ private void CompileMethod(
_debugDocumentProvider,
importChain,
_emittingPdb,
+ _emitTestCoverageData,
dynamicAnalysisSpans);
_moduleBeingBuiltOpt.SetMethodBody(methodSymbol.PartialDefinitionPart ?? methodSymbol, emittedBody);
@@ -1178,7 +1235,7 @@ internal static BoundStatement LowerBodyOrInitializer(
previousSubmissionFields: previousSubmissionFields,
allowOmissionOfConditionalCalls: true,
instrumentForDynamicAnalysis: instrumentForDynamicAnalysis,
- debugDocumentProvider:debugDocumentProvider,
+ debugDocumentProvider: debugDocumentProvider,
dynamicAnalysisSpans: ref dynamicAnalysisSpans,
diagnostics: diagnostics,
sawLambdas: out sawLambdas,
@@ -1231,7 +1288,7 @@ internal static BoundStatement LowerBodyOrInitializer(
lazyVariableSlotAllocator,
compilationState,
diagnostics,
- assignLocals: false);
+ assignLocals: null);
}
if (bodyWithoutLambdas.HasErrors)
@@ -1275,6 +1332,7 @@ private static MethodBody GenerateMethodBody(
DebugDocumentProvider debugDocumentProvider,
ImportChain importChainOpt,
bool emittingPdb,
+ bool emitTestCoverageData,
ImmutableArray dynamicAnalysisSpans)
{
// Note: don't call diagnostics.HasAnyErrors() in release; could be expensive if compilation has many warnings.
@@ -1301,7 +1359,7 @@ private static MethodBody GenerateMethodBody(
bool isAsyncStateMachine;
MethodSymbol kickoffMethod;
- if (method is SynthesizedStateMachineMethod stateMachineMethod &&
+ if (method is SynthesizedStateMachineMethod stateMachineMethod &&
method.Name == WellKnownMemberNames.MoveNextMethodName)
{
kickoffMethod = stateMachineMethod.StateMachineType.KickoffMethod;
@@ -1329,9 +1387,9 @@ private static MethodBody GenerateMethodBody(
// So it is undesirable to consider these exceptions "user unhandled" since there may well be user code that is awaiting the task.
// This is a heuristic since it's possible that there is no user code awaiting the task.
moveNextBodyDebugInfoOpt = new AsyncMoveNextBodyDebugInfo(
- kickoffMethod,
+ kickoffMethod,
kickoffMethod.ReturnsVoid ? asyncCatchHandlerOffset : -1,
- asyncYieldPoints,
+ asyncYieldPoints,
asyncResumePoints);
}
else
@@ -1383,7 +1441,7 @@ private static MethodBody GenerateMethodBody(
}
DynamicAnalysisMethodBodyData dynamicAnalysisDataOpt = null;
- if (moduleBuilder.EmitOptions.EmitTestCoverageData)
+ if (emitTestCoverageData)
{
Debug.Assert(debugDocumentProvider != null);
dynamicAnalysisDataOpt = new DynamicAnalysisMethodBodyData(dynamicAnalysisSpans);
@@ -1808,6 +1866,7 @@ internal static BoundCall GenerateObjectConstructorInitializer(MethodSymbol cons
invokedAsExtensionMethod: false,
argsToParamsOpt: ImmutableArray.Empty,
resultKind: resultKind,
+ binderOpt: null,
type: objectType,
hasErrors: hasErrors)
{ WasCompilerGenerated = true };
diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs
index 72b8f9303c885..00ed2fbed8133 100644
--- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs
+++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs
@@ -87,6 +87,7 @@ internal static EmitDifferenceResult EmitDifference(
updatedMethods,
diagnostics,
testData?.SymWriterFactory,
+ emitOptions.PdbFilePath,
cancellationToken);
}
@@ -123,8 +124,8 @@ private static EmitBaseline MapToCompilation(
// Mapping from previous compilation to the current.
var anonymousTypeMap = moduleBeingBuilt.GetAnonymousTypeMap();
var sourceAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly;
- var sourceContext = new EmitContext((PEModuleBuilder)previousGeneration.PEModuleBuilder, null, new DiagnosticBag());
- var otherContext = new EmitContext(moduleBeingBuilt, null, new DiagnosticBag());
+ var sourceContext = new EmitContext((PEModuleBuilder)previousGeneration.PEModuleBuilder, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true);
+ var otherContext = new EmitContext(moduleBeingBuilt, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true);
var matcher = new CSharpSymbolMatcher(
anonymousTypeMap,
diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs
index 50fe809e3f4c8..f304335d41170 100644
--- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs
+++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs
@@ -33,7 +33,7 @@ public PEDeltaAssemblyBuilder(
: base(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, additionalTypes: ImmutableArray.Empty)
{
var initialBaseline = previousGeneration.InitialBaseline;
- var context = new EmitContext(this, null, new DiagnosticBag());
+ var context = new EmitContext(this, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true);
// Hydrate symbols from initial metadata. Once we do so it is important to reuse these symbols across all generations,
// in order for the symbol matcher to be able to use reference equality once it maps symbols to initial metadata.
@@ -47,7 +47,7 @@ public PEDeltaAssemblyBuilder(
if (previousGeneration.Ordinal > 0)
{
var previousAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly;
- var previousContext = new EmitContext((PEModuleBuilder)previousGeneration.PEModuleBuilder, null, new DiagnosticBag());
+ var previousContext = new EmitContext((PEModuleBuilder)previousGeneration.PEModuleBuilder, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true);
matchToPrevious = new CSharpSymbolMatcher(
previousGeneration.AnonymousTypeMap,
diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs
index c776c270e26a2..20bb10723f950 100644
--- a/src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs
+++ b/src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs
@@ -582,10 +582,8 @@ private IEnumerable GetReturnValueCustomAttributesToEmit()
{
CheckDefinitionInvariant();
- ImmutableArray userDefined;
+ ImmutableArray userDefined = this.GetReturnTypeAttributes();
ArrayBuilder synthesized = null;
-
- userDefined = this.GetReturnTypeAttributes();
this.AddSynthesizedReturnTypeAttributes(ref synthesized);
// Note that callers of this method (CCI and ReflectionEmitter) have to enumerate
diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs
index da185b6ee18cf..da2b554d0c6bd 100644
--- a/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs
+++ b/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs
@@ -287,12 +287,15 @@ Cci.ITypeReference Cci.ITypeDefinition.GetBaseClass(EmitContext context)
diagnostics: context.Diagnostics) : null;
}
- IEnumerable Cci.ITypeDefinition.Events
+ IEnumerable Cci.ITypeDefinition.GetEvents(EmitContext context)
{
- get
+ CheckDefinitionInvariant();
+ foreach (var e in GetEventsToEmit())
{
- CheckDefinitionInvariant();
- return GetEventsToEmit();
+ if (e.ShouldInclude(context))
+ {
+ yield return e;
+ }
}
}
@@ -389,9 +392,15 @@ internal virtual IEnumerable GetEventsToEmit()
{
CheckDefinitionInvariant();
+ // All fields in a struct should be emitted
+ bool isStruct = this.IsStructType();
+
foreach (var f in GetFieldsToEmit())
{
- yield return f;
+ if (isStruct || f.ShouldInclude(context))
+ {
+ yield return f;
+ }
}
IEnumerable generated = ((PEModuleBuilder)context.Module).GetSynthesizedFields(this);
@@ -400,7 +409,10 @@ internal virtual IEnumerable GetEventsToEmit()
{
foreach (var f in generated)
{
- yield return f;
+ if (isStruct || f.ShouldInclude(context))
+ {
+ yield return f;
+ }
}
}
}
@@ -630,7 +642,10 @@ internal virtual bool IsMetadataSealed
foreach (var method in this.GetMethodsToEmit())
{
Debug.Assert((object)method != null);
- yield return method;
+ if (method.ShouldInclude(context))
+ {
+ yield return method;
+ }
}
IEnumerable generated = ((PEModuleBuilder)context.Module).GetSynthesizedMethods(this);
@@ -639,7 +654,10 @@ internal virtual bool IsMetadataSealed
{
foreach (var m in generated)
{
- yield return m;
+ if (m.ShouldInclude(context))
+ {
+ yield return m;
+ }
}
}
}
@@ -704,7 +722,10 @@ internal virtual IEnumerable GetMethodsToEmit()
foreach (var property in this.GetPropertiesToEmit())
{
Debug.Assert((object)property != null);
- yield return property;
+ if (property.ShouldInclude(context))
+ {
+ yield return property;
+ }
}
IEnumerable generated = ((PEModuleBuilder)context.Module).GetSynthesizedProperties(this);
@@ -713,7 +734,10 @@ internal virtual IEnumerable GetMethodsToEmit()
{
foreach (var m in generated)
{
- yield return m;
+ if (m.ShouldInclude(context))
+ {
+ yield return m;
+ }
}
}
}
diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs
index 60b6fb3d1412d..1f6765b2b9526 100644
--- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs
+++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs
@@ -83,9 +83,10 @@ internal sealed override Cci.ICustomAttribute SynthesizeAttribute(WellKnownMembe
return Compilation.TrySynthesizeAttribute(attributeConstructor);
}
- public sealed override IEnumerable GetSourceAssemblyAttributes()
+ public sealed override IEnumerable GetSourceAssemblyAttributes(bool isRefAssembly)
{
- return SourceModule.ContainingSourceAssembly.GetCustomAttributesToEmit(this.CompilationState, emittingAssemblyAttributesInNetModule: OutputKind.IsNetModule());
+ return SourceModule.ContainingSourceAssembly
+ .GetCustomAttributesToEmit(this.CompilationState, isRefAssembly, emittingAssemblyAttributesInNetModule: OutputKind.IsNetModule());
}
public sealed override IEnumerable GetSourceAssemblySecurityAttributes()
@@ -358,9 +359,9 @@ internal virtual bool TryGetAnonymousTypeName(NamedTypeSymbol template, out stri
return false;
}
- internal sealed override ImmutableArray GetAnonymousTypes()
+ internal sealed override ImmutableArray GetAnonymousTypes(EmitContext context)
{
- if (EmitOptions.EmitMetadataOnly)
+ if (context.MetadataOnly)
{
return ImmutableArray.Empty;
}
diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PropertySymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PropertySymbolAdapter.cs
index a9cdc135ae298..217a3dccd7f62 100644
--- a/src/Compilers/CSharp/Portable/Emitter/Model/PropertySymbolAdapter.cs
+++ b/src/Compilers/CSharp/Portable/Emitter/Model/PropertySymbolAdapter.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
+using Microsoft.Cci;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.Emit;
@@ -10,41 +11,38 @@
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal partial class PropertySymbol :
- Cci.IPropertyDefinition
+ IPropertyDefinition
{
#region IPropertyDefinition Members
- IEnumerable Cci.IPropertyDefinition.Accessors
+ IEnumerable IPropertyDefinition.GetAccessors(EmitContext context)
{
- get
- {
- CheckDefinitionInvariant();
+ CheckDefinitionInvariant();
- var getMethod = this.GetMethod;
- if ((object)getMethod != null)
- {
- yield return getMethod;
- }
+ MethodSymbol getMethod = this.GetMethod;
+ if (getMethod != null && getMethod.ShouldInclude(context))
+ {
+ yield return getMethod;
+ }
- var setMethod = this.SetMethod;
- if ((object)setMethod != null)
- {
- yield return setMethod;
- }
+ MethodSymbol setMethod = this.SetMethod;
+ if (setMethod != null && setMethod.ShouldInclude(context))
+ {
+ yield return setMethod;
+ }
- SourcePropertySymbol sourceProperty = this as SourcePropertySymbol;
- if ((object)sourceProperty != null)
+ SourcePropertySymbol sourceProperty = this as SourcePropertySymbol;
+ if ((object)sourceProperty != null && sourceProperty.ShouldInclude(context))
+ {
+ SynthesizedSealedPropertyAccessor synthesizedAccessor = sourceProperty.SynthesizedSealedAccessorOpt;
+ if ((object)synthesizedAccessor != null)
{
- SynthesizedSealedPropertyAccessor synthesizedAccessor = sourceProperty.SynthesizedSealedAccessorOpt;
- if ((object)synthesizedAccessor != null)
- {
- yield return synthesizedAccessor;
- }
+ yield return synthesizedAccessor;
}
}
}
- MetadataConstant Cci.IPropertyDefinition.DefaultValue
+ MetadataConstant IPropertyDefinition.DefaultValue
{
get
{
@@ -53,7 +51,7 @@ MetadataConstant Cci.IPropertyDefinition.DefaultValue
}
}
- Cci.IMethodReference Cci.IPropertyDefinition.Getter
+ IMethodReference IPropertyDefinition.Getter
{
get
{
@@ -68,7 +66,7 @@ Cci.IMethodReference Cci.IPropertyDefinition.Getter
}
}
- bool Cci.IPropertyDefinition.HasDefaultValue
+ bool IPropertyDefinition.HasDefaultValue
{
get
{
@@ -77,7 +75,7 @@ bool Cci.IPropertyDefinition.HasDefaultValue
}
}
- bool Cci.IPropertyDefinition.IsRuntimeSpecial
+ bool IPropertyDefinition.IsRuntimeSpecial
{
get
{
@@ -95,7 +93,7 @@ internal virtual bool HasRuntimeSpecialName
}
}
- bool Cci.IPropertyDefinition.IsSpecialName
+ bool IPropertyDefinition.IsSpecialName
{
get
{
@@ -104,16 +102,16 @@ bool Cci.IPropertyDefinition.IsSpecialName
}
}
- ImmutableArray Cci.IPropertyDefinition.Parameters
+ ImmutableArray IPropertyDefinition.Parameters
{
get
{
CheckDefinitionInvariant();
- return StaticCast.From(this.Parameters);
+ return StaticCast.From(this.Parameters);
}
}
- Cci.IMethodReference Cci.IPropertyDefinition.Setter
+ IMethodReference IPropertyDefinition.Setter
{
get
{
@@ -142,7 +140,7 @@ private void CheckDefinitionInvariantAllowEmbedded()
Debug.Assert(this.ContainingModule is SourceModuleSymbol || this.ContainingAssembly.IsLinked);
}
- Cci.CallingConvention Cci.ISignature.CallingConvention
+ CallingConvention ISignature.CallingConvention
{
get
{
@@ -151,7 +149,7 @@ Cci.CallingConvention Cci.ISignature.CallingConvention
}
}
- ushort Cci.ISignature.ParameterCount
+ ushort ISignature.ParameterCount
{
get
{
@@ -160,31 +158,31 @@ ushort Cci.ISignature.ParameterCount
}
}
- ImmutableArray Cci.ISignature.GetParameters(EmitContext context)
+ ImmutableArray ISignature.GetParameters(EmitContext context)
{
CheckDefinitionInvariant();
- return StaticCast.From(this.Parameters);
+ return StaticCast.From(this.Parameters);
}
- ImmutableArray Cci.ISignature.ReturnValueCustomModifiers
+ ImmutableArray ISignature.ReturnValueCustomModifiers
{
get
{
CheckDefinitionInvariantAllowEmbedded();
- return this.TypeCustomModifiers.As();
+ return this.TypeCustomModifiers.As();
}
}
- ImmutableArray Cci.ISignature.RefCustomModifiers
+ ImmutableArray ISignature.RefCustomModifiers
{
get
{
CheckDefinitionInvariantAllowEmbedded();
- return this.RefCustomModifiers.As();
+ return this.RefCustomModifiers.As();
}
}
- bool Cci.ISignature.ReturnValueIsByRef
+ bool ISignature.ReturnValueIsByRef
{
get
{
@@ -193,7 +191,7 @@ bool Cci.ISignature.ReturnValueIsByRef
}
}
- Cci.ITypeReference Cci.ISignature.GetType(EmitContext context)
+ ITypeReference ISignature.GetType(EmitContext context)
{
CheckDefinitionInvariantAllowEmbedded();
return ((PEModuleBuilder)context.Module).Translate(this.Type,
@@ -205,7 +203,7 @@ Cci.ITypeReference Cci.ISignature.GetType(EmitContext context)
#region ITypeDefinitionMember Members
- Cci.ITypeDefinition Cci.ITypeDefinitionMember.ContainingTypeDefinition
+ ITypeDefinition ITypeDefinitionMember.ContainingTypeDefinition
{
get
{
@@ -214,7 +212,7 @@ Cci.ITypeDefinition Cci.ITypeDefinitionMember.ContainingTypeDefinition
}
}
- Cci.TypeMemberVisibility Cci.ITypeDefinitionMember.Visibility
+ TypeMemberVisibility ITypeDefinitionMember.Visibility
{
get
{
@@ -227,7 +225,7 @@ Cci.TypeMemberVisibility Cci.ITypeDefinitionMember.Visibility
#region ITypeMemberReference Members
- Cci.ITypeReference Cci.ITypeMemberReference.GetContainingType(EmitContext context)
+ ITypeReference ITypeMemberReference.GetContainingType(EmitContext context)
{
CheckDefinitionInvariant();
return this.ContainingType;
@@ -237,13 +235,13 @@ Cci.ITypeReference Cci.ITypeMemberReference.GetContainingType(EmitContext contex
#region IReference Members
- void Cci.IReference.Dispatch(Cci.MetadataVisitor visitor)
+ void IReference.Dispatch(MetadataVisitor visitor)
{
CheckDefinitionInvariant();
- visitor.Visit((Cci.IPropertyDefinition)this);
+ visitor.Visit((IPropertyDefinition)this);
}
- Cci.IDefinition Cci.IReference.AsDefinition(EmitContext context)
+ IDefinition IReference.AsDefinition(EmitContext context)
{
CheckDefinitionInvariant();
return this;
@@ -253,7 +251,7 @@ Cci.IDefinition Cci.IReference.AsDefinition(EmitContext context)
#region INamedEntity Members
- string Cci.INamedEntity.Name
+ string INamedEntity.Name
{
get
{
@@ -264,7 +262,7 @@ string Cci.INamedEntity.Name
#endregion
- private Cci.IMethodReference GetSynthesizedSealedAccessor(MethodKind targetMethodKind)
+ private IMethodReference GetSynthesizedSealedAccessor(MethodKind targetMethodKind)
{
SourcePropertySymbol sourceProperty = this as SourcePropertySymbol;
if ((object)sourceProperty != null)
diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/SourceAssemblySymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/SourceAssemblySymbolAdapter.cs
new file mode 100644
index 0000000000000..e93fc7cdcc63f
--- /dev/null
+++ b/src/Compilers/CSharp/Portable/Emitter/Model/SourceAssemblySymbolAdapter.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+
+namespace Microsoft.CodeAnalysis.CSharp.Symbols
+{
+ internal partial class SourceAssemblySymbol
+ {
+ internal IEnumerable GetCustomAttributesToEmit(ModuleCompilationState compilationState, bool emittingRefAssembly, bool emittingAssemblyAttributesInNetModule)
+ {
+ CheckDefinitionInvariant();
+
+ ImmutableArray userDefined = this.GetAttributes();
+ ArrayBuilder synthesized = null;
+ this.AddSynthesizedAttributes(compilationState, ref synthesized);
+
+ if (emittingRefAssembly && !HasReferenceAssemblyAttribute)
+ {
+ var referenceAssemblyAttribute = this.DeclaringCompilation
+ .TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_ReferenceAssemblyAttribute__ctor, isOptionalUse: true);
+ Symbol.AddSynthesizedAttribute(ref synthesized, referenceAssemblyAttribute);
+ }
+
+ // Note that callers of this method (CCI and ReflectionEmitter) have to enumerate
+ // all items of the returned iterator, otherwise the synthesized ArrayBuilder may leak.
+ return GetCustomAttributesToEmit(userDefined, synthesized, isReturnType: false, emittingAssemblyAttributesInNetModule: emittingAssemblyAttributesInNetModule);
+ }
+ }
+}
diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/SymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/SymbolAdapter.cs
index d1c10b1df43d0..1395f36244021 100644
--- a/src/Compilers/CSharp/Portable/Emitter/Model/SymbolAdapter.cs
+++ b/src/Compilers/CSharp/Portable/Emitter/Model/SymbolAdapter.cs
@@ -66,6 +66,7 @@ internal virtual IEnumerable GetCustomAttributesToEmit(Modu
internal IEnumerable GetCustomAttributesToEmit(ModuleCompilationState compilationState, bool emittingAssemblyAttributesInNetModule)
{
CheckDefinitionInvariant();
+ Debug.Assert(this.Kind != SymbolKind.Assembly);
ImmutableArray userDefined;
ArrayBuilder synthesized = null;
diff --git a/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs b/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs
index 7d15930176980..2e41a059aaf81 100644
--- a/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs
+++ b/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs
@@ -331,7 +331,7 @@ private EmbeddedType EmbedType(
// Therefore, the following check can be as simple as:
Debug.Assert(!IsFrozen, "Set of embedded types is frozen.");
- var noPiaIndexer = new Cci.NoPiaReferenceIndexer(new EmitContext(ModuleBeingBuilt, syntaxNodeOpt, diagnostics));
+ var noPiaIndexer = new Cci.NoPiaReferenceIndexer(new EmitContext(ModuleBeingBuilt, syntaxNodeOpt, diagnostics, metadataOnly: false, includePrivateMembers: true));
// Make sure we embed all types referenced by the type declaration: implemented interfaces, etc.
noPiaIndexer.VisitTypeDefinitionNoMembers(embedded);
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
index 8343bd6e0f6df..32797ef03e951 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
@@ -1060,7 +1060,7 @@ internal enum ErrorCode
ERR_InvalidOutputName = 2041,
ERR_InvalidDebugInformationFormat = 2042,
ERR_LegacyObjectIdSyntax = 2043,
- ERR_SourceLinkRequiresPortablePdb = 2044,
+ ERR_SourceLinkRequiresPdb = 2044,
ERR_CannotEmbedWithoutPdb = 2045,
// unused 2046-2999
WRN_CLS_NoVarArgs = 3000,
@@ -1104,7 +1104,7 @@ internal enum ErrorCode
ERR_VarargsAsync = 4006,
ERR_ByRefTypeAndAwait = 4007,
ERR_BadAwaitArgVoidCall = 4008,
- ERR_MainCantBeAsync = 4009,
+ ERR_NonTaskMainCantBeAsync = 4009,
ERR_CantConvAsyncAnonFuncReturns = 4010,
ERR_BadAwaiterPattern = 4011,
ERR_BadSpecialByRefLocal = 4012,
@@ -1479,6 +1479,16 @@ internal enum ErrorCode
#region diagnostics for C# 7.1
+ ERR_NoRefOutWhenRefOnly = 8308,
+ ERR_NoNetModuleOutputWhenRefOutOrRefOnly = 8309,
+ // Available = 8310,
+ ERR_BadDynamicMethodArgDefaultLiteral = 8311,
+ ERR_DefaultLiteralNotValid = 8312,
+ WRN_DefaultInSwitch = 8313,
+ ERR_PatternWrongGenericTypeInVersion = 8314,
+
+ #endregion diagnostics for C# 7.1
+
ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation = 8501,
ERR_RuntimeDoesNotSupportDefaultInterfaceImplementationForMember = 8502,
@@ -1487,11 +1497,5 @@ internal enum ErrorCode
ERR_DefaultInterfaceImplementationModifier = 8503,
ERR_ImplicitImplementationOfNonPublicInterfaceMember = 8504,
- ERR_BadDynamicMethodArgDefaultLiteral = 9000,
- ERR_DefaultLiteralNotValid = 9001,
- WRN_DefaultInSwitch = 9002,
- ERR_PatternWrongGenericTypeInVersion = 9003,
-
- #endregion diagnostics for C# 7.1
}
}
diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
index 10f8705bbe511..7ca1c2467593b 100644
--- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs
+++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
@@ -130,8 +130,9 @@ internal enum MessageID
IDS_FeatureDefaultLiteral = MessageBase + 12718,
IDS_FeatureInferredTupleNames = MessageBase + 12719,
IDS_FeatureGenericPatternMatching = MessageBase + 12720,
+ IDS_FeatureAsyncMain = MessageBase + 12721,
- IDS_DefaultInterfaceImplementation = MessageBase + 12721,
+ IDS_DefaultInterfaceImplementation = MessageBase + 12722,
}
// Message IDs may refer to strings that need to be localized.
@@ -189,6 +190,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
switch (feature)
{
// C# 7.1 features.
+ case MessageID.IDS_FeatureAsyncMain:
case MessageID.IDS_FeatureDefaultLiteral:
case MessageID.IDS_FeatureInferredTupleNames:
case MessageID.IDS_FeatureGenericPatternMatching:
diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs
index b6e0e6fd5f15e..d624e3ee0bab3 100644
--- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs
+++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs
@@ -4353,7 +4353,7 @@ public BoundPropertyGroup Update(ImmutableArray properties, Boun
internal sealed partial class BoundCall : BoundExpression
{
- public BoundCall(SyntaxNode syntax, BoundExpression receiverOpt, MethodSymbol method, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool isDelegateCall, bool expanded, bool invokedAsExtensionMethod, ImmutableArray argsToParamsOpt, LookupResultKind resultKind, TypeSymbol type, bool hasErrors = false)
+ public BoundCall(SyntaxNode syntax, BoundExpression receiverOpt, MethodSymbol method, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool isDelegateCall, bool expanded, bool invokedAsExtensionMethod, ImmutableArray argsToParamsOpt, LookupResultKind resultKind, Binder binderOpt, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.Call, syntax, type, hasErrors || receiverOpt.HasErrors() || arguments.HasErrors())
{
@@ -4371,6 +4371,7 @@ public BoundCall(SyntaxNode syntax, BoundExpression receiverOpt, MethodSymbol me
this.InvokedAsExtensionMethod = invokedAsExtensionMethod;
this.ArgsToParamsOpt = argsToParamsOpt;
this._ResultKind = resultKind;
+ this.BinderOpt = binderOpt;
}
@@ -4395,16 +4396,18 @@ public BoundCall(SyntaxNode syntax, BoundExpression receiverOpt, MethodSymbol me
private readonly LookupResultKind _ResultKind;
public override LookupResultKind ResultKind { get { return _ResultKind;} }
+ public Binder BinderOpt { get; }
+
public override BoundNode Accept(BoundTreeVisitor visitor)
{
return visitor.VisitCall(this);
}
- public BoundCall Update(BoundExpression receiverOpt, MethodSymbol method, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool isDelegateCall, bool expanded, bool invokedAsExtensionMethod, ImmutableArray argsToParamsOpt, LookupResultKind resultKind, TypeSymbol type)
+ public BoundCall Update(BoundExpression receiverOpt, MethodSymbol method, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool isDelegateCall, bool expanded, bool invokedAsExtensionMethod, ImmutableArray argsToParamsOpt, LookupResultKind resultKind, Binder binderOpt, TypeSymbol type)
{
- if (receiverOpt != this.ReceiverOpt || method != this.Method || arguments != this.Arguments || argumentNamesOpt != this.ArgumentNamesOpt || argumentRefKindsOpt != this.ArgumentRefKindsOpt || isDelegateCall != this.IsDelegateCall || expanded != this.Expanded || invokedAsExtensionMethod != this.InvokedAsExtensionMethod || argsToParamsOpt != this.ArgsToParamsOpt || resultKind != this.ResultKind || type != this.Type)
+ if (receiverOpt != this.ReceiverOpt || method != this.Method || arguments != this.Arguments || argumentNamesOpt != this.ArgumentNamesOpt || argumentRefKindsOpt != this.ArgumentRefKindsOpt || isDelegateCall != this.IsDelegateCall || expanded != this.Expanded || invokedAsExtensionMethod != this.InvokedAsExtensionMethod || argsToParamsOpt != this.ArgsToParamsOpt || resultKind != this.ResultKind || binderOpt != this.BinderOpt || type != this.Type)
{
- var result = new BoundCall(this.Syntax, receiverOpt, method, arguments, argumentNamesOpt, argumentRefKindsOpt, isDelegateCall, expanded, invokedAsExtensionMethod, argsToParamsOpt, resultKind, type, this.HasErrors);
+ var result = new BoundCall(this.Syntax, receiverOpt, method, arguments, argumentNamesOpt, argumentRefKindsOpt, isDelegateCall, expanded, invokedAsExtensionMethod, argsToParamsOpt, resultKind, binderOpt, type, this.HasErrors);
result.WasCompilerGenerated = this.WasCompilerGenerated;
return result;
}
@@ -4505,7 +4508,7 @@ public BoundAttribute Update(MethodSymbol constructor, ImmutableArray constructorsGroup, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool expanded, ImmutableArray argsToParamsOpt, ConstantValue constantValueOpt, BoundExpression initializerExpressionOpt, TypeSymbol type, bool hasErrors = false)
+ public BoundObjectCreationExpression(SyntaxNode syntax, MethodSymbol constructor, ImmutableArray constructorsGroup, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool expanded, ImmutableArray argsToParamsOpt, ConstantValue constantValueOpt, BoundExpression initializerExpressionOpt, Binder binderOpt, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.ObjectCreationExpression, syntax, type, hasErrors || arguments.HasErrors() || initializerExpressionOpt.HasErrors())
{
@@ -4523,6 +4526,7 @@ public BoundObjectCreationExpression(SyntaxNode syntax, MethodSymbol constructor
this.ArgsToParamsOpt = argsToParamsOpt;
this.ConstantValueOpt = constantValueOpt;
this.InitializerExpressionOpt = initializerExpressionOpt;
+ this.BinderOpt = binderOpt;
}
@@ -4544,16 +4548,18 @@ public BoundObjectCreationExpression(SyntaxNode syntax, MethodSymbol constructor
public BoundExpression InitializerExpressionOpt { get; }
+ public Binder BinderOpt { get; }
+
public override BoundNode Accept(BoundTreeVisitor visitor)
{
return visitor.VisitObjectCreationExpression(this);
}
- public BoundObjectCreationExpression Update(MethodSymbol constructor, ImmutableArray constructorsGroup, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool expanded, ImmutableArray argsToParamsOpt, ConstantValue constantValueOpt, BoundExpression initializerExpressionOpt, TypeSymbol type)
+ public BoundObjectCreationExpression Update(MethodSymbol constructor, ImmutableArray constructorsGroup, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool expanded, ImmutableArray argsToParamsOpt, ConstantValue constantValueOpt, BoundExpression initializerExpressionOpt, Binder binderOpt, TypeSymbol type)
{
- if (constructor != this.Constructor || constructorsGroup != this.ConstructorsGroup || arguments != this.Arguments || argumentNamesOpt != this.ArgumentNamesOpt || argumentRefKindsOpt != this.ArgumentRefKindsOpt || expanded != this.Expanded || argsToParamsOpt != this.ArgsToParamsOpt || constantValueOpt != this.ConstantValueOpt || initializerExpressionOpt != this.InitializerExpressionOpt || type != this.Type)
+ if (constructor != this.Constructor || constructorsGroup != this.ConstructorsGroup || arguments != this.Arguments || argumentNamesOpt != this.ArgumentNamesOpt || argumentRefKindsOpt != this.ArgumentRefKindsOpt || expanded != this.Expanded || argsToParamsOpt != this.ArgsToParamsOpt || constantValueOpt != this.ConstantValueOpt || initializerExpressionOpt != this.InitializerExpressionOpt || binderOpt != this.BinderOpt || type != this.Type)
{
- var result = new BoundObjectCreationExpression(this.Syntax, constructor, constructorsGroup, arguments, argumentNamesOpt, argumentRefKindsOpt, expanded, argsToParamsOpt, constantValueOpt, initializerExpressionOpt, type, this.HasErrors);
+ var result = new BoundObjectCreationExpression(this.Syntax, constructor, constructorsGroup, arguments, argumentNamesOpt, argumentRefKindsOpt, expanded, argsToParamsOpt, constantValueOpt, initializerExpressionOpt, binderOpt, type, this.HasErrors);
result.WasCompilerGenerated = this.WasCompilerGenerated;
return result;
}
@@ -5418,7 +5424,7 @@ public BoundEventAccess Update(BoundExpression receiverOpt, EventSymbol eventSym
internal sealed partial class BoundIndexerAccess : BoundExpression
{
- public BoundIndexerAccess(SyntaxNode syntax, BoundExpression receiverOpt, PropertySymbol indexer, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool expanded, ImmutableArray argsToParamsOpt, TypeSymbol type, bool hasErrors = false)
+ public BoundIndexerAccess(SyntaxNode syntax, BoundExpression receiverOpt, PropertySymbol indexer, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool expanded, ImmutableArray argsToParamsOpt, Binder binderOpt, bool useSetterForDefaultArgumentGeneration, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.IndexerAccess, syntax, type, hasErrors || receiverOpt.HasErrors() || arguments.HasErrors())
{
@@ -5433,6 +5439,8 @@ public BoundIndexerAccess(SyntaxNode syntax, BoundExpression receiverOpt, Proper
this.ArgumentRefKindsOpt = argumentRefKindsOpt;
this.Expanded = expanded;
this.ArgsToParamsOpt = argsToParamsOpt;
+ this.BinderOpt = binderOpt;
+ this.UseSetterForDefaultArgumentGeneration = useSetterForDefaultArgumentGeneration;
}
@@ -5450,16 +5458,20 @@ public BoundIndexerAccess(SyntaxNode syntax, BoundExpression receiverOpt, Proper
public ImmutableArray ArgsToParamsOpt { get; }
+ public Binder BinderOpt { get; }
+
+ public bool UseSetterForDefaultArgumentGeneration { get; }
+
public override BoundNode Accept(BoundTreeVisitor visitor)
{
return visitor.VisitIndexerAccess(this);
}
- public BoundIndexerAccess Update(BoundExpression receiverOpt, PropertySymbol indexer, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool expanded, ImmutableArray argsToParamsOpt, TypeSymbol type)
+ public BoundIndexerAccess Update(BoundExpression receiverOpt, PropertySymbol indexer, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, bool expanded, ImmutableArray argsToParamsOpt, Binder binderOpt, bool useSetterForDefaultArgumentGeneration, TypeSymbol type)
{
- if (receiverOpt != this.ReceiverOpt || indexer != this.Indexer || arguments != this.Arguments || argumentNamesOpt != this.ArgumentNamesOpt || argumentRefKindsOpt != this.ArgumentRefKindsOpt || expanded != this.Expanded || argsToParamsOpt != this.ArgsToParamsOpt || type != this.Type)
+ if (receiverOpt != this.ReceiverOpt || indexer != this.Indexer || arguments != this.Arguments || argumentNamesOpt != this.ArgumentNamesOpt || argumentRefKindsOpt != this.ArgumentRefKindsOpt || expanded != this.Expanded || argsToParamsOpt != this.ArgsToParamsOpt || binderOpt != this.BinderOpt || useSetterForDefaultArgumentGeneration != this.UseSetterForDefaultArgumentGeneration || type != this.Type)
{
- var result = new BoundIndexerAccess(this.Syntax, receiverOpt, indexer, arguments, argumentNamesOpt, argumentRefKindsOpt, expanded, argsToParamsOpt, type, this.HasErrors);
+ var result = new BoundIndexerAccess(this.Syntax, receiverOpt, indexer, arguments, argumentNamesOpt, argumentRefKindsOpt, expanded, argsToParamsOpt, binderOpt, useSetterForDefaultArgumentGeneration, type, this.HasErrors);
result.WasCompilerGenerated = this.WasCompilerGenerated;
return result;
}
@@ -8964,7 +8976,7 @@ public override BoundNode VisitCall(BoundCall node)
BoundExpression receiverOpt = (BoundExpression)this.Visit(node.ReceiverOpt);
ImmutableArray arguments = (ImmutableArray)this.VisitList(node.Arguments);
TypeSymbol type = this.VisitType(node.Type);
- return node.Update(receiverOpt, node.Method, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.IsDelegateCall, node.Expanded, node.InvokedAsExtensionMethod, node.ArgsToParamsOpt, node.ResultKind, type);
+ return node.Update(receiverOpt, node.Method, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.IsDelegateCall, node.Expanded, node.InvokedAsExtensionMethod, node.ArgsToParamsOpt, node.ResultKind, node.BinderOpt, type);
}
public override BoundNode VisitEventAssignmentOperator(BoundEventAssignmentOperator node)
{
@@ -8985,7 +8997,7 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre
ImmutableArray arguments = (ImmutableArray)this.VisitList(node.Arguments);
BoundExpression initializerExpressionOpt = (BoundExpression)this.Visit(node.InitializerExpressionOpt);
TypeSymbol type = this.VisitType(node.Type);
- return node.Update(node.Constructor, node.ConstructorsGroup, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.ConstantValueOpt, initializerExpressionOpt, type);
+ return node.Update(node.Constructor, node.ConstructorsGroup, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.ConstantValueOpt, initializerExpressionOpt, node.BinderOpt, type);
}
public override BoundNode VisitTupleLiteral(BoundTupleLiteral node)
{
@@ -9124,7 +9136,7 @@ public override BoundNode VisitIndexerAccess(BoundIndexerAccess node)
BoundExpression receiverOpt = (BoundExpression)this.Visit(node.ReceiverOpt);
ImmutableArray arguments = (ImmutableArray)this.VisitList(node.Arguments);
TypeSymbol type = this.VisitType(node.Type);
- return node.Update(receiverOpt, node.Indexer, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, type);
+ return node.Update(receiverOpt, node.Indexer, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.BinderOpt, node.UseSetterForDefaultArgumentGeneration, type);
}
public override BoundNode VisitDynamicIndexerAccess(BoundDynamicIndexerAccess node)
{
@@ -10313,6 +10325,7 @@ public override TreeDumperNode VisitCall(BoundCall node, object arg)
new TreeDumperNode("invokedAsExtensionMethod", node.InvokedAsExtensionMethod, null),
new TreeDumperNode("argsToParamsOpt", node.ArgsToParamsOpt, null),
new TreeDumperNode("resultKind", node.ResultKind, null),
+ new TreeDumperNode("binderOpt", node.BinderOpt, null),
new TreeDumperNode("type", node.Type, null)
}
);
@@ -10356,6 +10369,7 @@ public override TreeDumperNode VisitObjectCreationExpression(BoundObjectCreation
new TreeDumperNode("argsToParamsOpt", node.ArgsToParamsOpt, null),
new TreeDumperNode("constantValueOpt", node.ConstantValueOpt, null),
new TreeDumperNode("initializerExpressionOpt", null, new TreeDumperNode[] { Visit(node.InitializerExpressionOpt, null) }),
+ new TreeDumperNode("binderOpt", node.BinderOpt, null),
new TreeDumperNode("type", node.Type, null)
}
);
@@ -10602,6 +10616,8 @@ public override TreeDumperNode VisitIndexerAccess(BoundIndexerAccess node, objec
new TreeDumperNode("argumentRefKindsOpt", node.ArgumentRefKindsOpt, null),
new TreeDumperNode("expanded", node.Expanded, null),
new TreeDumperNode("argsToParamsOpt", node.ArgsToParamsOpt, null),
+ new TreeDumperNode("binderOpt", node.BinderOpt, null),
+ new TreeDumperNode("useSetterForDefaultArgumentGeneration", node.UseSetterForDefaultArgumentGeneration, null),
new TreeDumperNode("type", node.Type, null)
}
);
diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs
index 5b9c0b56eafd2..dc56bc050b763 100644
--- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs
@@ -1041,7 +1041,7 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre
Debug.Assert(node.InitializerExpressionOpt == null);
BoundSpillSequenceBuilder builder = null;
var arguments = this.VisitExpressionList(ref builder, node.Arguments, node.ArgumentRefKindsOpt);
- return UpdateExpression(builder, node.Update(node.Constructor, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.ConstantValueOpt, node.InitializerExpressionOpt, node.Type));
+ return UpdateExpression(builder, node.Update(node.Constructor, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.Expanded, node.ArgsToParamsOpt, node.ConstantValueOpt, node.InitializerExpressionOpt, node.BinderOpt, node.Type));
}
public override BoundNode VisitPointerElementAccess(BoundPointerElementAccess node)
diff --git a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DynamicAnalysisInjector.cs b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DynamicAnalysisInjector.cs
index e1c54b14d9174..c2c73ba4c85fa 100644
--- a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DynamicAnalysisInjector.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DynamicAnalysisInjector.cs
@@ -1,12 +1,13 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using Microsoft.CodeAnalysis.CodeGen;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.CSharp.Symbols;
-using Roslyn.Utilities;
using System.Collections.Immutable;
using System.Diagnostics;
-using System;
+using System.Linq;
+using Microsoft.Cci;
+using Microsoft.CodeAnalysis.CodeGen;
+using Microsoft.CodeAnalysis.Collections;
+using Microsoft.CodeAnalysis.CSharp.Symbols;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Microsoft.CodeAnalysis.CSharp
{
@@ -18,7 +19,8 @@ internal sealed class DynamicAnalysisInjector : CompoundInstrumenter
{
private readonly MethodSymbol _method;
private readonly BoundStatement _methodBody;
- private readonly MethodSymbol _createPayload;
+ private readonly MethodSymbol _createPayloadForMethodsSpanningSingleFile;
+ private readonly MethodSymbol _createPayloadForMethodsSpanningMultipleFiles;
private readonly ArrayBuilder _spansBuilder;
private ImmutableArray _dynamicAnalysisSpans = ImmutableArray.Empty;
private readonly BoundStatement _methodEntryInstrumentation;
@@ -28,7 +30,13 @@ internal sealed class DynamicAnalysisInjector : CompoundInstrumenter
private readonly DebugDocumentProvider _debugDocumentProvider;
private readonly SyntheticBoundNodeFactory _methodBodyFactory;
- public static DynamicAnalysisInjector TryCreate(MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory methodBodyFactory, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, Instrumenter previous)
+ public static DynamicAnalysisInjector TryCreate(
+ MethodSymbol method,
+ BoundStatement methodBody,
+ SyntheticBoundNodeFactory methodBodyFactory,
+ DiagnosticBag diagnostics,
+ DebugDocumentProvider debugDocumentProvider,
+ Instrumenter previous)
{
// Do not instrument implicitly-declared methods, except for constructors.
// Instrument implicit constructors in order to instrument member initializers.
@@ -43,28 +51,54 @@ public static DynamicAnalysisInjector TryCreate(MethodSymbol method, BoundStatem
return null;
}
- MethodSymbol createPayload = GetCreatePayload(methodBodyFactory.Compilation, methodBody.Syntax, diagnostics);
+ MethodSymbol createPayloadForMethodsSpanningSingleFile = GetCreatePayloadOverload(
+ methodBodyFactory.Compilation,
+ WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile,
+ methodBody.Syntax,
+ diagnostics);
+
+ MethodSymbol createPayloadForMethodsSpanningMultipleFiles = GetCreatePayloadOverload(
+ methodBodyFactory.Compilation,
+ WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningMultipleFiles,
+ methodBody.Syntax,
+ diagnostics);
// Do not instrument any methods if CreatePayload is not present.
- if ((object)createPayload == null)
+ if ((object)createPayloadForMethodsSpanningSingleFile == null || (object)createPayloadForMethodsSpanningMultipleFiles == null)
{
return null;
}
// Do not instrument CreatePayload if it is part of the current compilation (which occurs only during testing).
// CreatePayload will fail at run time with an infinite recursion if it is instrumented.
- if (method.Equals(createPayload))
+ if (method.Equals(createPayloadForMethodsSpanningSingleFile) || method.Equals(createPayloadForMethodsSpanningMultipleFiles))
{
return null;
}
- return new DynamicAnalysisInjector(method, methodBody, methodBodyFactory, createPayload, diagnostics, debugDocumentProvider, previous);
- }
-
- private DynamicAnalysisInjector(MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory methodBodyFactory, MethodSymbol createPayload, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, Instrumenter previous)
- : base(previous)
- {
- _createPayload = createPayload;
+ return new DynamicAnalysisInjector(
+ method,
+ methodBody,
+ methodBodyFactory,
+ createPayloadForMethodsSpanningSingleFile,
+ createPayloadForMethodsSpanningMultipleFiles,
+ diagnostics,
+ debugDocumentProvider,
+ previous);
+ }
+
+ private DynamicAnalysisInjector(
+ MethodSymbol method,
+ BoundStatement methodBody,
+ SyntheticBoundNodeFactory methodBodyFactory,
+ MethodSymbol createPayloadForMethodsSpanningSingleFile,
+ MethodSymbol createPayloadForMethodsSpanningMultipleFiles,
+ DiagnosticBag diagnostics,
+ DebugDocumentProvider debugDocumentProvider,
+ Instrumenter previous) : base(previous)
+ {
+ _createPayloadForMethodsSpanningSingleFile = createPayloadForMethodsSpanningSingleFile;
+ _createPayloadForMethodsSpanningMultipleFiles = createPayloadForMethodsSpanningMultipleFiles;
_method = method;
_methodBody = methodBody;
_spansBuilder = ArrayBuilder.GetInstance();
@@ -129,6 +163,78 @@ private static bool IsExcludedFromCodeCoverage(MethodSymbol method)
return false;
}
+ private static BoundExpressionStatement GetCreatePayloadStatement(
+ ImmutableArray dynamicAnalysisSpans,
+ SyntaxNode methodBodySyntax,
+ LocalSymbol methodPayload,
+ MethodSymbol createPayloadForMethodsSpanningSingleFile,
+ MethodSymbol createPayloadForMethodsSpanningMultipleFiles,
+ BoundExpression mvid,
+ BoundExpression methodToken,
+ BoundExpression payloadSlot,
+ SyntheticBoundNodeFactory methodBodyFactory,
+ DebugDocumentProvider debugDocumentProvider)
+ {
+ MethodSymbol createPayloadOverload;
+ BoundExpression fileIndexOrIndicesArgument;
+
+ if (dynamicAnalysisSpans.IsEmpty)
+ {
+ createPayloadOverload = createPayloadForMethodsSpanningSingleFile;
+
+ // For a compiler generated method that has no 'real' spans, we emit the index for
+ // the document corresponding to the syntax node that is associated with its bound node.
+ var document = GetSourceDocument(debugDocumentProvider, methodBodySyntax);
+ fileIndexOrIndicesArgument = methodBodyFactory.SourceDocumentIndex(document);
+ }
+ else
+ {
+ var documents = PooledHashSet.GetInstance();
+ var fileIndices = ArrayBuilder.GetInstance();
+
+ foreach (var span in dynamicAnalysisSpans)
+ {
+ var document = span.Document;
+ if (documents.Add(document))
+ {
+ fileIndices.Add(methodBodyFactory.SourceDocumentIndex(document));
+ }
+ }
+
+ documents.Free();
+
+ // At this point, we should have at least one document since we have already
+ // handled the case where method has no 'real' spans (and therefore no documents) above.
+ if (fileIndices.Count == 1)
+ {
+ createPayloadOverload = createPayloadForMethodsSpanningSingleFile;
+ fileIndexOrIndicesArgument = fileIndices.Single();
+ }
+ else
+ {
+ createPayloadOverload = createPayloadForMethodsSpanningMultipleFiles;
+
+ // Order of elements in fileIndices should be deterministic because these
+ // elements were added based on order of spans in dynamicAnalysisSpans above.
+ fileIndexOrIndicesArgument = methodBodyFactory.Array(
+ methodBodyFactory.SpecialType(SpecialType.System_Int32), fileIndices.ToImmutable());
+ }
+
+ fileIndices.Free();
+ }
+
+ return methodBodyFactory.Assignment(
+ methodBodyFactory.Local(methodPayload),
+ methodBodyFactory.Call(
+ null,
+ createPayloadOverload,
+ mvid,
+ methodToken,
+ fileIndexOrIndicesArgument,
+ payloadSlot,
+ methodBodyFactory.Literal(dynamicAnalysisSpans.Length)));
+ }
+
public override BoundStatement CreateBlockPrologue(BoundBlock original, out LocalSymbol synthesizedLocal)
{
BoundStatement previousPrologue = base.CreateBlockPrologue(original, out synthesizedLocal);
@@ -138,22 +244,50 @@ public override BoundStatement CreateBlockPrologue(BoundBlock original, out Loca
// In the future there will be multiple analysis kinds.
const int analysisKind = 0;
- ArrayTypeSymbol modulePayloadType = ArrayTypeSymbol.CreateCSharpArray(_methodBodyFactory.Compilation.Assembly, _payloadType);
+ ArrayTypeSymbol modulePayloadType =
+ ArrayTypeSymbol.CreateCSharpArray(_methodBodyFactory.Compilation.Assembly, _payloadType);
// Synthesize the initialization of the instrumentation payload array, using concurrency-safe code:
//
// var payload = PID.PayloadRootField[methodIndex];
// if (payload == null)
- // payload = Instrumentation.CreatePayload(mvid, methodIndex, fileIndex, ref PID.PayloadRootField[methodIndex], payloadLength);
+ // payload = Instrumentation.CreatePayload(mvid, methodIndex, fileIndexOrIndices, ref PID.PayloadRootField[methodIndex], payloadLength);
+
+ BoundStatement payloadInitialization =
+ _methodBodyFactory.Assignment(
+ _methodBodyFactory.Local(_methodPayload),
+ _methodBodyFactory.ArrayAccess(
+ _methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType),
+ ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method))));
- BoundStatement payloadInitialization = _methodBodyFactory.Assignment(_methodBodyFactory.Local(_methodPayload), _methodBodyFactory.ArrayAccess(_methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method))));
BoundExpression mvid = _methodBodyFactory.ModuleVersionId();
BoundExpression methodToken = _methodBodyFactory.MethodDefIndex(_method);
- BoundExpression fileIndex = _methodBodyFactory.SourceDocumentIndex(GetSourceDocument(_methodBody.Syntax));
- BoundExpression payloadSlot = _methodBodyFactory.ArrayAccess(_methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method)));
- BoundStatement createPayloadCall = _methodBodyFactory.Assignment(_methodBodyFactory.Local(_methodPayload), _methodBodyFactory.Call(null, _createPayload, mvid, methodToken, fileIndex, payloadSlot, _methodBodyFactory.Literal(_dynamicAnalysisSpans.Length)));
- BoundExpression payloadNullTest = _methodBodyFactory.Binary(BinaryOperatorKind.ObjectEqual, _methodBodyFactory.SpecialType(SpecialType.System_Boolean), _methodBodyFactory.Local(_methodPayload), _methodBodyFactory.Null(_payloadType));
+ BoundExpression payloadSlot =
+ _methodBodyFactory.ArrayAccess(
+ _methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType),
+ ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method)));
+
+ BoundStatement createPayloadCall =
+ GetCreatePayloadStatement(
+ _dynamicAnalysisSpans,
+ _methodBody.Syntax,
+ _methodPayload,
+ _createPayloadForMethodsSpanningSingleFile,
+ _createPayloadForMethodsSpanningMultipleFiles,
+ mvid,
+ methodToken,
+ payloadSlot,
+ _methodBodyFactory,
+ _debugDocumentProvider);
+
+ BoundExpression payloadNullTest =
+ _methodBodyFactory.Binary(
+ BinaryOperatorKind.ObjectEqual,
+ _methodBodyFactory.SpecialType(SpecialType.System_Boolean),
+ _methodBodyFactory.Local(_methodPayload),
+ _methodBodyFactory.Null(_payloadType));
+
BoundStatement payloadIf = _methodBodyFactory.If(payloadNullTest, createPayloadCall);
Debug.Assert(synthesizedLocal == null);
@@ -271,7 +405,7 @@ public override BoundStatement InstrumentReturnStatement(BoundReturnStatement or
return AddDynamicAnalysis(original, rewritten);
}
-
+
private static bool ReturnsValueWithinExpressionBodiedConstruct(BoundReturnStatement returnStatement)
{
if (returnStatement.WasCompilerGenerated &&
@@ -340,12 +474,12 @@ private BoundStatement CollectDynamicAnalysis(BoundStatement original, BoundStat
return statementFactory.StatementList(AddAnalysisPoint(SyntaxForSpan(original), statementFactory), rewritten);
}
- private Cci.DebugSourceDocument GetSourceDocument(SyntaxNode syntax)
+ private static Cci.DebugSourceDocument GetSourceDocument(DebugDocumentProvider debugDocumentProvider, SyntaxNode syntax)
{
- return GetSourceDocument(syntax, syntax.GetLocation().GetMappedLineSpan());
+ return GetSourceDocument(debugDocumentProvider, syntax, syntax.GetLocation().GetMappedLineSpan());
}
- private Cci.DebugSourceDocument GetSourceDocument(SyntaxNode syntax, FileLinePositionSpan span)
+ private static Cci.DebugSourceDocument GetSourceDocument(DebugDocumentProvider debugDocumentProvider, SyntaxNode syntax, FileLinePositionSpan span)
{
string path = span.Path;
// If the path for the syntax node is empty, try the path for the entire syntax tree.
@@ -354,7 +488,7 @@ private Cci.DebugSourceDocument GetSourceDocument(SyntaxNode syntax, FileLinePos
path = syntax.SyntaxTree.FilePath;
}
- return _debugDocumentProvider.Invoke(path, basePath: "");
+ return debugDocumentProvider.Invoke(path, basePath: "");
}
private BoundStatement AddAnalysisPoint(SyntaxNode syntaxForSpan, Text.TextSpan alternateSpan, SyntheticBoundNodeFactory statementFactory)
@@ -371,10 +505,19 @@ private BoundStatement AddAnalysisPoint(SyntaxNode syntaxForSpan, FileLinePositi
{
// Add an entry in the spans array.
int spansIndex = _spansBuilder.Count;
- _spansBuilder.Add(new SourceSpan(GetSourceDocument(syntaxForSpan, span), span.StartLinePosition.Line, span.StartLinePosition.Character, span.EndLinePosition.Line, span.EndLinePosition.Character));
+ _spansBuilder.Add(new SourceSpan(
+ GetSourceDocument(_debugDocumentProvider, syntaxForSpan, span),
+ span.StartLinePosition.Line,
+ span.StartLinePosition.Character,
+ span.EndLinePosition.Line,
+ span.EndLinePosition.Character));
// Generate "_payload[pointIndex] = true".
- BoundArrayAccess payloadCell = statementFactory.ArrayAccess(statementFactory.Local(_methodPayload), statementFactory.Literal(spansIndex));
+ BoundArrayAccess payloadCell =
+ statementFactory.ArrayAccess(
+ statementFactory.Local(_methodPayload),
+ statementFactory.Literal(spansIndex));
+
return statementFactory.Assignment(payloadCell, statementFactory.Literal(true));
}
@@ -421,10 +564,10 @@ private static SyntaxNode SyntaxForSpan(BoundStatement statement)
return syntaxForSpan;
}
-
- private static MethodSymbol GetCreatePayload(CSharpCompilation compilation, SyntaxNode syntax, DiagnosticBag diagnostics)
+
+ private static MethodSymbol GetCreatePayloadOverload(CSharpCompilation compilation, WellKnownMember overload, SyntaxNode syntax, DiagnosticBag diagnostics)
{
- return (MethodSymbol)Binder.GetWellKnownTypeMember(compilation, WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayload, diagnostics, syntax: syntax);
+ return (MethodSymbol)Binder.GetWellKnownTypeMember(compilation, overload, diagnostics, syntax: syntax);
}
private static SyntaxNode MethodDeclarationIfAvailable(SyntaxNode body)
@@ -478,7 +621,7 @@ private static Text.TextSpan SkipAttributes(SyntaxNode syntax)
return syntax.Span;
}
-
+
private static Text.TextSpan SkipAttributes(SyntaxNode syntax, SyntaxList attributes, SyntaxTokenList modifiers, SyntaxToken keyword, TypeSyntax type)
{
Text.TextSpan originalSpan = syntax.Span;
diff --git a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs
index 9830f0705377c..a592b8e77bb1d 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs
@@ -98,10 +98,10 @@ public MappedLocalFunction(SynthesizedLambdaMethod symbol, ClosureKind closureKi
// or the "this" parameter when at the top level. Keys in this map are never constructed types.
private readonly Dictionary _framePointers = new Dictionary();
- // True if the rewritten tree should include assignments of the
- // original locals to the lifted proxies. This is only useful for the
- // expression evaluator where the original locals are left as is.
- private readonly bool _assignLocals;
+ // The set of original locals that should be assigned to proxies
+ // if lifted. This is useful for the expression evaluator where
+ // the original locals are left as is.
+ private readonly HashSet _assignLocals;
// The current method or lambda being processed.
private MethodSymbol _currentMethod;
@@ -159,7 +159,7 @@ private LambdaRewriter(
VariableSlotAllocator slotAllocatorOpt,
TypeCompilationState compilationState,
DiagnosticBag diagnostics,
- bool assignLocals)
+ HashSet assignLocals)
: base(slotAllocatorOpt, compilationState, diagnostics)
{
Debug.Assert(analysis != null);
@@ -207,7 +207,7 @@ protected override bool NeedsProxy(Symbol localOrParameter)
/// Slot allocator.
/// The caller's buffer into which we produce additional methods to be emitted by the caller
/// Diagnostic bag for diagnostics
- /// The rewritten tree should include assignments of the original locals to the lifted proxies
+ /// The set of original locals that should be assigned to proxies if lifted
public static BoundStatement Rewrite(
BoundStatement loweredBody,
NamedTypeSymbol thisType,
@@ -220,7 +220,7 @@ public static BoundStatement Rewrite(
VariableSlotAllocator slotAllocatorOpt,
TypeCompilationState compilationState,
DiagnosticBag diagnostics,
- bool assignLocals)
+ HashSet assignLocals)
{
Debug.Assert((object)thisType != null);
Debug.Assert(((object)thisParameter == null) || (thisParameter.Type == thisType));
@@ -642,7 +642,7 @@ private BoundNode IntroduceFrame(BoundNode node, LambdaFrame frame, Func(SyntaxNode syntax, WellKnownMemb
///
/// This function provides a false sense of security, it is likely going to surprise you when the requested member is missing.
- /// Recommendation: Do not use, use instead!
+ /// Recommendation: Do not use, use instead!
/// If used, a unit-test with a missing member is absolutely a must have.
///
private MethodSymbol UnsafeGetSpecialTypeMethod(SyntaxNode syntax, SpecialMember specialMember)
+ {
+ return UnsafeGetSpecialTypeMethod(syntax, specialMember, _compilation, _diagnostics);
+ }
+
+ ///
+ /// This function provides a false sense of security, it is likely going to surprise you when the requested member is missing.
+ /// Recommendation: Do not use, use instead!
+ /// If used, a unit-test with a missing member is absolutely a must have.
+ ///
+ private static MethodSymbol UnsafeGetSpecialTypeMethod(SyntaxNode syntax, SpecialMember specialMember, CSharpCompilation compilation, DiagnosticBag diagnostics)
{
MethodSymbol method;
- if (TryGetSpecialTypeMethod(syntax, specialMember, out method))
+ if (TryGetSpecialTypeMethod(syntax, specialMember, compilation, diagnostics, out method))
{
return method;
}
@@ -329,15 +338,20 @@ private MethodSymbol UnsafeGetSpecialTypeMethod(SyntaxNode syntax, SpecialMember
{
MemberDescriptor descriptor = SpecialMembers.GetDescriptor(specialMember);
SpecialType type = (SpecialType)descriptor.DeclaringTypeId;
- TypeSymbol container = _compilation.Assembly.GetSpecialType(type);
- TypeSymbol returnType = new ExtendedErrorTypeSymbol(compilation: _compilation, name: descriptor.Name, errorInfo: null, arity: descriptor.Arity);
+ TypeSymbol container = compilation.Assembly.GetSpecialType(type);
+ TypeSymbol returnType = new ExtendedErrorTypeSymbol(compilation: compilation, name: descriptor.Name, errorInfo: null, arity: descriptor.Arity);
return new ErrorMethodSymbol(container, returnType, "Missing");
}
}
private bool TryGetSpecialTypeMethod(SyntaxNode syntax, SpecialMember specialMember, out MethodSymbol method)
{
- return Binder.TryGetSpecialTypeMember(_compilation, specialMember, syntax, _diagnostics, out method);
+ return TryGetSpecialTypeMethod(syntax, specialMember, _compilation, _diagnostics, out method);
+ }
+
+ private static bool TryGetSpecialTypeMethod(SyntaxNode syntax, SpecialMember specialMember, CSharpCompilation compilation, DiagnosticBag diagnostics, out MethodSymbol method)
+ {
+ return Binder.TryGetSpecialTypeMember(compilation, specialMember, syntax, diagnostics, out method);
}
public override BoundNode VisitTypeOfOperator(BoundTypeOfOperator node)
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AnonymousObjectCreation.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AnonymousObjectCreation.cs
index 03c4f0f2cb53b..58039e05a3874 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AnonymousObjectCreation.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AnonymousObjectCreation.cs
@@ -25,6 +25,7 @@ public override BoundNode VisitAnonymousObjectCreationExpression(BoundAnonymousO
argsToParamsOpt: default(ImmutableArray),
constantValueOpt: null,
initializerExpressionOpt: null,
+ binderOpt: null,
type: node.Type);
}
}
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
index 79f3e1e825424..8ec81d79de3d8 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
@@ -1195,6 +1195,7 @@ private BoundExpression MakeLiftedBinaryOperatorConsequence(
return new BoundObjectCreationExpression(
syntax,
UnsafeGetNullableMethod(syntax, type, SpecialMember.System_Nullable_T__ctor),
+ null,
unliftedOp);
}
@@ -1484,6 +1485,7 @@ private BoundExpression MakeNewNullableBoolean(SyntaxNode syntax, bool? value)
return new BoundObjectCreationExpression(
syntax,
UnsafeGetNullableMethod(syntax, nullableBoolType, SpecialMember.System_Nullable_T__ctor),
+ null,
MakeBooleanConstant(syntax, value.GetValueOrDefault()));
}
@@ -1719,10 +1721,20 @@ private BoundExpression LowerLiftedBooleanOperator(
/// If used, a unit-test with a missing member is absolutely a must have.
///
private MethodSymbol UnsafeGetNullableMethod(SyntaxNode syntax, TypeSymbol nullableType, SpecialMember member)
+ {
+ return UnsafeGetNullableMethod(syntax, nullableType, member, _compilation, _diagnostics);
+ }
+
+ ///
+ /// This function provides a false sense of security, it is likely going to surprise you when the requested member is missing.
+ /// Recommendation: Do not use, use instead!
+ /// If used, a unit-test with a missing member is absolutely a must have.
+ ///
+ private static MethodSymbol UnsafeGetNullableMethod(SyntaxNode syntax, TypeSymbol nullableType, SpecialMember member, CSharpCompilation compilation, DiagnosticBag diagnostics)
{
var nullableType2 = nullableType as NamedTypeSymbol;
Debug.Assert((object)nullableType2 != null);
- return UnsafeGetSpecialTypeMethod(syntax, member).AsMember(nullableType2);
+ return UnsafeGetSpecialTypeMethod(syntax, member, compilation, diagnostics).AsMember(nullableType2);
}
private bool TryGetNullableMethod(SyntaxNode syntax, TypeSymbol nullableType, SpecialMember member, out MethodSymbol result)
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs
index 3ee96a545797e..38463182dbd62 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs
@@ -1,12 +1,13 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
+using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Semantics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
@@ -223,6 +224,7 @@ private BoundExpression MakeCall(
invokedAsExtensionMethod: invokedAsExtensionMethod,
argsToParamsOpt: default(ImmutableArray),
resultKind: resultKind,
+ binderOpt: null,
type: type);
}
else
@@ -238,6 +240,7 @@ private BoundExpression MakeCall(
node.InvokedAsExtensionMethod,
default(ImmutableArray),
node.ResultKind,
+ node.BinderOpt,
node.Type);
}
@@ -385,39 +388,15 @@ private ImmutableArray MakeArguments(
//
// If none of those are the case then we can just take an early out.
- // An applicable "vararg" method could not possibly be applicable in its expanded
- // form, and cannot possibly have named arguments or used optional parameters,
- // because the __arglist() argument has to be positional and in the last position.
-
-
- if (methodOrIndexer.GetIsVararg())
- {
- Debug.Assert(rewrittenArguments.Length == methodOrIndexer.GetParameterCount() + 1);
- Debug.Assert(argsToParamsOpt.IsDefault);
- Debug.Assert(!expanded);
- temps = default(ImmutableArray);
- return rewrittenArguments;
- }
-
- var receiverNamedType = invokedAsExtensionMethod ?
- ((MethodSymbol)methodOrIndexer).Parameters[0].Type as NamedTypeSymbol :
- methodOrIndexer.ContainingType;
-
- bool isComReceiver = (object)receiverNamedType != null && receiverNamedType.IsComImport;
-
ArrayBuilder temporariesBuilder = ArrayBuilder.GetInstance();
rewrittenArguments = _factory.MakeTempsForDiscardArguments(rewrittenArguments, temporariesBuilder);
- if (rewrittenArguments.Length == methodOrIndexer.GetParameterCount() &&
- argsToParamsOpt.IsDefault &&
- !expanded &&
- !isComReceiver)
+ if (CanSkipRewriting(rewrittenArguments, methodOrIndexer, expanded, argsToParamsOpt, invokedAsExtensionMethod, out var isComReceiver))
{
temps = temporariesBuilder.ToImmutableAndFree();
return rewrittenArguments;
}
-
// We have:
// * a list of arguments, already converted to their proper types,
// in source code order. Some optional arguments might be missing.
@@ -512,6 +491,81 @@ private ImmutableArray MakeArguments(
return actualArguments.AsImmutableOrNull();
}
+ internal static ImmutableArray MakeArgumentsInEvaluationOrder(
+ Binder binder,
+ SyntaxNode syntax,
+ ImmutableArray arguments,
+ Symbol methodOrIndexer,
+ MethodSymbol optionalParametersMethod,
+ bool expanded,
+ ImmutableArray argsToParamsOpt,
+ bool invokedAsExtensionMethod)
+ {
+ Debug.Assert(binder != null);
+
+ // Either the methodOrIndexer is a property, in which case the method used
+ // for optional parameters is an accessor of that property (or an overridden
+ // property), or the methodOrIndexer is used for optional parameters directly.
+ Debug.Assert(((methodOrIndexer.Kind == SymbolKind.Property) && optionalParametersMethod.IsAccessor()) ||
+ (object)methodOrIndexer == optionalParametersMethod);
+
+ // We need to do a fancy rewrite under the following circumstances:
+ // (1) a params array is being used; we need to generate the array.
+ // (2) there were optional parameters that had no corresponding arguments.
+ //
+ // If neither of those are the case then we can just take an early out.
+
+
+ if (CanSkipRewriting(arguments, methodOrIndexer, expanded, argsToParamsOpt, invokedAsExtensionMethod, out var isComReceiver))
+ {
+ // In this case, the invocation is not in expanded form and there's no named argument provided.
+ // So we just return list of arguments as is.
+ return arguments.ZipAsArray(methodOrIndexer.GetParameters(), (a, p) => BoundCall.CreateArgumentOperation(ArgumentKind.Explicit, p, a));
+ }
+
+ return BuildArgumentsInEvaluationOrder(syntax,
+ methodOrIndexer,
+ optionalParametersMethod,
+ expanded,
+ argsToParamsOpt,
+ arguments,
+ binder);
+ }
+
+ // temporariesBuilder will be null when factory is null.
+ private static bool CanSkipRewriting(
+ ImmutableArray rewrittenArguments,
+ Symbol methodOrIndexer,
+ bool expanded,
+ ImmutableArray argsToParamsOpt,
+ bool invokedAsExtensionMethod,
+ out bool isComReceiver)
+ {
+ // An applicable "vararg" method could not possibly be applicable in its expanded
+ // form, and cannot possibly have named arguments or used optional parameters,
+ // because the __arglist() argument has to be positional and in the last position.
+
+ if (methodOrIndexer.GetIsVararg())
+ {
+ Debug.Assert(rewrittenArguments.Length == methodOrIndexer.GetParameterCount() + 1);
+ Debug.Assert(argsToParamsOpt.IsDefault);
+ Debug.Assert(!expanded);
+ isComReceiver = false;
+ return true;
+ }
+
+ var receiverNamedType = invokedAsExtensionMethod ?
+ ((MethodSymbol)methodOrIndexer).Parameters[0].Type as NamedTypeSymbol :
+ methodOrIndexer.ContainingType;
+
+ isComReceiver = (object)receiverNamedType != null && receiverNamedType.IsComImport;
+
+ return rewrittenArguments.Length == methodOrIndexer.GetParameterCount() &&
+ argsToParamsOpt.IsDefault &&
+ !expanded &&
+ !isComReceiver;
+ }
+
private static ImmutableArray GetRefKindsOrNull(ArrayBuilder refKinds)
{
foreach (var refKind in refKinds)
@@ -544,44 +598,32 @@ private void BuildStoresToTemps(
RefKind refKind = argumentRefKinds.RefKinds(a);
Debug.Assert(arguments[p] == null);
- if (expanded && p == arguments.Length - 1)
+ // Unfortunately, we violate the specification and allow:
+ // M(int q, params int[] x) ... M(x : X(), q : Q());
+ // which means that we cannot bail out just because
+ // an argument of an expanded-form call corresponds to
+ // the parameter array. We need to make sure that the
+ // side effects of X() and Q() continue to happen in the right
+ // order here.
+ //
+ // Fortunately, we do disallow M(x : 123, x : 345, x : 456).
+ //
+ // Here's what we'll do. If all the remaining arguments
+ // correspond to elements in the parameter array then
+ // we can bail out here without creating any temporaries.
+ // The next step in the call rewriter will deal with gathering
+ // up the elements.
+ //
+ // However, if there are other elements after this one
+ // that do not correspond to elements in the parameter array
+ // then we need to create a temporary as usual. The step that
+ // produces the parameter array will need to deal with that
+ // eventuality.
+
+ if (IsBeginningOfParamArray(p, a, expanded, arguments.Length, rewrittenArguments, argsToParamsOpt, out int paramArrayArgumentCount)
+ && a + paramArrayArgumentCount == rewrittenArguments.Length)
{
- // Unfortunately, we violate the specification and allow:
- // M(int q, params int[] x) ... M(x : X(), q : Q());
- // which means that we cannot bail out just because
- // an argument of an expanded-form call corresponds to
- // the parameter array. We need to make sure that the
- // side effects of X() and Q() continue to happen in the right
- // order here.
- //
- // Fortunately, we do disallow M(x : 123, x : 345, x : 456).
- //
- // Here's what we'll do. If all the remaining arguments
- // correspond to elements in the parameter array then
- // we can bail out here without creating any temporaries.
- // The next step in the call rewriter will deal with gathering
- // up the elements.
- //
- // However, if there are other elements after this one
- // that do not correspond to elements in the parameter array
- // then we need to create a temporary as usual. The step that
- // produces the parameter array will need to deal with that
- // eventuality.
-
- bool canBail = true;
- for (int remainingArgument = a + 1; remainingArgument < rewrittenArguments.Length; ++remainingArgument)
- {
- int remainingParameter = (!argsToParamsOpt.IsDefault) ? argsToParamsOpt[remainingArgument] : remainingArgument;
- if (remainingParameter != arguments.Length - 1)
- {
- canBail = false;
- break;
- }
- }
- if (canBail)
- {
- return;
- }
+ return;
}
if (IsSafeForReordering(argument, refKind))
@@ -599,6 +641,111 @@ private void BuildStoresToTemps(
}
}
+ // This fills in the arguments and parameters arrays in evaluation order.
+ private static ImmutableArray BuildArgumentsInEvaluationOrder(
+ SyntaxNode syntax,
+ Symbol methodOrIndexer,
+ MethodSymbol optionalParametersMethod,
+ bool expanded,
+ ImmutableArray argsToParamsOpt,
+ ImmutableArray arguments,
+ Binder binder)
+ {
+ ImmutableArray parameters = methodOrIndexer.GetParameters();
+
+ ArrayBuilder argumentsInEvaluationBuilder = ArrayBuilder.GetInstance(parameters.Length);
+
+ PooledHashSet processedParameters = PooledHashSet.GetInstance();
+
+ // First, fill in all the explicitly provided arguments.
+ for (int a = 0; a < arguments.Length; ++a)
+ {
+ BoundExpression argument = arguments[a];
+
+ int p = (!argsToParamsOpt.IsDefault) ? argsToParamsOpt[a] : a;
+ var parameter = parameters[p];
+
+ Debug.Assert(!processedParameters.Contains(p));
+
+ processedParameters.Add(p);
+
+ ArgumentKind kind = ArgumentKind.Explicit;
+
+ if (IsBeginningOfParamArray(p, a, expanded, parameters.Length, arguments, argsToParamsOpt, out int paramArrayArgumentCount))
+ {
+ int firstNonParamArrayArgumentIndex = a + paramArrayArgumentCount;
+ Debug.Assert(firstNonParamArrayArgumentIndex <= arguments.Length);
+
+ kind = ArgumentKind.ParamArray;
+ ArrayBuilder paramArray = ArrayBuilder.GetInstance(paramArrayArgumentCount);
+
+ for (int i = a; i < firstNonParamArrayArgumentIndex; ++i)
+ {
+ paramArray.Add(arguments[i]);
+ }
+
+ // Set loop variable so the value for next iteration will be the index of the first non param-array argument after param-array argument(s).
+ a = firstNonParamArrayArgumentIndex - 1;
+
+ argument = CreateParamArrayArgument(syntax, parameter.Type, paramArray.ToImmutableAndFree(), null, binder);
+ }
+
+ argumentsInEvaluationBuilder.Add(BoundCall.CreateArgumentOperation(kind, parameter, argument));
+ }
+
+ // Collect parameters with missing arguments.
+ ArrayBuilder missingParametersBuilder = ArrayBuilder.GetInstance(parameters.Length);
+ for (int i = 0; i < parameters.Length; ++i)
+ {
+ if (!processedParameters.Contains(i))
+ {
+ missingParametersBuilder.Add(parameters[i]);
+ }
+ }
+
+ processedParameters.Free();
+
+ // Finally, append default value as arguments.
+ AppendMissingOptionalArguments(syntax, methodOrIndexer, optionalParametersMethod, expanded, binder, missingParametersBuilder, argumentsInEvaluationBuilder);
+
+ missingParametersBuilder.Free();
+
+ return argumentsInEvaluationBuilder.ToImmutableAndFree();
+ }
+
+ ///
+ /// Returns true if the given argument is the begining of a list of param array arguments (could be empty), otherwise returns false.
+ /// When returns true, numberOfParamArrayArguments is set to the number of param array arguments.
+ ///
+ private static bool IsBeginningOfParamArray(
+ int parameterIndex,
+ int argumentIndex,
+ bool expanded,
+ int parameterCount,
+ ImmutableArray arguments,
+ ImmutableArray argsToParamsOpt,
+ out int numberOfParamArrayArguments)
+ {
+ numberOfParamArrayArguments = 0;
+
+ if (expanded && parameterIndex == parameterCount - 1)
+ {
+ int remainingArgument = argumentIndex + 1;
+ for (; remainingArgument < arguments.Length; ++remainingArgument)
+ {
+ int remainingParameter = (!argsToParamsOpt.IsDefault) ? argsToParamsOpt[remainingArgument] : remainingArgument;
+ if (remainingParameter != parameterCount - 1)
+ {
+ break;
+ }
+ }
+ numberOfParamArrayArguments = remainingArgument - argumentIndex;
+ return true;
+ }
+
+ return false;
+ }
+
private BoundExpression BuildParamsArray(
SyntaxNode syntax,
Symbol methodOrIndexer,
@@ -659,21 +806,48 @@ private BoundExpression BuildParamsArray(
invokedAsExtensionMethod: false,
argsToParamsOpt: default(ImmutableArray),
resultKind: LookupResultKind.Viable,
+ binderOpt: null,
type: arrayEmpty.ReturnType);
}
}
}
- var int32Type = methodOrIndexer.ContainingAssembly.GetPrimitiveType(Microsoft.Cci.PrimitiveTypeCode.Int32);
+ return CreateParamArrayArgument(syntax, paramArrayType, arrayArgs, this, null);
+ }
+
+ private static BoundExpression CreateParamArrayArgument(SyntaxNode syntax,
+ TypeSymbol paramArrayType,
+ ImmutableArray arrayArgs,
+ LocalRewriter localRewriter,
+ Binder binder)
+ {
+ Debug.Assert(localRewriter == null ^ binder == null);
+
+ TypeSymbol int32Type = (localRewriter != null ? localRewriter._compilation : binder.Compilation).GetSpecialType(SpecialType.System_Int32);
+ BoundExpression arraySize = MakeLiteral(syntax, ConstantValue.Create(arrayArgs.Length), int32Type, localRewriter);
return new BoundArrayCreation(
syntax,
- ImmutableArray.Create(
- MakeLiteral(syntax, ConstantValue.Create(arrayArgs.Length), int32Type)),
+ ImmutableArray.Create(arraySize),
new BoundArrayInitialization(syntax, arrayArgs),
paramArrayType);
}
+ ///
+ /// To create literal expression for IOperation, set localRewriter to null.
+ ///
+ private static BoundExpression MakeLiteral(SyntaxNode syntax, ConstantValue constantValue, TypeSymbol type, LocalRewriter localRewriter)
+ {
+ if (localRewriter != null)
+ {
+ return localRewriter.MakeLiteral(syntax, constantValue, type);
+ }
+ else
+ {
+ return new BoundLiteral(syntax, constantValue, type, constantValue.IsBad);
+ }
+ }
+
private static void OptimizeTemporaries(
BoundExpression[] arguments,
ArrayBuilder refKinds,
@@ -820,6 +994,56 @@ private void InsertMissingOptionalArguments(SyntaxNode syntax,
}
}
+ private static void AppendMissingOptionalArguments(SyntaxNode syntax,
+ Symbol methodOrIndexer,
+ MethodSymbol optionalParametersMethod,
+ bool expanded,
+ Binder binder,
+ ArrayBuilder missingParameters,
+ ArrayBuilder argumentsBuilder)
+ {
+ ImmutableArray parameters = methodOrIndexer.GetParameters();
+ ImmutableArray parametersOfOptionalParametersMethod = optionalParametersMethod.Parameters;
+
+ foreach (ParameterSymbol parameter in missingParameters)
+ {
+ BoundExpression argument;
+ ArgumentKind kind;
+
+ // In case of indexer access, missing parameters are corresponding to the indexer symbol, we need to
+ // get default values based on actual accessor method parameter symbols (but still want to tie resulted IArgument
+ // to the indexer parameter.)
+ ParameterSymbol parameterOfOptionalParametersMethod = parametersOfOptionalParametersMethod[parameter.Ordinal];
+
+ if (expanded && parameterOfOptionalParametersMethod.Ordinal == parameters.Length - 1)
+ {
+ Debug.Assert(parameterOfOptionalParametersMethod.IsParams);
+
+ // Create an empty array for omitted param array argument.
+ argument = CreateParamArrayArgument(syntax, parameterOfOptionalParametersMethod.Type, ImmutableArray.Empty, null, binder);
+ kind = ArgumentKind.ParamArray;
+ }
+ else
+ {
+ Debug.Assert(parameterOfOptionalParametersMethod.IsOptional);
+
+ var unusedDiagnostics = DiagnosticBag.GetInstance();
+
+ argument = GetDefaultParameterValue(syntax,
+ parameterOfOptionalParametersMethod,
+ enableCallerInfo: ThreeState.Unknown,
+ localRewriter: null,
+ binder: binder,
+ diagnostics: unusedDiagnostics);
+ kind = ArgumentKind.DefaultValue;
+
+ unusedDiagnostics.Free();
+ }
+
+ argumentsBuilder.Add(BoundCall.CreateArgumentOperation(kind, parameter, argument));
+ }
+ }
+
private static SourceLocation GetCallerLocation(SyntaxNode syntax, ThreeState enableCallerInfo)
{
switch (enableCallerInfo)
@@ -878,9 +1102,43 @@ private static SourceLocation GetCallerLocation(SyntaxNode syntax, ThreeState en
/// we will provide caller information as a value of this parameter.
/// This is done to match the native compiler behavior and user requests (see http://roslyn.codeplex.com/workitem/171). This behavior
/// does not match the C# spec that currently requires to provide caller information only in explicit invocations and query expressions.
- ///
+ ///
private BoundExpression GetDefaultParameterValue(SyntaxNode syntax, ParameterSymbol parameter, ThreeState enableCallerInfo)
{
+ return GetDefaultParameterValue(syntax, parameter, enableCallerInfo, this, null, this._diagnostics);
+ }
+
+ ///
+ /// This helper is used by both LocalRewriter and IOperation.
+ /// - For lowering, 'localRewriter' must be passed in as an argument, and set 'binder' and 'diagnostics' to null.
+ /// - For deriving argument expression for IArgument operation, 'localRewriter' must be null, and 'compilation', 'diagnostics'
+ /// must be passed in, where 'callerMemberName' must not be null if 'parameter.IsCallerMemberName' is 'true'.
+ ///
+ private static BoundExpression GetDefaultParameterValue(
+ SyntaxNode syntax,
+ ParameterSymbol parameter,
+ ThreeState enableCallerInfo,
+ LocalRewriter localRewriter,
+ Binder binder,
+ DiagnosticBag diagnostics)
+ {
+ Debug.Assert(localRewriter == null ^ binder == null);
+ Debug.Assert(diagnostics != null);
+
+ bool isLowering;
+ CSharpCompilation compilation;
+
+ if (localRewriter != null)
+ {
+ isLowering = true;
+ compilation = localRewriter._compilation;
+ }
+ else
+ {
+ isLowering = false;
+ compilation = binder.Compilation;
+ }
+
// TODO: Ideally, the enableCallerInfo parameter would be of just bool type with only 'true' and 'false' values, and all callers
// explicitly provided one of those values, so that we do not rely on shape of syntax nodes in the rewriter. There are not many immediate callers,
// but often the immediate caller does not have the required information, so all possible call chains should be analyzed and possibly updated
@@ -893,8 +1151,9 @@ private BoundExpression GetDefaultParameterValue(SyntaxNode syntax, ParameterSym
SourceLocation callerSourceLocation;
// For compatibility with the native compiler we treat all bad imported constant
- // values as default(T).
- if (defaultConstantValue != null && defaultConstantValue.IsBad)
+ // values as default(T). However, we don't do this for IOperation purpose, in which case
+ // we will expose the bad node.
+ if (defaultConstantValue != null && defaultConstantValue.IsBad && isLowering)
{
defaultConstantValue = ConstantValue.Null;
}
@@ -902,94 +1161,107 @@ private BoundExpression GetDefaultParameterValue(SyntaxNode syntax, ParameterSym
if (parameter.IsCallerLineNumber && ((callerSourceLocation = GetCallerLocation(syntax, enableCallerInfo)) != null))
{
int line = callerSourceLocation.SourceTree.GetDisplayLineNumber(callerSourceLocation.SourceSpan);
- BoundExpression lineLiteral = MakeLiteral(syntax, ConstantValue.Create(line), _compilation.GetSpecialType(SpecialType.System_Int32));
+
+ BoundExpression lineLiteral = MakeLiteral(syntax, ConstantValue.Create(line), compilation.GetSpecialType(SpecialType.System_Int32), localRewriter);
if (parameterType.IsNullableType())
{
- defaultValue = MakeConversionNode(lineLiteral, parameterType.GetNullableUnderlyingType(), false);
+ TypeSymbol nullableType = parameterType.GetNullableUnderlyingType();
+ defaultValue = MakeConversionNode(lineLiteral, nullableType, @checked: false);
// wrap it in a nullable ctor.
defaultValue = new BoundObjectCreationExpression(
syntax,
- UnsafeGetNullableMethod(syntax, parameterType, SpecialMember.System_Nullable_T__ctor),
+ UnsafeGetNullableMethod(syntax, parameterType, SpecialMember.System_Nullable_T__ctor, compilation, diagnostics),
+ null,
defaultValue);
}
else
{
- defaultValue = MakeConversionNode(lineLiteral, parameterType, false);
- }
+ defaultValue = MakeConversionNode(lineLiteral, parameterType, @checked: false);
+ }
}
else if (parameter.IsCallerFilePath && ((callerSourceLocation = GetCallerLocation(syntax, enableCallerInfo)) != null))
{
- string path = callerSourceLocation.SourceTree.GetDisplayPath(callerSourceLocation.SourceSpan, _compilation.Options.SourceReferenceResolver);
- BoundExpression memberNameLiteral = MakeLiteral(syntax, ConstantValue.Create(path), _compilation.GetSpecialType(SpecialType.System_String));
- defaultValue = MakeConversionNode(memberNameLiteral, parameterType, false);
+ string path = callerSourceLocation.SourceTree.GetDisplayPath(callerSourceLocation.SourceSpan, compilation.Options.SourceReferenceResolver);
+ BoundExpression memberNameLiteral = MakeLiteral(syntax, ConstantValue.Create(path), compilation.GetSpecialType(SpecialType.System_String), localRewriter);
+ defaultValue = MakeConversionNode(memberNameLiteral, parameterType, @checked: false);
}
else if (parameter.IsCallerMemberName && ((callerSourceLocation = GetCallerLocation(syntax, enableCallerInfo)) != null))
{
string memberName;
- switch (_factory.TopLevelMethod.MethodKind)
+ if (isLowering)
{
- case MethodKind.Constructor:
- case MethodKind.StaticConstructor:
- // See if the code is actually part of a field, field-like event or property initializer and return the name of the corresponding member.
- var memberDecl = syntax.Ancestors().OfType().FirstOrDefault();
-
- if (memberDecl != null)
- {
- BaseFieldDeclarationSyntax fieldDecl;
-
- if (memberDecl.Kind() == SyntaxKind.PropertyDeclaration)
- {
- var propDecl = (PropertyDeclarationSyntax)memberDecl;
- EqualsValueClauseSyntax initializer = propDecl.Initializer;
+ MethodSymbol topLevelMethod = localRewriter._factory.TopLevelMethod;
+ switch (topLevelMethod.MethodKind)
+ {
+ case MethodKind.Constructor:
+ case MethodKind.StaticConstructor:
+ // See if the code is actually part of a field, field-like event or property initializer and return the name of the corresponding member.
+ var memberDecl = syntax.Ancestors().OfType().FirstOrDefault();
- if (initializer != null && initializer.Span.Contains(syntax.Span))
- {
- memberName = propDecl.Identifier.ValueText;
- break;
- }
- }
- else if ((fieldDecl = memberDecl as BaseFieldDeclarationSyntax) != null)
+ if (memberDecl != null)
{
- memberName = null;
+ BaseFieldDeclarationSyntax fieldDecl;
- foreach (VariableDeclaratorSyntax varDecl in fieldDecl.Declaration.Variables)
+ if (memberDecl.Kind() == SyntaxKind.PropertyDeclaration)
{
- EqualsValueClauseSyntax initializer = varDecl.Initializer;
+ var propDecl = (PropertyDeclarationSyntax)memberDecl;
+ EqualsValueClauseSyntax initializer = propDecl.Initializer;
if (initializer != null && initializer.Span.Contains(syntax.Span))
{
- memberName = varDecl.Identifier.ValueText;
+ memberName = propDecl.Identifier.ValueText;
break;
}
}
-
- if (memberName != null)
+ else if ((fieldDecl = memberDecl as BaseFieldDeclarationSyntax) != null)
{
- break;
+ memberName = null;
+
+ foreach (VariableDeclaratorSyntax varDecl in fieldDecl.Declaration.Variables)
+ {
+ EqualsValueClauseSyntax initializer = varDecl.Initializer;
+
+ if (initializer != null && initializer.Span.Contains(syntax.Span))
+ {
+ memberName = varDecl.Identifier.ValueText;
+ break;
+ }
+ }
+
+ if (memberName != null)
+ {
+ break;
+ }
}
}
- }
- goto default;
+ goto default;
- default:
- memberName = _factory.TopLevelMethod.GetMemberCallerName();
- break;
+ default:
+ memberName = topLevelMethod.GetMemberCallerName();
+ break;
+ }
+ }
+ else
+ {
+ memberName = binder.ContainingMember().GetMemberCallerName();
}
- BoundExpression memberNameLiteral = MakeLiteral(syntax, ConstantValue.Create(memberName), _compilation.GetSpecialType(SpecialType.System_String));
- defaultValue = MakeConversionNode(memberNameLiteral, parameterType, false);
+ BoundExpression memberNameLiteral = MakeLiteral(syntax, ConstantValue.Create(memberName), compilation.GetSpecialType(SpecialType.System_String), localRewriter);
+ defaultValue = MakeConversionNode(memberNameLiteral, parameterType, @checked: false);
}
else if (defaultConstantValue == ConstantValue.NotAvailable)
- {
+ {
// There is no constant value given for the parameter in source/metadata.
if (parameterType.IsDynamic() || parameterType.SpecialType == SpecialType.System_Object)
{
// We have something like M([Optional] object x). We have special handling for such situations.
- defaultValue = GetDefaultParameterSpecial(syntax, parameter);
+ defaultValue = isLowering
+ ? localRewriter.GetDefaultParameterSpecial(syntax, parameter)
+ : GetDefaultParameterSpecialForIOperation(syntax, parameter, compilation, diagnostics);
}
else
{
@@ -1008,8 +1280,8 @@ private BoundExpression GetDefaultParameterValue(SyntaxNode syntax, ParameterSym
// We have something like M(double? x = 1.23), so replace the argument
// with new double?(1.23).
- TypeSymbol constantType = _compilation.GetSpecialType(defaultConstantValue.SpecialType);
- defaultValue = MakeLiteral(syntax, defaultConstantValue, constantType);
+ TypeSymbol constantType = compilation.GetSpecialType(defaultConstantValue.SpecialType);
+ defaultValue = MakeLiteral(syntax, defaultConstantValue, constantType, localRewriter);
// The parameter's underlying type might not match the constant type. For example, we might have
// a default value of 5 (an integer) but a parameter type of decimal?.
@@ -1019,27 +1291,52 @@ private BoundExpression GetDefaultParameterValue(SyntaxNode syntax, ParameterSym
// Finally, wrap it in a nullable ctor.
defaultValue = new BoundObjectCreationExpression(
syntax,
- UnsafeGetNullableMethod(syntax, parameterType, SpecialMember.System_Nullable_T__ctor),
- defaultValue);
+ UnsafeGetNullableMethod(syntax, parameterType, SpecialMember.System_Nullable_T__ctor, compilation, diagnostics),
+ null,
+ defaultValue);
}
else if (defaultConstantValue.IsNull || defaultConstantValue.IsBad)
{
- defaultValue = MakeLiteral(syntax, defaultConstantValue, parameterType);
+ defaultValue = MakeLiteral(syntax, defaultConstantValue, parameterType, localRewriter);
}
else
{
// We have something like M(double x = 1.23), so replace the argument with 1.23.
- TypeSymbol constantType = _compilation.GetSpecialType(defaultConstantValue.SpecialType);
- defaultValue = MakeLiteral(syntax, defaultConstantValue, constantType);
- // The parameter type might not match the constant type.
+ TypeSymbol constantType = compilation.GetSpecialType(defaultConstantValue.SpecialType);
+ defaultValue = MakeLiteral(syntax, defaultConstantValue, constantType, localRewriter);
+ // The parameter type might not match the constant type.
defaultValue = MakeConversionNode(defaultValue, parameterType, @checked: false, acceptFailingConversion: true);
}
return defaultValue;
- }
+
+ BoundExpression MakeConversionNode(BoundExpression operand, TypeSymbol type, bool @checked, bool acceptFailingConversion = false)
+ {
+ if (isLowering)
+ {
+ return localRewriter.MakeConversionNode(operand, type, @checked, acceptFailingConversion);
+ }
+ else
+ {
+ return MakeConversionForIOperation(operand, type, syntax, compilation, diagnostics, @checked, acceptFailingConversion);
+ }
+ }
+ }
private BoundExpression GetDefaultParameterSpecial(SyntaxNode syntax, ParameterSymbol parameter)
+ {
+ BoundExpression defaultValue = GetDefaultParameterSpecialNoConversion(syntax, parameter, this._compilation);
+ return MakeConversionNode(defaultValue, parameter.Type, @checked: false);
+ }
+
+ private static BoundExpression GetDefaultParameterSpecialForIOperation(SyntaxNode syntax, ParameterSymbol parameter, CSharpCompilation compilation, DiagnosticBag diagnostics)
+ {
+ BoundExpression defaultValue = GetDefaultParameterSpecialNoConversion(syntax, parameter, compilation);
+ return MakeConversionForIOperation(defaultValue, parameter.Type, syntax, compilation, diagnostics, @checked: false);
+ }
+
+ private static BoundExpression GetDefaultParameterSpecialNoConversion(SyntaxNode syntax, ParameterSymbol parameter, CSharpCompilation compilation)
{
// We have a call to a method M([Optional] object x) which omits the argument. The value we generate
// for the argument depends on the presence or absence of other attributes. The rules are:
@@ -1062,25 +1359,23 @@ private BoundExpression GetDefaultParameterSpecial(SyntaxNode syntax, ParameterS
else if (parameter.IsIUnknownConstant)
{
// new UnknownWrapper(default(object))
- var methodSymbol = (MethodSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_UnknownWrapper__ctor);
+ var methodSymbol = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_UnknownWrapper__ctor);
var argument = new BoundDefaultExpression(syntax, parameter.Type);
- defaultValue = new BoundObjectCreationExpression(syntax, methodSymbol, argument);
+ defaultValue = new BoundObjectCreationExpression(syntax, methodSymbol, null, argument);
}
else if (parameter.IsIDispatchConstant)
{
// new DispatchWrapper(default(object))
- var methodSymbol = (MethodSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_DispatchWrapper__ctor);
+ var methodSymbol = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_DispatchWrapper__ctor);
var argument = new BoundDefaultExpression(syntax, parameter.Type);
- defaultValue = new BoundObjectCreationExpression(syntax, methodSymbol, argument);
+ defaultValue = new BoundObjectCreationExpression(syntax, methodSymbol, null, argument);
}
else
{
// Type.Missing
- var fieldSymbol = (FieldSymbol)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Type__Missing);
+ var fieldSymbol = (FieldSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Type__Missing);
defaultValue = new BoundFieldAccess(syntax, null, fieldSymbol, ConstantValue.NotAvailable);
- }
-
- defaultValue = MakeConversionNode(defaultValue, parameter.Type, @checked: false);
+ }
return defaultValue;
}
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs
index 1e8f69755e997..274599cdc9533 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs
@@ -328,6 +328,8 @@ private BoundIndexerAccess TransformIndexerAccess(BoundIndexerAccess indexerAcce
argumentRefKinds,
false,
default(ImmutableArray),
+ null,
+ indexerAccess.UseSetterForDefaultArgumentGeneration,
indexerAccess.Type);
}
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs
index 3ff46b9d2e426..0b545e0c4daa7 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs
@@ -108,9 +108,11 @@ private BoundExpression MakeConversionNode(
{
Debug.Assert(oldNode == null || oldNode.Syntax == syntax);
Debug.Assert((object)rewrittenType != null);
- @checked = @checked &&
- (_inExpressionLambda && (explicitCastInCode || DistinctSpecialTypes(rewrittenOperand.Type, rewrittenType)) ||
- NeedsChecked(rewrittenOperand.Type, rewrittenType));
+
+ if (_inExpressionLambda)
+ {
+ @checked = @checked && NeedsCheckedConversionInExpressionTree(rewrittenOperand.Type, rewrittenType, explicitCastInCode);
+ }
switch (conversion.Kind)
{
@@ -373,53 +375,8 @@ private BoundExpression MakeConversionNode(
type: rewrittenType);
}
- private static bool DistinctSpecialTypes(TypeSymbol source, TypeSymbol target)
- {
- Debug.Assert((object)target != null);
-
- if ((object)source == null)
- {
- return false;
- }
-
- SpecialType sourceST = source.StrippedType().EnumUnderlyingType().SpecialType;
- SpecialType targetST = target.StrippedType().EnumUnderlyingType().SpecialType;
- return sourceST != targetST;
- }
-
- private const bool y = true;
- private const bool n = false;
-
- private static readonly bool[,] s_needsChecked =
- { // chri08u08i16u16i32u32i64u64
- /* chr */
- { n, y, y, y, n, n, n, n, n },
- /* i08 */
- { y, n, y, n, y, n, y, n, y },
- /* u08 */
- { n, y, n, n, n, n, n, n, n },
- /* i16 */
- { y, y, y, n, y, n, y, n, y },
- /* u16 */
- { n, y, y, y, n, n, n, n, n },
- /* i32 */
- { y, y, y, y, y, n, y, n, y },
- /* u32 */
- { y, y, y, y, y, y, n, n, n },
- /* i64 */
- { y, y, y, y, y, y, y, n, y },
- /* u64 */
- { y, y, y, y, y, y, y, y, n },
- /* dec */
- { n, n, n, n, n, n, n, n, n },
- /* r32 */
- { y, y, y, y, y, y, y, y, y },
- /* r64 */
- { y, y, y, y, y, y, y, y, y },
- };
-
// Determine if the conversion can actually overflow at runtime. If not, no need to generate a checked instruction.
- private static bool NeedsChecked(TypeSymbol source, TypeSymbol target)
+ private static bool NeedsCheckedConversionInExpressionTree(TypeSymbol source, TypeSymbol target, bool explicitCastInCode)
{
Debug.Assert((object)target != null);
@@ -428,22 +385,20 @@ private static bool NeedsChecked(TypeSymbol source, TypeSymbol target)
return false;
}
- if (source.IsDynamic())
- {
- return true;
- }
+ SpecialType GetUnderlyingSpecialType(TypeSymbol type) =>
+ type.StrippedType().EnumUnderlyingType().SpecialType;
- SpecialType sourceST = source.StrippedType().EnumUnderlyingType().SpecialType;
- SpecialType targetST = target.StrippedType().EnumUnderlyingType().SpecialType;
+ bool IsInRange(SpecialType type, SpecialType low, SpecialType high) =>
+ low <= type && type <= high;
+
+ SpecialType sourceST = GetUnderlyingSpecialType(source);
+ SpecialType targetST = GetUnderlyingSpecialType(target);
// integral to double or float is never checked, but float/double to integral
// may be checked.
- bool sourceIsNumeric = SpecialType.System_Char <= sourceST && sourceST <= SpecialType.System_Double;
- bool targetIsNumeric = SpecialType.System_Char <= targetST && targetST <= SpecialType.System_UInt64;
- return
- sourceIsNumeric && target.IsPointerType() ||
- targetIsNumeric && source.IsPointerType() ||
- sourceIsNumeric && targetIsNumeric && s_needsChecked[sourceST - SpecialType.System_Char, targetST - SpecialType.System_Char];
+ return (explicitCastInCode || sourceST != targetST) &&
+ IsInRange(sourceST, SpecialType.System_Char, SpecialType.System_Double) &&
+ IsInRange(targetST, SpecialType.System_Char, SpecialType.System_UInt64);
}
///
@@ -456,10 +411,26 @@ private static bool NeedsChecked(TypeSymbol source, TypeSymbol target)
/// The error will be suppressed only for conversions from or .
///
private BoundExpression MakeConversionNode(BoundExpression rewrittenOperand, TypeSymbol rewrittenType, bool @checked, bool acceptFailingConversion = false)
+ {
+ Conversion conversion = MakeConversion(rewrittenOperand, rewrittenType, _compilation, _diagnostics, acceptFailingConversion);
+ if (!conversion.IsValid)
+ {
+ return _factory.NullOrDefault(rewrittenType);
+ }
+
+ return MakeConversionNode(rewrittenOperand.Syntax, rewrittenOperand, conversion, rewrittenType, @checked);
+ }
+
+ private static Conversion MakeConversion(
+ BoundExpression rewrittenOperand,
+ TypeSymbol rewrittenType,
+ CSharpCompilation compilation,
+ DiagnosticBag diagnostics,
+ bool acceptFailingConversion)
{
HashSet useSiteDiagnostics = null;
- Conversion conversion = _compilation.Conversions.ClassifyConversionFromType(rewrittenOperand.Type, rewrittenType, ref useSiteDiagnostics);
- _diagnostics.Add(rewrittenOperand.Syntax, useSiteDiagnostics);
+ Conversion conversion = compilation.Conversions.ClassifyConversionFromType(rewrittenOperand.Type, rewrittenType, ref useSiteDiagnostics);
+ diagnostics.Add(rewrittenOperand.Syntax, useSiteDiagnostics);
if (!conversion.IsValid)
{
@@ -468,17 +439,44 @@ private BoundExpression MakeConversionNode(BoundExpression rewrittenOperand, Typ
rewrittenOperand.Type.SpecialType != SpecialType.System_DateTime)
{
// error CS0029: Cannot implicitly convert type '{0}' to '{1}'
- _diagnostics.Add(
+ diagnostics.Add(
ErrorCode.ERR_NoImplicitConv,
rewrittenOperand.Syntax.Location,
rewrittenOperand.Type,
rewrittenType);
}
+ }
- return _factory.NullOrDefault(rewrittenType);
+ return conversion;
+ }
+
+ private static BoundExpression MakeConversionForIOperation(
+ BoundExpression operand,
+ TypeSymbol type,
+ SyntaxNode syntax,
+ CSharpCompilation compilation,
+ DiagnosticBag diagnostics,
+ bool @checked,
+ bool acceptFailingConversion = false)
+ {
+ Conversion conversion = MakeConversion(operand, type, compilation, diagnostics, acceptFailingConversion);
+
+ if (conversion.IsIdentity)
+ {
+ return operand;
}
- return MakeConversionNode(rewrittenOperand.Syntax, rewrittenOperand, conversion, rewrittenType, @checked);
+ // TODO: Consider doing constant folding for default parameter value conversion.
+ // https://github.com/dotnet/roslyn/issues/19591
+ return new BoundConversion(
+ syntax,
+ operand,
+ conversion,
+ @checked: @checked,
+ explicitCastInCode: false,
+ constantValueOpt: default(ConstantValue),
+ type: type,
+ hasErrors: !conversion.IsValid);
}
///
@@ -745,7 +743,7 @@ private BoundExpression RewriteNullableConversion(
BoundExpression rewrittenConversion = MakeConversionNode(syntax, rewrittenOperand, conversion.UnderlyingConversions[0], rewrittenType.GetNullableUnderlyingType(), @checked);
MethodSymbol ctor = UnsafeGetNullableMethod(syntax, rewrittenType, SpecialMember.System_Nullable_T__ctor);
- return new BoundObjectCreationExpression(syntax, ctor, rewrittenConversion);
+ return new BoundObjectCreationExpression(syntax, ctor, null, rewrittenConversion);
}
else
{
@@ -851,6 +849,7 @@ private BoundExpression RewriteFullyLiftedBuiltInConversion(
BoundExpression consequence = new BoundObjectCreationExpression(
syntax,
UnsafeGetNullableMethod(syntax, type, SpecialMember.System_Nullable_T__ctor),
+ null,
MakeConversionNode(
syntax,
BoundCall.Synthesized(syntax, boundTemp, getValueOrDefault),
@@ -926,6 +925,7 @@ private BoundExpression OptimizeLiftedBuiltInConversion(
return new BoundObjectCreationExpression(
syntax,
UnsafeGetNullableMethod(syntax, type, SpecialMember.System_Nullable_T__ctor),
+ null,
MakeConversionNode(
syntax,
nonNullValue,
@@ -1031,7 +1031,7 @@ private BoundExpression MakeLiftedUserDefinedConversionConsequence(BoundCall cal
{
Debug.Assert(resultType.IsNullableType() && resultType.GetNullableUnderlyingType() == call.Method.ReturnType);
MethodSymbol ctor = UnsafeGetNullableMethod(call.Syntax, resultType, SpecialMember.System_Nullable_T__ctor);
- return new BoundObjectCreationExpression(call.Syntax, ctor, call);
+ return new BoundObjectCreationExpression(call.Syntax, ctor, null, call);
}
return call;
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IfStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IfStatement.cs
index 0c807fc1072f1..2305c3e63d718 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IfStatement.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IfStatement.cs
@@ -59,6 +59,7 @@ private static BoundStatement RewriteIfStatement(
builder.Add(new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, afterif));
builder.Add(rewrittenConsequence);
+ builder.Add(new BoundSequencePoint(null, null));
builder.Add(new BoundLabelStatement(syntax, afterif));
var statements = builder.ToImmutableAndFree();
return new BoundStatementList(syntax, statements, hasErrors);
@@ -86,6 +87,7 @@ private static BoundStatement RewriteIfStatement(
builder.Add(new BoundGotoStatement(syntax, afterif));
builder.Add(new BoundLabelStatement(syntax, alt));
builder.Add(rewrittenAlternativeOpt);
+ builder.Add(new BoundSequencePoint(null, null));
builder.Add(new BoundLabelStatement(syntax, afterif));
return new BoundStatementList(syntax, builder.ToImmutableAndFree(), hasErrors);
}
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IndexerAccess.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IndexerAccess.cs
index d2ae090a187da..888ca6650eb3b 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IndexerAccess.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IndexerAccess.cs
@@ -105,8 +105,8 @@ private BoundExpression MakeIndexerAccess(
// This node will be rewritten with MakePropertyAssignment when rewriting the enclosing BoundAssignmentOperator.
return oldNodeOpt != null ?
- oldNodeOpt.Update(rewrittenReceiver, indexer, rewrittenArguments, argumentNamesOpt, argumentRefKindsOpt, expanded, argsToParamsOpt, type) :
- new BoundIndexerAccess(syntax, rewrittenReceiver, indexer, rewrittenArguments, argumentNamesOpt, argumentRefKindsOpt, expanded, argsToParamsOpt, type);
+ oldNodeOpt.Update(rewrittenReceiver, indexer, rewrittenArguments, argumentNamesOpt, argumentRefKindsOpt, expanded, argsToParamsOpt, null, isLeftOfAssignment, type) :
+ new BoundIndexerAccess(syntax, rewrittenReceiver, indexer, rewrittenArguments, argumentNamesOpt, argumentRefKindsOpt, expanded, argsToParamsOpt, null, isLeftOfAssignment, type);
}
else
{
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Literal.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Literal.cs
index 264d08a50d1e9..d8ba8ef9e36a3 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Literal.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Literal.cs
@@ -135,7 +135,7 @@ private BoundExpression MakeDecimalLiteral(SyntaxNode syntax, ConstantValue cons
return new BoundObjectCreationExpression(
syntax, ctor, arguments.ToImmutableAndFree(),
default(ImmutableArray), default(ImmutableArray), false, default(ImmutableArray),
- constantValue, null, ctor.ContainingType);
+ constantValue, null, null, ctor.ContainingType);
}
private BoundExpression MakeDateTimeLiteral(SyntaxNode syntax, ConstantValue constantValue)
@@ -154,7 +154,7 @@ private BoundExpression MakeDateTimeLiteral(SyntaxNode syntax, ConstantValue con
return new BoundObjectCreationExpression(
syntax, ctor, arguments.ToImmutableAndFree(),
default(ImmutableArray), default(ImmutableArray), false, default(ImmutableArray),
- ConstantValue.NotAvailable, null, ctor.ContainingType);
+ ConstantValue.NotAvailable, null, null, ctor.ContainingType);
}
}
}
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectCreationExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectCreationExpression.cs
index a0bb56b340dde..38b8b5d4c20f3 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectCreationExpression.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectCreationExpression.cs
@@ -203,6 +203,7 @@ private BoundExpression MakeNewT(SyntaxNode syntax, TypeParameterSymbol typePara
invokedAsExtensionMethod: false,
argsToParamsOpt: default(ImmutableArray),
resultKind: LookupResultKind.Viable,
+ binderOpt: null,
type: typeParameter);
return createInstanceCall;
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs
index f54cbd709d3bb..c8f353222bbab 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PatternSwitchStatement.cs
@@ -38,7 +38,7 @@ private class PatternSwitchLocalRewriter : DecisionTreeBuilder
private ArrayBuilder _loweredDecisionTree = ArrayBuilder.GetInstance();
private PatternSwitchLocalRewriter(LocalRewriter localRewriter, BoundPatternSwitchStatement node)
- : base(localRewriter._factory.CurrentMethod, localRewriter._factory.Compilation.Conversions)
+ : base(localRewriter._factory.CurrentMethod, node.Syntax, localRewriter._factory.Compilation.Conversions)
{
this._localRewriter = localRewriter;
this._factory = localRewriter._factory;
@@ -59,15 +59,9 @@ private BoundStatement MakeLoweredForm(BoundPatternSwitchStatement node)
var expression = _localRewriter.VisitExpression(node.Expression);
var result = ArrayBuilder.GetInstance();
- // if the expression is "too complex", we copy it to a temp.
- LocalSymbol initialTemp = null;
if (expression.ConstantValue == null)
{
- initialTemp = _factory.SynthesizedLocal(expression.Type, expression.Syntax);
- result.Add(_factory.Assignment(_factory.Local(initialTemp), expression));
- expression = _factory.Local(initialTemp);
-
- // EnC: We need to insert a hidden sequence point to handle function remapping in case
+ // EnC: We need to insert a hidden sequence point to handle function remapping in case
// the containing method is edited while methods invoked in the expression are being executed.
if (!node.WasCompilerGenerated && _localRewriter.Instrument)
{
@@ -85,7 +79,6 @@ private BoundStatement MakeLoweredForm(BoundPatternSwitchStatement node)
}
// at this point the end of result is unreachable.
- _declaredTemps.AddOptional(initialTemp);
_declaredTemps.AddRange(node.InnerLocals);
// output the sections of code
@@ -148,7 +141,7 @@ private DecisionTree LowerToDecisionTree(
BoundExpression loweredExpression,
BoundPatternSwitchStatement node)
{
- var loweredDecisionTree = DecisionTree.Create(loweredExpression, loweredExpression.Type, _enclosingSymbol);
+ var loweredDecisionTree = CreateEmptyDecisionTree(loweredExpression);
BoundPatternSwitchLabel defaultLabel = null;
SyntaxNode defaultSection = null;
foreach (var section in node.SwitchSections)
@@ -223,15 +216,11 @@ private void LowerDecisionTree(BoundExpression expression, DecisionTree decision
_loweredDecisionTree.Add(_factory.Assignment(decisionTree.Expression, convertedExpression));
}
+ // If the temp is not yet in the declared temp set, add it now
if (_declaredTempSet.Add(decisionTree.Temp))
{
_declaredTemps.Add(decisionTree.Temp);
}
- else
- {
- // we should only attempt to declare each temp once.
- throw ExceptionUtilities.Unreachable;
- }
}
switch (decisionTree.Kind)
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ReturnStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ReturnStatement.cs
index a611dffde4a0a..18b2442dbe4a7 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ReturnStatement.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ReturnStatement.cs
@@ -28,10 +28,6 @@ public override BoundNode VisitReturnStatement(BoundReturnStatement node)
{
rewritten = _instrumenter.InstrumentReturnStatement(node, rewritten);
}
- else if (node.WasCompilerGenerated && _factory.CurrentMethod?.IsAsync == true)
- {
- rewritten = new BoundSequencePoint(null, rewritten);
- }
return rewritten;
}
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TryStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TryStatement.cs
index be1e749b9f2c2..c9b43e9e35a11 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TryStatement.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TryStatement.cs
@@ -79,6 +79,11 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
return base.VisitCatchBlock(node);
}
+ if (node.ExceptionFilterOpt.ConstantValue?.BooleanValue == false)
+ {
+ return null;
+ }
+
BoundExpression rewrittenExceptionSourceOpt = (BoundExpression)this.Visit(node.ExceptionSourceOpt);
BoundExpression rewrittenFilter = (BoundExpression)this.Visit(node.ExceptionFilterOpt);
BoundBlock rewrittenBody = (BoundBlock)this.Visit(node.Body);
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleCreationExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleCreationExpression.cs
index ad637c2120f2b..8dbab708121b9 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleCreationExpression.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_TupleCreationExpression.cs
@@ -60,7 +60,7 @@ private BoundExpression MakeTupleCreationExpression(SyntaxNode syntax, NamedType
}
MethodSymbol smallestConstructor = smallestCtor.AsMember(smallestType);
- BoundObjectCreationExpression currentCreation = new BoundObjectCreationExpression(syntax, smallestConstructor, smallestCtorArguments);
+ BoundObjectCreationExpression currentCreation = new BoundObjectCreationExpression(syntax, smallestConstructor, null, smallestCtorArguments);
if (underlyingTupleTypeChain.Count > 0)
{
@@ -83,7 +83,7 @@ private BoundExpression MakeTupleCreationExpression(SyntaxNode syntax, NamedType
.Add(currentCreation);
MethodSymbol constructor = tuple8Ctor.AsMember(underlyingTupleTypeChain.Pop());
- currentCreation = new BoundObjectCreationExpression(syntax, constructor, ctorArguments);
+ currentCreation = new BoundObjectCreationExpression(syntax, constructor, null, ctorArguments);
}
while (underlyingTupleTypeChain.Count > 0);
}
@@ -96,7 +96,8 @@ private BoundExpression MakeTupleCreationExpression(SyntaxNode syntax, NamedType
currentCreation.Expanded,
currentCreation.ArgsToParamsOpt,
currentCreation.ConstantValue,
- currentCreation.InitializerExpressionOpt,
+ currentCreation.InitializerExpressionOpt,
+ currentCreation.BinderOpt,
type);
return currentCreation;
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs
index b3c64901f9383..6d19d2eb3b737 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs
@@ -348,6 +348,7 @@ private BoundExpression GetLiftedUnaryOperatorConsequence(UnaryOperatorKind kind
BoundExpression consequence = new BoundObjectCreationExpression(
syntax,
ctor,
+ null,
unliftedOp);
return consequence;
}
@@ -633,7 +634,7 @@ private BoundExpression MakeUserDefinedIncrementOperator(BoundIncrementOperator
BoundExpression userDefinedCall = BoundCall.Synthesized(syntax, null, node.MethodOpt, call_GetValueOrDefault);
// new S?(op_Increment(temp.GetValueOrDefault()))
- BoundExpression consequence = new BoundObjectCreationExpression(syntax, ctor, userDefinedCall);
+ BoundExpression consequence = new BoundObjectCreationExpression(syntax, ctor, null, userDefinedCall);
// default(S?)
BoundExpression alternative = new BoundDefaultExpression(syntax, null, type);
@@ -700,7 +701,7 @@ private BoundExpression MakeBuiltInIncrementOperator(BoundIncrementOperator node
{
binaryOperandType = _compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(binaryOperandType);
MethodSymbol ctor = UnsafeGetNullableMethod(node.Syntax, binaryOperandType, SpecialMember.System_Nullable_T__ctor);
- boundOne = new BoundObjectCreationExpression(node.Syntax, ctor, boundOne);
+ boundOne = new BoundObjectCreationExpression(node.Syntax, ctor, null, boundOne);
}
// Now we construct the other operand to the binary addition. We start with just plain "x".
@@ -800,7 +801,7 @@ private BoundExpression MakeLiftedDecimalIncDecOperator(SyntaxNode syntax, Binar
// op_Inc(x.GetValueOrDefault())
BoundExpression methodCall = BoundCall.Synthesized(syntax, null, method, getValueCall);
// new decimal?(op_Inc(x.GetValueOrDefault()))
- BoundExpression consequence = new BoundObjectCreationExpression(syntax, ctor, methodCall);
+ BoundExpression consequence = new BoundObjectCreationExpression(syntax, ctor, null, methodCall);
// default(decimal?)
BoundExpression alternative = new BoundDefaultExpression(syntax, null, operand.Type);
diff --git a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs
index 4b8e2d4becf59..4005e66d8c8fb 100644
--- a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs
@@ -255,6 +255,7 @@ public override BoundNode VisitCall(BoundCall node)
node.InvokedAsExtensionMethod,
node.ArgsToParamsOpt,
node.ResultKind,
+ node.BinderOpt,
rewrittenType);
}
@@ -471,6 +472,7 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre
rewritten.ArgsToParamsOpt,
rewritten.ConstantValueOpt,
rewritten.InitializerExpressionOpt,
+ rewritten.BinderOpt,
rewritten.Type);
}
diff --git a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs
index 3f4fe16167ae4..1529d4c6f2c74 100644
--- a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs
@@ -6,12 +6,9 @@
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
-using System.Text;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Symbols;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
@@ -174,12 +171,13 @@ private void CheckCurrentType()
{
Debug.Assert((object)TopLevelMethod == null || TopLevelMethod.ContainingType == CurrentType);
- // In EE scenarios, lambdas are considered to be contained by the user-defined methods,
- // rather than the EE-defined methods for which we are generating bound nodes. This is
- // because the containing symbols are used to determine the type of the "this" parameter,
- // which we need to the user-defined types.
+ // In EE scenarios, lambdas and local functions are considered to be contained by the
+ // user-defined methods, rather than the EE-defined methods for which we are generating
+ // bound nodes. This is because the containing symbols are used to determine the type
+ // of the "this" parameter, which we need to be the user-defined types.
Debug.Assert((object)CurrentMethod == null ||
CurrentMethod.MethodKind == MethodKind.AnonymousFunction ||
+ CurrentMethod.MethodKind == MethodKind.LocalFunction ||
CurrentMethod.ContainingType == CurrentType);
}
}
@@ -570,7 +568,7 @@ public BoundObjectCreationExpression New(NamedTypeSymbol type, params BoundExpre
public BoundObjectCreationExpression New(MethodSymbol ctor, params BoundExpression[] args)
{
// TODO: add diagnostics for when things fall apart
- return new BoundObjectCreationExpression(Syntax, ctor, args) { WasCompilerGenerated = true };
+ return new BoundObjectCreationExpression(Syntax, ctor, null, args) { WasCompilerGenerated = true };
}
public BoundExpression InstanceCall(BoundExpression receiver, string name, BoundExpression arg)
@@ -637,7 +635,7 @@ public BoundCall Call(BoundExpression receiver, MethodSymbol method, ImmutableAr
return new BoundCall(
Syntax, receiver, method, args,
ImmutableArray.Empty, ImmutableArray.Empty, false, false, false,
- default(ImmutableArray), LookupResultKind.Viable, method.ReturnType,
+ default(ImmutableArray), LookupResultKind.Viable, null, method.ReturnType,
hasErrors:method.OriginalDefinition is ErrorMethodSymbol)
{ WasCompilerGenerated = true };
}
@@ -648,7 +646,7 @@ public BoundCall Call(BoundExpression receiver, MethodSymbol method, ImmutableAr
return new BoundCall(
Syntax, receiver, method, args,
ImmutableArray.Empty, refKinds, false, false, false,
- ImmutableArray.Empty, LookupResultKind.Viable, method.ReturnType)
+ ImmutableArray.Empty, LookupResultKind.Viable, null, method.ReturnType)
{ WasCompilerGenerated = true };
}
@@ -956,9 +954,14 @@ public BoundExpression ThrowExpression(BoundExpression thrown, TypeSymbol type)
public BoundExpression Null(TypeSymbol type)
{
- BoundExpression nullLiteral = new BoundLiteral(Syntax, ConstantValue.Null, type) { WasCompilerGenerated = true };
+ return Null(type, Syntax);
+ }
+
+ public static BoundExpression Null(TypeSymbol type, SyntaxNode syntax)
+ {
+ BoundExpression nullLiteral = new BoundLiteral(syntax, ConstantValue.Null, type) { WasCompilerGenerated = true };
return type.IsPointerType()
- ? BoundConversion.SynthesizedNonUserDefined(Syntax, nullLiteral, Conversion.NullToPointer, type)
+ ? BoundConversion.SynthesizedNonUserDefined(syntax, nullLiteral, Conversion.NullToPointer, type)
: nullLiteral;
}
@@ -1182,7 +1185,12 @@ public BoundExpression Array(TypeSymbol elementType, BoundExpression length)
internal BoundExpression Default(TypeSymbol type)
{
- return new BoundDefaultExpression(Syntax, type) { WasCompilerGenerated = true };
+ return Default(type, Syntax);
+ }
+
+ internal static BoundExpression Default(TypeSymbol type, SyntaxNode syntax)
+ {
+ return new BoundDefaultExpression(syntax, type) { WasCompilerGenerated = true };
}
internal BoundStatement Try(
@@ -1221,7 +1229,12 @@ internal BoundTryStatement Fault(BoundBlock tryBlock, BoundBlock faultBlock)
internal BoundExpression NullOrDefault(TypeSymbol typeSymbol)
{
- return typeSymbol.IsValueType ? Default(typeSymbol) : Null(typeSymbol);
+ return NullOrDefault(typeSymbol, this.Syntax);
+ }
+
+ internal static BoundExpression NullOrDefault(TypeSymbol typeSymbol, SyntaxNode syntax)
+ {
+ return typeSymbol.IsValueType ? Default(typeSymbol, syntax) : Null(typeSymbol, syntax);
}
internal BoundExpression Not(
diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs
index d4b9e5ef6aa03..c5f37ce315d96 100644
--- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs
@@ -6,6 +6,7 @@
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Symbols;
using Roslyn.Utilities;
@@ -84,7 +85,7 @@ public virtual bool IsGenericMethod
internal virtual bool IsDirectlyExcludedFromCodeCoverage { get => false; }
///
- /// Returns true if this method is an extension method.
+ /// Returns true if this method is an extension method.
///
public abstract bool IsExtensionMethod { get; }
@@ -114,7 +115,7 @@ public virtual bool IsGenericMethod
internal abstract IEnumerable GetSecurityInformation();
///
- /// Marshalling information for return value (FieldMarshal in metadata).
+ /// Marshalling information for return value (FieldMarshal in metadata).
///
internal abstract MarshalPseudoCustomAttributeData ReturnValueMarshallingInformation { get; }
@@ -133,7 +134,7 @@ public virtual bool IsGenericMethod
///
/// Returns true if this method hides base methods by name. This cannot be specified directly
/// in the C# language, but can be true for methods defined in other languages imported from
- /// metadata. The equivalent of the "hidebyname" flag in metadata.
+ /// metadata. The equivalent of the "hidebyname" flag in metadata.
///
public abstract bool HidesBaseMethodsByName { get; }
@@ -184,7 +185,7 @@ public virtual bool IsCheckedBuiltin
public abstract TypeSymbol ReturnType { get; }
///
- /// Returns the type arguments that have been substituted for the type parameters.
+ /// Returns the type arguments that have been substituted for the type parameters.
/// If nothing has been substituted for a given type parameter,
/// then the type parameter itself is consider the type argument.
///
@@ -275,13 +276,13 @@ internal virtual bool IsExplicitInterfaceImplementation
/// Returns interface methods explicitly implemented by this method.
///
///
- /// Methods imported from metadata can explicitly implement more than one method,
+ /// Methods imported from metadata can explicitly implement more than one method,
/// that is why return type is ImmutableArray.
///
public abstract ImmutableArray ExplicitInterfaceImplementations { get; }
///
- /// Returns the list of custom modifiers, if any, associated with the return type.
+ /// Returns the list of custom modifiers, if any, associated with the return type.
///
public abstract ImmutableArray ReturnTypeCustomModifiers { get; }
@@ -309,7 +310,7 @@ public virtual ImmutableArray GetReturnTypeAttributes()
/// returns the property that this method is the getter or setter for.
/// If this method has MethodKind of MethodKind.EventAdd or MethodKind.EventRemove,
/// returns the event that this method is the adder or remover for.
- /// Note, the set of possible associated symbols might be expanded in the future to
+ /// Note, the set of possible associated symbols might be expanded in the future to
/// reflect changes in the languages.
///
public abstract Symbol AssociatedSymbol { get; }
@@ -327,19 +328,19 @@ internal MethodSymbol GetLeastOverriddenMethod(NamedTypeSymbol accessingTypeOpt)
while (m.IsOverride && !m.HidesBaseMethodsByName)
{
// We might not be able to access the overridden method. For example,
- //
+ //
// .assembly A
// {
// InternalsVisibleTo("B")
// public class A { internal virtual void M() { } }
// }
- //
+ //
// .assembly B
// {
// InternalsVisibleTo("C")
// public class B : A { internal override void M() { } }
// }
- //
+ //
// .assembly C
// {
// public class C : B { ... new B().M ... } // A.M is not accessible from here
@@ -374,9 +375,9 @@ internal MethodSymbol GetConstructedLeastOverriddenMethod(NamedTypeSymbol access
///
/// If this method overrides another method (because it both had the override modifier
/// and there correctly was a method to override), returns the overridden method.
- /// Note that if an overriding method D.M overrides C.M, which in turn overrides
+ /// Note that if an overriding method D.M overrides C.M, which in turn overrides
/// virtual method A.M, the "overridden method" of D.M is C.M, not the original virtual
- /// method A.M. Note also that constructed generic methods are not considered to
+ /// method A.M. Note also that constructed generic methods are not considered to
/// override anything.
///
public MethodSymbol OverriddenMethod
@@ -587,7 +588,7 @@ internal bool IsSubmissionInitializer
}
///
- /// Determines whether this method is a candidate for a default assembly entry point
+ /// Determines whether this method is a candidate for a default assembly entry point
/// (i.e. it is a static method called "Main").
///
internal bool IsEntryPointCandidate
@@ -595,53 +596,6 @@ internal bool IsEntryPointCandidate
get { return IsStatic && Name == WellKnownMemberNames.EntryPointMethodName; }
}
- ///
- /// Checks if the method has an entry point compatible signature, i.e.
- /// - the return type is either void or int
- /// - has either no parameter or a single parameter of type string[]
- ///
- internal bool HasEntryPointSignature()
- {
- if (this.IsVararg)
- {
- return false;
- }
-
- TypeSymbol returnType = ReturnType;
- if (returnType.SpecialType != SpecialType.System_Int32 && returnType.SpecialType != SpecialType.System_Void)
- {
- return false;
- }
-
- if (RefKind != RefKind.None)
- {
- return false;
- }
-
- if (Parameters.Length == 0)
- {
- return true;
- }
-
- if (Parameters.Length > 1)
- {
- return false;
- }
-
- if (!ParameterRefKinds.IsDefault)
- {
- return false;
- }
-
- var firstType = Parameters[0].Type;
- if (firstType.TypeKind != TypeKind.Array)
- {
- return false;
- }
-
- var array = (ArrayTypeSymbol)firstType;
- return array.IsSZArray && array.ElementType.SpecialType == SpecialType.System_String;
- }
internal override TResult Accept(CSharpSymbolVisitor visitor, TArgument argument)
{
@@ -738,7 +692,7 @@ public virtual TypeSymbol ReceiverType
}
///
- /// If this method is a reduced extension method, returns a type inferred during reduction process for the type parameter.
+ /// If this method is a reduced extension method, returns a type inferred during reduction process for the type parameter.
///
/// Type parameter of the corresponding method.
/// Inferred type or Nothing if nothing was inferred.
@@ -888,7 +842,7 @@ internal bool CalculateUseSiteDiagnostic(ref DiagnosticInfo result)
return true;
}
- // If the member is in an assembly with unified references,
+ // If the member is in an assembly with unified references,
// we check if its definition depends on a type from a unified reference.
if (this.ContainingModule.HasUnifiedReferences)
{
@@ -908,7 +862,7 @@ internal bool CalculateUseSiteDiagnostic(ref DiagnosticInfo result)
}
///
- /// Return error code that has highest priority while calculating use site error for this symbol.
+ /// Return error code that has highest priority while calculating use site error for this symbol.
///
protected override int HighestPriorityUseSiteError
{
@@ -949,7 +903,7 @@ internal virtual TypeSymbol IteratorElementType
///
/// Generates bound block representing method's body for methods in lowered form and adds it to
- /// a collection of method bodies of the current module. This method is supposed to only be
+ /// a collection of method bodies of the current module. This method is supposed to only be
/// called for method symbols which return SynthesizesLoweredBoundBody == true.
///
internal virtual void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics)
@@ -980,7 +934,7 @@ internal virtual bool SynthesizesLoweredBoundBody
///
/// Syntax offset is a unique identifier for the local within the emitted method body.
/// It's based on position of the local declarator. In single-part method bodies it's simply the distance
- /// from the start of the method body syntax span. If a method body has multiple parts (such as a constructor
+ /// from the start of the method body syntax span. If a method body has multiple parts (such as a constructor
/// comprising of code for member initializers and constructor initializer calls) the offset is calculated
/// as if all source these parts were concatenated together and prepended to the constructor body.
/// The resulting syntax offset is then negative for locals defined outside of the constructor body.
@@ -1232,7 +1186,7 @@ public virtual bool IsTupleMethod
///
/// If this is a method of a tuple type, return corresponding underlying method from the
- /// tuple underlying type. Otherwise, null.
+ /// tuple underlying type. Otherwise, null.
///
public virtual MethodSymbol TupleUnderlyingMethod
{
diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs
index a651f6f1b3a9e..8924222d9878d 100644
--- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
@@ -300,5 +301,19 @@ public static bool IsGenericTaskReturningAsync(this MethodSymbol method, CSharpC
return method.IsAsync
&& method.ReturnType.IsGenericTaskType(compilation);
}
+
+ internal static CSharpSyntaxNode ExtractReturnTypeSyntax(this MethodSymbol method)
+ {
+ method = method.PartialDefinitionPart ?? method;
+ foreach (var reference in method.DeclaringSyntaxReferences)
+ {
+ if (reference.GetSyntax() is MethodDeclarationSyntax methodDeclaration)
+ {
+ return methodDeclaration.ReturnType;
+ }
+ }
+
+ return (CSharpSyntaxNode)CSharpSyntaxTree.Dummy.GetRoot();
+ }
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs
index 4cc0f8a9bea23..48f86ecbd1c2e 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs
@@ -8,7 +8,6 @@
using System.Linq;
using System.Reflection;
using System.Threading;
-using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -20,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
///
/// Represents an assembly built by compiler.
///
- internal sealed class SourceAssemblySymbol : MetadataOrSourceAssemblySymbol, ISourceAssemblySymbolInternal, IAttributeTargetSymbol
+ internal sealed partial class SourceAssemblySymbol : MetadataOrSourceAssemblySymbol, ISourceAssemblySymbolInternal, IAttributeTargetSymbol
{
///
/// A Compilation the assembly is created for.
@@ -730,7 +729,7 @@ private void ValidateIVTPublicKeys(DiagnosticBag diagnostics)
/// Forces binding and decoding of attributes.
/// This property shouldn't be accessed during binding as it can lead to attribute binding cycle.
///
- private bool InternalsAreVisible
+ public bool InternalsAreVisible
{
get
{
@@ -1696,6 +1695,15 @@ private bool HasDebuggableAttribute
}
}
+ private bool HasReferenceAssemblyAttribute
+ {
+ get
+ {
+ CommonAssemblyWellKnownAttributeData assemblyData = this.GetSourceDecodedWellKnownAttributeData();
+ return assemblyData != null && assemblyData.HasReferenceAssemblyAttribute;
+ }
+ }
+
internal override void AddSynthesizedAttributes(ModuleCompilationState compilationState, ref ArrayBuilder attributes)
{
base.AddSynthesizedAttributes(compilationState, ref attributes);
@@ -2264,6 +2272,10 @@ private void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments().HasCompilationRelaxationsAttribute = true;
}
+ else if (attribute.IsTargetAttribute(this, AttributeDescription.ReferenceAssemblyAttribute))
+ {
+ arguments.GetOrCreateData().HasReferenceAssemblyAttribute = true;
+ }
else if (attribute.IsTargetAttribute(this, AttributeDescription.RuntimeCompatibilityAttribute))
{
bool wrapNonExceptionThrows = true;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs
index 1d45cc848a95f..889173b25084b 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs
@@ -1,9 +1,11 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
@@ -17,7 +19,6 @@ internal abstract class SynthesizedEntryPointSymbol : MethodSymbol
internal const string FactoryName = "";
private readonly NamedTypeSymbol _containingType;
- private readonly TypeSymbol _returnType;
internal static SynthesizedEntryPointSymbol Create(SynthesizedInteractiveInitializerMethod initializerMethod, DiagnosticBag diagnostics)
{
@@ -54,13 +55,11 @@ internal static SynthesizedEntryPointSymbol Create(SynthesizedInteractiveInitial
}
}
- private SynthesizedEntryPointSymbol(NamedTypeSymbol containingType, TypeSymbol returnType)
+ private SynthesizedEntryPointSymbol(NamedTypeSymbol containingType)
{
Debug.Assert((object)containingType != null);
- Debug.Assert((object)returnType != null);
_containingType = containingType;
- _returnType = returnType;
}
internal override bool GenerateDebugInfo
@@ -128,11 +127,6 @@ internal override RefKind RefKind
get { return RefKind.None; }
}
- public override TypeSymbol ReturnType
- {
- get { return _returnType; }
- }
-
public override ImmutableArray ReturnTypeCustomModifiers
{
get { return ImmutableArray.Empty; }
@@ -160,7 +154,7 @@ public override int Arity
public override bool ReturnsVoid
{
- get { return _returnType.SpecialType == SpecialType.System_Void; }
+ get { return ReturnType.SpecialType == SpecialType.System_Void; }
}
public override MethodKind MethodKind
@@ -286,7 +280,7 @@ internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree l
throw ExceptionUtilities.Unreachable;
}
- private CSharpSyntaxNode GetSyntax()
+ private static CSharpSyntaxNode DummySyntax()
{
var syntaxTree = CSharpSyntaxTree.Dummy;
return (CSharpSyntaxNode)syntaxTree.GetRoot();
@@ -325,34 +319,133 @@ private static BoundCall CreateParameterlessCall(CSharpSyntaxNode syntax, BoundE
invokedAsExtensionMethod: false,
argsToParamsOpt: default(ImmutableArray),
resultKind: LookupResultKind.Viable,
+ binderOpt: null,
type: method.ReturnType)
{ WasCompilerGenerated = true };
}
+ /// A synthesized entrypoint that forwards all calls to an async Main Method
+ internal sealed class AsyncForwardEntryPoint : SynthesizedEntryPointSymbol
+ {
+ /// The user-defined asynchronous main method.
+ private readonly CSharpSyntaxNode _userMainReturnTypeSyntax;
+
+ private readonly BoundExpression _getAwaiterGetResultCall;
+
+ private readonly ImmutableArray _parameters;
+
+ internal AsyncForwardEntryPoint(CSharpCompilation compilation, NamedTypeSymbol containingType, MethodSymbol userMain) :
+ base(containingType)
+ {
+ // There should be no way for a userMain to be passed in unless it already passed the
+ // parameter checks for determining entrypoint validity.
+ Debug.Assert(userMain.ParameterCount == 0 || userMain.ParameterCount == 1);
+
+ _userMainReturnTypeSyntax = userMain.ExtractReturnTypeSyntax();
+ var binder = compilation.GetBinder(_userMainReturnTypeSyntax);
+ _parameters = SynthesizedParameterSymbol.DeriveParameters(userMain, this);
+
+ var arguments = Parameters.SelectAsArray((p, s) => (BoundExpression)new BoundParameter(s, p, p.Type), _userMainReturnTypeSyntax);
+
+ // Main(args) or Main()
+ BoundCall userMainInvocation = new BoundCall(
+ syntax: _userMainReturnTypeSyntax,
+ receiverOpt: null,
+ method: userMain,
+ arguments: arguments,
+ argumentNamesOpt: default(ImmutableArray),
+ argumentRefKindsOpt: default(ImmutableArray),
+ isDelegateCall: false,
+ expanded: false,
+ invokedAsExtensionMethod: false,
+ argsToParamsOpt: default(ImmutableArray),
+ resultKind: LookupResultKind.Viable,
+ binderOpt: binder,
+ type: userMain.ReturnType)
+ { WasCompilerGenerated = true };
+
+ // The diagnostics that would be produced here will already have been captured and returned.
+ var droppedBag = DiagnosticBag.GetInstance();
+ var success = binder.GetAwaitableExpressionInfo(userMainInvocation, out _, out _, out _, out _getAwaiterGetResultCall, _userMainReturnTypeSyntax, droppedBag);
+ droppedBag.Free();
+
+ Debug.Assert(
+ ReturnType.SpecialType == SpecialType.System_Void ||
+ ReturnType.SpecialType == SpecialType.System_Int32);
+ }
+
+ public override string Name => MainName;
+
+ public override ImmutableArray Parameters => _parameters;
+
+ public override TypeSymbol ReturnType => _getAwaiterGetResultCall.Type;
+
+ internal override BoundBlock CreateBody()
+ {
+ var syntax = _userMainReturnTypeSyntax;
+
+ if (ReturnsVoid)
+ {
+ return new BoundBlock(
+ syntax: syntax,
+ locals: ImmutableArray.Empty,
+ statements: ImmutableArray.Create(
+ new BoundExpressionStatement(
+ syntax: syntax,
+ expression: _getAwaiterGetResultCall
+ )
+ { WasCompilerGenerated = true },
+ new BoundReturnStatement(
+ syntax: syntax,
+ refKind: RefKind.None,
+ expressionOpt: null
+ )
+ { WasCompilerGenerated = true }
+ )
+ )
+ { WasCompilerGenerated = true };
+
+ }
+ else
+ {
+ return new BoundBlock(
+ syntax: syntax,
+ locals: ImmutableArray.Empty,
+ statements: ImmutableArray.Create(
+ new BoundReturnStatement(
+ syntax: syntax,
+ refKind: RefKind.None,
+ expressionOpt: _getAwaiterGetResultCall
+ )
+ )
+ )
+ { WasCompilerGenerated = true };
+ }
+ }
+ }
+
private sealed class ScriptEntryPoint : SynthesizedEntryPointSymbol
{
private readonly MethodSymbol _getAwaiterMethod;
private readonly MethodSymbol _getResultMethod;
+ private readonly TypeSymbol _returnType;
internal ScriptEntryPoint(NamedTypeSymbol containingType, TypeSymbol returnType, MethodSymbol getAwaiterMethod, MethodSymbol getResultMethod) :
- base(containingType, returnType)
+ base(containingType)
{
Debug.Assert(containingType.IsScriptClass);
Debug.Assert(returnType.SpecialType == SpecialType.System_Void);
_getAwaiterMethod = getAwaiterMethod;
_getResultMethod = getResultMethod;
+ _returnType = returnType;
}
- public override string Name
- {
- get { return MainName; }
- }
+ public override string Name => MainName;
- public override ImmutableArray Parameters
- {
- get { return ImmutableArray.Empty; }
- }
+ public override ImmutableArray Parameters => ImmutableArray.Empty;
+
+ public override TypeSymbol ReturnType => _returnType;
// private static void ()
// {
@@ -365,7 +458,7 @@ internal override BoundBlock CreateBody()
Debug.Assert((object)_getAwaiterMethod != null);
Debug.Assert((object)_getResultMethod != null);
- var syntax = this.GetSyntax();
+ var syntax = DummySyntax();
var ctor = _containingType.GetScriptConstructor();
Debug.Assert(ctor.ParameterCount == 0);
@@ -391,7 +484,8 @@ internal override BoundBlock CreateBody()
scriptLocal,
new BoundObjectCreationExpression(
syntax,
- ctor)
+ ctor,
+ null)
{ WasCompilerGenerated = true },
_containingType)
{ WasCompilerGenerated = true })
@@ -423,13 +517,15 @@ internal override BoundBlock CreateBody()
private sealed class SubmissionEntryPoint : SynthesizedEntryPointSymbol
{
private readonly ImmutableArray _parameters;
+ private readonly TypeSymbol _returnType;
internal SubmissionEntryPoint(NamedTypeSymbol containingType, TypeSymbol returnType, TypeSymbol submissionArrayType) :
- base(containingType, returnType)
+ base(containingType)
{
Debug.Assert(containingType.IsSubmissionClass);
Debug.Assert(returnType.SpecialType != SpecialType.System_Void);
_parameters = ImmutableArray.Create(SynthesizedParameterSymbol.Create(this, submissionArrayType, 0, RefKind.None, "submissionArray"));
+ _returnType = returnType;
}
public override string Name
@@ -442,6 +538,8 @@ public override ImmutableArray Parameters
get { return _parameters; }
}
+ public override TypeSymbol ReturnType => _returnType;
+
// private static T (object[] submissionArray)
// {
// var submission = new Submission#N(submissionArray);
@@ -449,7 +547,7 @@ public override ImmutableArray Parameters
// }
internal override BoundBlock CreateBody()
{
- var syntax = this.GetSyntax();
+ var syntax = DummySyntax();
var ctor = _containingType.GetScriptConstructor();
Debug.Assert(ctor.ParameterCount == 1);
@@ -481,6 +579,7 @@ internal override BoundBlock CreateBody()
default(ImmutableArray),
null,
null,
+ null,
_containingType)
{ WasCompilerGenerated = true },
_containingType)
diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
index b63e0120146af..a3d3b87784e2e 100644
--- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
+++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
@@ -25,9 +25,8 @@
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
-
-using static Roslyn.Test.Utilities.SharedResourceHelpers;
using static Microsoft.CodeAnalysis.CommonDiagnosticAnalyzers;
+using static Roslyn.Test.Utilities.SharedResourceHelpers;
namespace Microsoft.CodeAnalysis.CSharp.CommandLine.UnitTests
{
@@ -37,7 +36,7 @@ public class CommandLineTests : CSharpTestBase
private static readonly string s_defaultSdkDirectory = RuntimeEnvironment.GetRuntimeDirectory();
private static readonly string s_compilerVersion = typeof(Csc).GetTypeInfo().Assembly.GetCustomAttribute().Version;
private static readonly string s_compilerShortCommitHash =
- CommonCompiler.ExtractShortCommitHash(typeof(CSharpCompiler).GetTypeInfo().Assembly.GetCustomAttribute().Hash);
+ CommonCompiler.ExtractShortCommitHash(typeof(CSharpCompiler).GetTypeInfo().Assembly.GetCustomAttribute()?.Hash);
private readonly string _baseDirectory = TempRoot.Root;
@@ -1725,19 +1724,19 @@ public void SourceLink()
Assert.Equal(Path.Combine(_baseDirectory, "s l.json"), parsedArgs.SourceLink);
parsedArgs = DefaultParse(new[] { "/sourcelink:sl.json", "/debug:full", "a.cs" }, _baseDirectory);
- parsedArgs.Errors.Verify(Diagnostic(ErrorCode.ERR_SourceLinkRequiresPortablePdb));
+ parsedArgs.Errors.Verify();
parsedArgs = DefaultParse(new[] { "/sourcelink:sl.json", "/debug:pdbonly", "a.cs" }, _baseDirectory);
- parsedArgs.Errors.Verify(Diagnostic(ErrorCode.ERR_SourceLinkRequiresPortablePdb));
+ parsedArgs.Errors.Verify();
parsedArgs = DefaultParse(new[] { "/sourcelink:sl.json", "/debug-", "a.cs" }, _baseDirectory);
- parsedArgs.Errors.Verify(Diagnostic(ErrorCode.ERR_SourceLinkRequiresPortablePdb));
+ parsedArgs.Errors.Verify(Diagnostic(ErrorCode.ERR_SourceLinkRequiresPdb));
parsedArgs = DefaultParse(new[] { "/sourcelink:sl.json", "/debug+", "a.cs" }, _baseDirectory);
- parsedArgs.Errors.Verify(Diagnostic(ErrorCode.ERR_SourceLinkRequiresPortablePdb));
+ parsedArgs.Errors.Verify();
parsedArgs = DefaultParse(new[] { "/sourcelink:sl.json", "a.cs" }, _baseDirectory);
- parsedArgs.Errors.Verify(Diagnostic(ErrorCode.ERR_SourceLinkRequiresPortablePdb));
+ parsedArgs.Errors.Verify(Diagnostic(ErrorCode.ERR_SourceLinkRequiresPdb));
}
[Fact]
@@ -1800,6 +1799,31 @@ public void SourceLink_EndToEnd_Portable()
CleanupAllGeneratedFiles(src.Path);
}
+ [Fact]
+ public void SourceLink_EndToEnd_Windows()
+ {
+ var dir = Temp.CreateDirectory();
+
+ var src = dir.CreateFile("a.cs");
+ src.WriteAllText(@"class C { public static void Main() {} }");
+
+ var sl = dir.CreateFile("sl.json");
+ byte[] slContent = Encoding.UTF8.GetBytes(@"{ ""documents"" : {} }");
+ sl.WriteAllBytes(slContent);
+
+ var outWriter = new StringWriter(CultureInfo.InvariantCulture);
+ var csc = new MockCSharpCompiler(null, dir.Path, new[] { "/nologo", "/debug:full", "/sourcelink:sl.json", "a.cs" });
+ int exitCode = csc.Run(outWriter);
+ Assert.Equal(0, exitCode);
+
+ var pdbStream = File.OpenRead(Path.Combine(dir.Path, "a.pdb"));
+ var actualData = PdbValidation.GetSourceLinkData(pdbStream);
+ AssertEx.Equal(slContent, actualData);
+
+ // Clean up temp files
+ CleanupAllGeneratedFiles(src.Path);
+ }
+
[Fact]
public void Embed()
{
@@ -2876,6 +2900,40 @@ public void ParseOut()
// error CS2005: Missing file specification for '/out:' option
Diagnostic(ErrorCode.ERR_NoFileSpec).WithArguments("/out:"));
+ parsedArgs = DefaultParse(new[] { @"/refout:", "a.cs" }, baseDirectory);
+ parsedArgs.Errors.Verify(
+ // error CS2005: Missing file specification for '/refout:' option
+ Diagnostic(ErrorCode.ERR_NoFileSpec).WithArguments("/refout:"));
+
+ parsedArgs = DefaultParse(new[] { @"/refout:ref.dll", "/refonly", "a.cs" }, baseDirectory);
+ parsedArgs.Errors.Verify(
+ // error CS8301: Do not use refout when using refonly.
+ Diagnostic(ErrorCode.ERR_NoRefOutWhenRefOnly).WithLocation(1, 1));
+
+ parsedArgs = DefaultParse(new[] { @"/refout:ref.dll", "/link:b", "a.cs" }, baseDirectory);
+ parsedArgs.Errors.Verify();
+
+ parsedArgs = DefaultParse(new[] { "/refonly", "/link:b", "a.cs" }, baseDirectory);
+ parsedArgs.Errors.Verify();
+
+ parsedArgs = DefaultParse(new[] { "/refonly:incorrect", "a.cs" }, baseDirectory);
+ parsedArgs.Errors.Verify(
+ // error CS2007: Unrecognized option: '/refonly:incorrect'
+ Diagnostic(ErrorCode.ERR_BadSwitch).WithArguments("/refonly:incorrect").WithLocation(1, 1)
+ );
+
+ parsedArgs = DefaultParse(new[] { @"/refout:ref.dll", "/target:module", "a.cs" }, baseDirectory);
+ parsedArgs.Errors.Verify(
+ // error CS8302: Cannot compile net modules when using /refout or /refonly.
+ Diagnostic(ErrorCode.ERR_NoNetModuleOutputWhenRefOutOrRefOnly).WithLocation(1, 1)
+ );
+
+ parsedArgs = DefaultParse(new[] { @"/refonly", "/target:module", "a.cs" }, baseDirectory);
+ parsedArgs.Errors.Verify(
+ // error CS8302: Cannot compile net modules when using /refout or /refonly.
+ Diagnostic(ErrorCode.ERR_NoNetModuleOutputWhenRefOutOrRefOnly).WithLocation(1, 1)
+ );
+
// Dev11 reports CS2007: Unrecognized option: '/out'
parsedArgs = DefaultParse(new[] { @"/out", "a.cs" }, baseDirectory);
parsedArgs.Errors.Verify(
@@ -7275,12 +7333,14 @@ public void IOFailure_DisposeXmlFile()
Assert.Equal($"error CS0016: Could not write to output file '{xmlPath}' -- 'Fake IOException'{Environment.NewLine}", outWriter.ToString());
}
- [Fact]
- public void IOFailure_DisposeSourceLinkFile()
+ [Theory]
+ [InlineData("portable")]
+ [InlineData("full")]
+ public void IOFailure_DisposeSourceLinkFile(string format)
{
var srcPath = MakeTrivialExe(Temp.CreateDirectory().Path);
var sourceLinkPath = Path.Combine(Path.GetDirectoryName(srcPath), "test.json");
- var csc = new MockCSharpCompiler(null, _baseDirectory, new[] { "/nologo", "/preferreduilang:en", "/debug:portable", $"/sourcelink:{sourceLinkPath}", srcPath });
+ var csc = new MockCSharpCompiler(null, _baseDirectory, new[] { "/nologo", "/preferreduilang:en", "/debug:" + format, $"/sourcelink:{sourceLinkPath}", srcPath });
csc.FileOpen = (file, mode, access, share) =>
{
if (file == sourceLinkPath)
@@ -8970,6 +9030,7 @@ public void ParseSeparatedPaths_QuotedComma()
paths);
}
+ [CompilerTrait(CompilerFeature.Determinism)]
[Fact]
public void PathMapParser()
{
@@ -9003,6 +9064,82 @@ public void PathMapParser()
Assert.Equal((int)ErrorCode.ERR_InvalidPathMap, parsedArgs.Errors[0].Code);
}
+ [Fact]
+ [CompilerTrait(CompilerFeature.Determinism)]
+ public void PathMapPdbParser()
+ {
+ var dir = Path.Combine(_baseDirectory, "a");
+ var parsedArgs = DefaultParse(new[] { $@"/pathmap:{dir}=b:\", "a.cs", @"/pdb:a\data.pdb", "/debug:full" }, _baseDirectory);
+ parsedArgs.Errors.Verify();
+ Assert.Equal(Path.Combine(dir, @"data.pdb"), parsedArgs.PdbPath);
+
+ // This value is calculate during Emit phases and should be null even in the face of a pathmap targeting it.
+ Assert.Null(parsedArgs.EmitOptions.PdbFilePath);
+ }
+
+ [Fact]
+ [CompilerTrait(CompilerFeature.Determinism)]
+ public void PathMapPdbEmit()
+ {
+ void AssertPdbEmit(TempDirectory dir, string pdbPath, string pePdbPath, params string[] extraArgs)
+ {
+ var source = @"class Program { static void Main() { } }";
+ var src = dir.CreateFile("a.cs").WriteAllText(source);
+ var defaultArgs = new[] { "/nologo", "a.cs", "/out:a.exe", "/debug:full", $"/pdb:{pdbPath}" };
+ var isDeterministic = extraArgs.Contains("/deterministic");
+ var args = defaultArgs.Concat(extraArgs).ToArray();
+ var outWriter = new StringWriter(CultureInfo.InvariantCulture);
+
+ var csc = new MockCSharpCompiler(null, dir.Path, args);
+ int exitCode = csc.Run(outWriter);
+ Assert.Equal(0, exitCode);
+
+ var exePath = Path.Combine(dir.Path, "a.exe");
+ Assert.True(File.Exists(exePath));
+ Assert.True(File.Exists(pdbPath));
+ using (var peStream = File.OpenRead(exePath))
+ {
+ PdbValidation.ValidateDebugDirectory(peStream, null, pePdbPath, isDeterministic);
+ }
+ }
+
+ // Case with no mappings
+ using (var dir = new DisposableDirectory(Temp))
+ {
+ var pdbPath = Path.Combine(dir.Path, "a.pdb");
+ AssertPdbEmit(dir, pdbPath, pdbPath);
+ }
+
+ // Simple mapping
+ using (var dir = new DisposableDirectory(Temp))
+ {
+ var pdbPath = Path.Combine(dir.Path, "a.pdb");
+ AssertPdbEmit(dir, pdbPath, @"q:\a.pdb", $@"/pathmap:{dir.Path}=q:\");
+ }
+
+ // Simple mapping deterministic
+ using (var dir = new DisposableDirectory(Temp))
+ {
+ var pdbPath = Path.Combine(dir.Path, "a.pdb");
+ AssertPdbEmit(dir, pdbPath, @"q:\a.pdb", $@"/pathmap:{dir.Path}=q:\", "/deterministic");
+ }
+
+ // Partial mapping
+ using (var dir = new DisposableDirectory(Temp))
+ {
+ dir.CreateDirectory("pdb");
+ var pdbPath = Path.Combine(dir.Path, @"pdb\a.pdb");
+ AssertPdbEmit(dir, pdbPath, @"q:\pdb\a.pdb", $@"/pathmap:{dir.Path}=q:\");
+ }
+
+ // Legacy feature flag
+ using (var dir = new DisposableDirectory(Temp))
+ {
+ var pdbPath = Path.Combine(dir.Path, "a.pdb");
+ AssertPdbEmit(dir, pdbPath, @"a.pdb", $@"/features:pdb-path-determinism");
+ }
+ }
+
[WorkItem(7588, "https://github.com/dotnet/roslyn/issues/7588")]
[Fact]
public void Version()
@@ -9024,6 +9161,197 @@ public void Version()
}
}
+ [Fact]
+ public void RefOut()
+ {
+ var dir = Temp.CreateDirectory();
+ var refDir = dir.CreateDirectory("ref");
+
+ var src = dir.CreateFile("a.cs");
+ src.WriteAllText(@"
+public class C
+{
+ /// Main method
+ public static void Main()
+ {
+ System.Console.Write(""Hello"");
+ }
+ /// Private method
+ private static void PrivateMethod()
+ {
+ System.Console.Write(""Private"");
+ }
+}");
+
+ var outWriter = new StringWriter(CultureInfo.InvariantCulture);
+ var csc = new MockCSharpCompiler(null, dir.Path,
+ new[] { "/nologo", "/out:a.exe", "/refout:ref/a.dll", "/doc:doc.xml", "/deterministic", "a.cs" });
+
+ int exitCode = csc.Run(outWriter);
+ Assert.Equal(0, exitCode);
+
+ var exe = Path.Combine(dir.Path, "a.exe");
+ Assert.True(File.Exists(exe));
+
+ MetadataReaderUtils.VerifyPEMetadata(exe,
+ new[] { "TypeDefinition:", "TypeDefinition:C" },
+ new[] { "MethodDefinition:Void Main()", "MethodDefinition:Void PrivateMethod()", "MethodDefinition:Void .ctor()" },
+ new[] { "CompilationRelaxationsAttribute", "RuntimeCompatibilityAttribute", "DebuggableAttribute" }
+ );
+
+ var doc = Path.Combine(dir.Path, "doc.xml");
+ Assert.True(File.Exists(doc));
+
+ var content = File.ReadAllText(doc);
+ var expectedDoc =
+@"
+
+
+ a
+
+
+
+ Main method
+
+
+ Private method
+
+
+";
+ Assert.Equal(expectedDoc, content.Trim());
+
+ var output = ProcessUtilities.RunAndGetOutput(exe, startFolder: dir.Path);
+ Assert.Equal("Hello", output.Trim());
+
+ var refDll = Path.Combine(refDir.Path, "a.dll");
+ Assert.True(File.Exists(refDll));
+
+ // The types and members that are included needs further refinement.
+ // See issue https://github.com/dotnet/roslyn/issues/17612
+ MetadataReaderUtils.VerifyPEMetadata(refDll,
+ new[] { "TypeDefinition:", "TypeDefinition:C" },
+ new[] { "MethodDefinition:Void Main()", "MethodDefinition:Void .ctor()" },
+ new[] { "CompilationRelaxationsAttribute", "RuntimeCompatibilityAttribute", "DebuggableAttribute", "ReferenceAssemblyAttribute" }
+ );
+
+ // Clean up temp files
+ CleanupAllGeneratedFiles(dir.Path);
+ CleanupAllGeneratedFiles(refDir.Path);
+ }
+
+ [Fact]
+ public void RefOutWithError()
+ {
+ var dir = Temp.CreateDirectory();
+ dir.CreateDirectory("ref");
+
+ var src = dir.CreateFile("a.cs");
+ src.WriteAllText(@"class C { public static void Main() { error(); } }");
+
+ var outWriter = new StringWriter(CultureInfo.InvariantCulture);
+ var csc = new MockCSharpCompiler(null, dir.Path,
+ new[] { "/nologo", "/out:a.dll", "/refout:ref/a.dll", "/deterministic", "a.cs" });
+ int exitCode = csc.Run(outWriter);
+ Assert.Equal(1, exitCode);
+
+ var dll = Path.Combine(dir.Path, "a.dll");
+ Assert.False(File.Exists(dll));
+
+ var refDll = Path.Combine(dir.Path, Path.Combine("ref", "a.dll"));
+ Assert.False(File.Exists(refDll));
+
+ Assert.Equal("a.cs(1,39): error CS0103: The name 'error' does not exist in the current context", outWriter.ToString().Trim());
+
+ // Clean up temp files
+ CleanupAllGeneratedFiles(dir.Path);
+ }
+
+ [Fact]
+ public void RefOnly()
+ {
+ var dir = Temp.CreateDirectory();
+
+ var src = dir.CreateFile("a.cs");
+ src.WriteAllText(@"
+using System;
+class C
+{
+ /// Main method
+ public static void Main()
+ {
+ error(); // semantic error in method body
+ }
+ private event Action E1
+ {
+ add { }
+ remove { }
+ }
+ private event Action E2;
+
+ /// Private Class Field
+ private int field;
+
+ /// Private Struct
+ private struct S
+ {
+ /// Private Struct Field
+ private int field;
+ }
+}");
+
+ var outWriter = new StringWriter(CultureInfo.InvariantCulture);
+ var csc = new MockCSharpCompiler(null, dir.Path,
+ new[] { "/nologo", "/out:a.dll", "/refonly", "/debug", "/deterministic", "/doc:doc.xml", "a.cs" });
+ int exitCode = csc.Run(outWriter);
+ Assert.Equal("", outWriter.ToString());
+ Assert.Equal(0, exitCode);
+
+ var refDll = Path.Combine(dir.Path, "a.dll");
+ Assert.True(File.Exists(refDll));
+
+ // The types and members that are included needs further refinement.
+ // See issue https://github.com/dotnet/roslyn/issues/17612
+ MetadataReaderUtils.VerifyPEMetadata(refDll,
+ new[] { "TypeDefinition:", "TypeDefinition:C", "TypeDefinition:S" },
+ new[] { "MethodDefinition:Void Main()", "MethodDefinition:Void .ctor()" },
+ new[] { "CompilationRelaxationsAttribute", "RuntimeCompatibilityAttribute", "DebuggableAttribute", "ReferenceAssemblyAttribute" }
+ );
+
+ var pdb = Path.Combine(dir.Path, "a.pdb");
+ Assert.False(File.Exists(pdb));
+
+ var doc = Path.Combine(dir.Path, "doc.xml");
+ Assert.True(File.Exists(doc));
+
+ var content = File.ReadAllText(doc);
+ var expectedDoc =
+@"
+
+
+ a
+
+
+
+ Main method
+
+
+ Private Class Field
+
+
+ Private Struct
+
+
+ Private Struct Field
+
+
+";
+ Assert.Equal(expectedDoc, content.Trim());
+
+
+ // Clean up temp files
+ CleanupAllGeneratedFiles(dir.Path);
+ }
+
[Fact]
public void CompilingCodeWithInvalidPreProcessorSymbolsShouldProvideDiagnostics()
{
diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Assembly.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Assembly.cs
index a5ed0b9969357..5798e61b98e8d 100644
--- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Assembly.cs
+++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Assembly.cs
@@ -954,7 +954,8 @@ private static void TestDuplicateAssemblyAttributesNotEmitted(AssemblySymbol ass
// We should get only unique netmodule/assembly attributes here, duplicate ones should not be emitted.
int expectedEmittedAttrsCount = expectedSrcAttrCount - expectedDuplicateAttrCount;
- var allEmittedAttrs = assembly.GetCustomAttributesToEmit(new ModuleCompilationState(), emittingAssemblyAttributesInNetModule: false);
+ var allEmittedAttrs = ((SourceAssemblySymbol)assembly).GetCustomAttributesToEmit(new ModuleCompilationState(),
+ emittingRefAssembly: false, emittingAssemblyAttributesInNetModule: false);
var emittedAttrs = allEmittedAttrs.Where(a => string.Equals(a.AttributeClass.Name, attrTypeName, StringComparison.Ordinal)).AsImmutable();
Assert.Equal(expectedEmittedAttrsCount, emittedAttrs.Length);
@@ -1243,7 +1244,8 @@ static void Main(string[] args) { }
expectedDuplicateAttrCount: 1,
attrTypeName: "AssemblyTitleAttribute");
- var attrs = consoleappCompilation.Assembly.GetCustomAttributesToEmit(new ModuleCompilationState(), emittingAssemblyAttributesInNetModule: false);
+ var attrs = ((SourceAssemblySymbol)consoleappCompilation.Assembly).GetCustomAttributesToEmit(new ModuleCompilationState(),
+ emittingRefAssembly: false, emittingAssemblyAttributesInNetModule: false);
foreach (var a in attrs)
{
switch (a.AttributeClass.Name)
diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/WellKnownAttributesTestBase.cs b/src/Compilers/CSharp/Test/Emit/Attributes/WellKnownAttributesTestBase.cs
index 10d44a7cf2c09..332fe419da9ad 100644
--- a/src/Compilers/CSharp/Test/Emit/Attributes/WellKnownAttributesTestBase.cs
+++ b/src/Compilers/CSharp/Test/Emit/Attributes/WellKnownAttributesTestBase.cs
@@ -87,7 +87,7 @@ internal static void VerifyParamArrayAttribute(ParameterSymbol parameter, Source
var paramArrayAttributeCtor = (MethodSymbol)emitModule.Compilation.GetWellKnownTypeMember(WellKnownMember.System_ParamArrayAttribute__ctor);
bool found = false;
- var context = new EmitContext(emitModule, null, new DiagnosticBag());
+ var context = new EmitContext(emitModule, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true);
foreach (Microsoft.Cci.ICustomAttribute attr in parameter.GetSynthesizedAttributes())
{
diff --git a/src/Compilers/CSharp/Test/Emit/CSharpCompilerEmitTest.csproj b/src/Compilers/CSharp/Test/Emit/CSharpCompilerEmitTest.csproj
index 0d8951495e9e2..e4d06c7c65ba6 100644
--- a/src/Compilers/CSharp/Test/Emit/CSharpCompilerEmitTest.csproj
+++ b/src/Compilers/CSharp/Test/Emit/CSharpCompilerEmitTest.csproj
@@ -57,6 +57,9 @@
+
+ Emit\MvidReader.cs
+
@@ -70,6 +73,7 @@
+
@@ -142,14 +146,13 @@
-
+
-
@@ -159,6 +162,7 @@
+
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs
new file mode 100644
index 0000000000000..34bd9f103093a
--- /dev/null
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs
@@ -0,0 +1,1462 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
+using Xunit;
+using System.Threading;
+using Microsoft.CodeAnalysis.Test.Utilities;
+
+namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
+{
+ [CompilerTrait(CompilerFeature.AsyncMain)]
+ public class CodeGenAsyncMainTests : EmitMetadataTestBase
+ {
+ [Fact]
+ public void MultipleMainsOneOfWhichHasBadTaskType_CSharp71_WithMainType()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+namespace System.Threading.Tasks {
+ public class Task {
+ public void GetAwaiter() {}
+ }
+}
+
+static class Program {
+ static Task Main() {
+ return null;
+ }
+ static void Main(string[] args) { }
+}";
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe.WithMainTypeName("Program"), parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ sourceCompilation.VerifyEmitDiagnostics(
+ // (11,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(11, 12));
+ }
+
+ [Fact]
+ public void MultipleMainsOneOfWhichHasBadTaskType_CSharp7()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+namespace System.Threading.Tasks {
+ public class Task {
+ public void GetAwaiter() {}
+ }
+}
+
+static class Program {
+ static Task Main() {
+ return null;
+ }
+ static void Main(string[] args) { }
+}";
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
+ sourceCompilation.VerifyEmitDiagnostics(
+ // (11,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(11, 12),
+ // (11,22): warning CS0028: 'Program.Main()' has the wrong signature to be an entry point
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("Program.Main()").WithLocation(11, 22));
+ }
+
+ [Fact]
+ public void MultipleMainsOneOfWhichHasBadTaskType_CSharp7_WithExplicitMain()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+namespace System.Threading.Tasks {
+ public class Task {
+ public void GetAwaiter() {}
+ }
+}
+
+static class Program {
+ static Task Main() {
+ return null;
+ }
+ static void Main(string[] args) { }
+}";
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe.WithMainTypeName("Program"), parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
+ sourceCompilation.VerifyEmitDiagnostics(
+ // (11,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(11, 12));
+ }
+
+ [Fact]
+ public void MultipleMainsOneOfWhichHasBadTaskType_CSharp71()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+namespace System.Threading.Tasks {
+ public class Task {
+ public void GetAwaiter() {}
+ }
+}
+
+static class Program {
+ static Task Main() {
+ return null;
+ }
+ static void Main(string[] args) { }
+}";
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ sourceCompilation.VerifyEmitDiagnostics(
+ // (11,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(11, 12),
+ // (11,22): warning CS0028: 'Program.Main()' has the wrong signature to be an entry point
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("Program.Main()").WithLocation(11, 22));
+ }
+
+ [Fact]
+ public void GetResultReturnsSomethingElse_CSharp7()
+ {
+ var source = @"
+using System.Threading.Tasks;
+using System;
+
+namespace System.Runtime.CompilerServices {
+ public interface INotifyCompletion {
+ void OnCompleted(Action action);
+ }
+}
+
+namespace System.Threading.Tasks {
+ public class Awaiter: System.Runtime.CompilerServices.INotifyCompletion {
+ public double GetResult() { return 0.0; }
+ public bool IsCompleted => true;
+ public void OnCompleted(Action action) {}
+ }
+ public class Task {
+ public Awaiter GetAwaiter() {
+ return new Awaiter();
+ }
+ }
+}
+
+static class Program {
+ static Task Main() {
+ return null;
+ }
+}";
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
+ sourceCompilation.VerifyEmitDiagnostics(
+ // (25,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(25, 12),
+ // (25,22): warning CS0028: 'Program.Main()' has the wrong signature to be an entry point
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("Program.Main()").WithLocation(25, 22),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void GetResultReturnsSomethingElse_CSharp71()
+ {
+ var source = @"
+using System.Threading.Tasks;
+using System;
+
+namespace System.Runtime.CompilerServices {
+ public interface INotifyCompletion {
+ void OnCompleted(Action action);
+ }
+}
+
+namespace System.Threading.Tasks {
+ public class Awaiter: System.Runtime.CompilerServices.INotifyCompletion {
+ public double GetResult() { return 0.0; }
+ public bool IsCompleted => true;
+ public void OnCompleted(Action action) {}
+ }
+ public class Task {
+ public Awaiter GetAwaiter() {
+ return new Awaiter();
+ }
+ }
+}
+
+static class Program {
+ static Task Main() {
+ return null;
+ }
+}";
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ sourceCompilation.VerifyEmitDiagnostics(
+ // (25,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(25, 12),
+ // (25,22): warning CS0028: 'Program.Main()' has the wrong signature to be an entry point
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("Program.Main()").WithLocation(25, 22),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void TaskOfTGetAwaiterReturnsVoid_CSharp7()
+ {
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+namespace System.Threading.Tasks {
+ public class Task {
+ public void GetAwaiter() {}
+ }
+}
+
+static class Program {
+ static Task Main() {
+ return null;
+ }
+}";
+
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
+ sourceCompilation.VerifyDiagnostics(
+ // (12,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(12, 12),
+ // (12,12): error CS1986: 'await' requires that the type Task have a suitable GetAwaiter method
+ // static Task Main() {
+ Diagnostic(ErrorCode.ERR_BadAwaitArg, "Task").WithArguments("System.Threading.Tasks.Task").WithLocation(12, 12),
+ // (12,22): warning CS0028: 'Program.Main()' has the wrong signature to be an entry point
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("Program.Main()").WithLocation(12, 22),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1),
+ // (2,1): hidden CS8019: Unnecessary using directive.
+ // using System;
+ Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using System;").WithLocation(2, 1));
+ }
+
+ [Fact]
+ public void TaskOfTGetAwaiterReturnsVoid_CSharp71()
+ {
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+namespace System.Threading.Tasks {
+ public class Task {
+ public void GetAwaiter() {}
+ }
+}
+
+static class Program {
+ static Task Main() {
+ return null;
+ }
+}";
+
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ sourceCompilation.VerifyDiagnostics(
+ // (12,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(12, 12),
+ // (12,12): error CS1986: 'await' requires that the type Task have a suitable GetAwaiter method
+ // static Task Main() {
+ Diagnostic(ErrorCode.ERR_BadAwaitArg, "Task").WithArguments("System.Threading.Tasks.Task").WithLocation(12, 12),
+ // (12,22): warning CS0028: 'Program.Main()' has the wrong signature to be an entry point
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("Program.Main()").WithLocation(12, 22),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1),
+ // (2,1): hidden CS8019: Unnecessary using directive.
+ // using System;
+ Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using System;").WithLocation(2, 1));
+ }
+
+ [Fact]
+ public void TaskGetAwaiterReturnsVoid()
+ {
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+namespace System.Threading.Tasks {
+ public class Task {
+ public void GetAwaiter() {}
+ }
+}
+
+static class Program {
+ static Task Main() {
+ return null;
+ }
+}";
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ sourceCompilation.VerifyEmitDiagnostics(
+ // (12,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(12, 12),
+ // (12,12): error CS1986: 'await' requires that the type Task have a suitable GetAwaiter method
+ // static Task Main() {
+ Diagnostic(ErrorCode.ERR_BadAwaitArg, "Task").WithArguments("System.Threading.Tasks.Task").WithLocation(12, 12),
+ // (12,17): warning CS0028: 'Program.Main()' has the wrong signature to be an entry point
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("Program.Main()").WithLocation(12, 17),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MissingMethodsOnTask()
+ {
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+namespace System.Threading.Tasks {
+ public class Task {}
+}
+
+static class Program {
+ static Task Main() {
+ return null;
+ }
+}";
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ sourceCompilation.VerifyEmitDiagnostics(
+ // (10,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(10, 12),
+ // (10,12): error CS1061: 'Task' does not contain a definition for 'GetAwaiter' and no extension method 'GetAwaiter' accepting a first argument of type 'Task' could be found (are you missing a using directive or an assembly reference?)
+ // static Task Main() {
+ Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Task").WithArguments("System.Threading.Tasks.Task", "GetAwaiter").WithLocation(10, 12),
+ // (10,17): warning CS0028: 'Program.Main()' has the wrong signature to be an entry point
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("Program.Main()").WithLocation(10, 17),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void EmitTaskOfIntReturningMainWithoutInt()
+ {
+ var corAssembly = @"
+namespace System {
+ public class Object {}
+ public abstract class ValueType{}
+ public struct Int32{}
+}";
+ var corCompilation = CreateCompilation(corAssembly, options: TestOptions.DebugDll);
+ corCompilation.VerifyDiagnostics();
+
+ var taskAssembly = @"
+namespace System.Threading.Tasks {
+ public class Task{}
+}";
+ var taskCompilation = CreateCompilationWithMscorlib45(taskAssembly, options: TestOptions.DebugDll);
+ taskCompilation.VerifyDiagnostics();
+
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+static class Program {
+ static Task Main() {
+ return null;
+ }
+}";
+ var sourceCompilation = CreateCompilation(source, new[] { corCompilation.ToMetadataReference(), taskCompilation.ToMetadataReference() }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ sourceCompilation.VerifyEmitDiagnostics(
+ // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options.
+ Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1),
+ // (6,17): error CS0518: Predefined type 'System.Int32' is not defined or imported
+ // static Task Main() {
+ Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Task").WithArguments("System.Threading.Tasks.Task", "GetAwaiter").WithLocation(6, 12),
+ // (6,22): warning CS0028: 'Program.Main()' has the wrong signature to be an entry point
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("Program.Main()").WithLocation(6, 22),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void EmitTaskReturningMainWithoutVoid()
+ {
+ var corAssembly = @"
+namespace System {
+ public class Object {}
+}";
+ var corCompilation = CreateCompilation(corAssembly, options: TestOptions.DebugDll);
+ corCompilation.VerifyDiagnostics();
+
+ var taskAssembly = @"
+namespace System.Threading.Tasks {
+ public class Task{}
+}";
+ var taskCompilation = CreateCompilationWithMscorlib45(taskAssembly, options: TestOptions.DebugDll);
+ taskCompilation.VerifyDiagnostics();
+
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+static class Program {
+ static Task Main() {
+ return null;
+ }
+}";
+ var sourceCompilation = CreateCompilation(source, new[] { corCompilation.ToMetadataReference(), taskCompilation.ToMetadataReference() }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ sourceCompilation.VerifyEmitDiagnostics(
+ // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options.
+ Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1),
+ // (6,12): error CS1061: 'Task' does not contain a definition for 'GetAwaiter' and no extension method 'GetAwaiter' accepting a first argument of type 'Task' could be found (are you missing a using directive or an assembly reference?)
+ // static Task Main() {
+ Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Task").WithArguments("System.Threading.Tasks.Task", "GetAwaiter").WithLocation(6, 12),
+ // (6,17): warning CS0028: 'Program.Main()' has the wrong signature to be an entry point
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("Program.Main()").WithLocation(6, 17),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void AsyncEmitMainTest()
+ {
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+class Program {
+ static async Task Main() {
+ Console.Write(""hello "");
+ await Task.Factory.StartNew(() => 5);
+ Console.Write(""async main"");
+ }
+}";
+ var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ var verifier = CompileAndVerify(c, expectedOutput: "hello async main", expectedReturnCode: 0);
+ }
+
+ [Fact]
+ public void AsyncMainTestCodegenWithErrors()
+ {
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+class Program {
+ static async Task Main() {
+ Console.WriteLine(""hello"");
+ await Task.Factory.StartNew(() => 5);
+ Console.WriteLine(""async main"");
+ }
+}";
+ var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ c.VerifyEmitDiagnostics(
+ // (6,28): error CS0161: 'Program.Main()': not all code paths return a value
+ // static async Task Main() {
+ Diagnostic(ErrorCode.ERR_ReturnExpected, "Main").WithArguments("Program.Main()").WithLocation(6, 28));
+ }
+
+
+ [Fact]
+ public void AsyncEmitMainOfIntTest_StringArgs()
+ {
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+class Program {
+ static async Task Main(string[] args) {
+ Console.Write(""hello "");
+ await Task.Factory.StartNew(() => 5);
+ Console.Write(""async main"");
+ return 10;
+ }
+}";
+ var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ var verifier = CompileAndVerify(c, expectedOutput: "hello async main", expectedReturnCode: 10);
+ }
+
+ [Fact]
+ public void AsyncEmitMainOfIntTest_ParamsStringArgs()
+ {
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+class Program {
+ static async Task Main(params string[] args) {
+ Console.Write(""hello "");
+ await Task.Factory.StartNew(() => 5);
+ Console.Write(""async main"");
+ return 10;
+ }
+}";
+ var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ var verifier = CompileAndVerify(c, expectedOutput: "hello async main", expectedReturnCode: 10);
+ }
+
+ [Fact]
+ public void AsyncEmitMainTest_StringArgs()
+ {
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+class Program {
+ static async Task Main(string[] args) {
+ Console.Write(""hello "");
+ await Task.Factory.StartNew(() => 5);
+ Console.Write(""async main"");
+ }
+}";
+ var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ var verifier = CompileAndVerify(c, expectedOutput: "hello async main", expectedReturnCode: 0);
+ }
+
+ [Fact]
+ public void AsyncEmitMainTestCodegenWithErrors_StringArgs()
+ {
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+class Program {
+ static async Task Main(string[] args) {
+ Console.WriteLine(""hello"");
+ await Task.Factory.StartNew(() => 5);
+ Console.WriteLine(""async main"");
+ }
+}";
+ var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ c.VerifyEmitDiagnostics(
+ // (6,28): error CS0161: 'Program.Main()': not all code paths return a value
+ // static async Task Main() {
+ Diagnostic(ErrorCode.ERR_ReturnExpected, "Main").WithArguments("Program.Main(string[])").WithLocation(6, 28));
+ }
+
+ [Fact]
+ public void AsyncEmitMainOfIntTest_StringArgs_WithArgs()
+ {
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+class Program {
+ static async Task Main(string[] args) {
+ Console.Write(""hello "");
+ await Task.Factory.StartNew(() => 5);
+ Console.Write(args[0]);
+ return 10;
+ }
+}";
+ var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ var verifier = CompileAndVerify(c, expectedOutput: "hello async main", expectedReturnCode: 10, args: new string[] { "async main" });
+ }
+
+ [Fact]
+ public void AsyncEmitMainTest_StringArgs_WithArgs()
+ {
+ var source = @"
+using System;
+using System.Threading.Tasks;
+
+class Program {
+ static async Task Main(string[] args) {
+ Console.Write(""hello "");
+ await Task.Factory.StartNew(() => 5);
+ Console.Write(args[0]);
+ }
+}";
+ var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ var verifier = CompileAndVerify(c, expectedOutput: "hello async main", expectedReturnCode: 0, args: new string[] { "async main" });
+ }
+
+ [Fact]
+ public void MainCanBeAsyncWithArgs()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static Task Main(string[] args)
+ {
+ await Task.Factory.StartNew(() => { });
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ compilation.VerifyDiagnostics();
+ var entry = compilation.GetEntryPoint(CancellationToken.None);
+ Assert.NotNull(entry);
+ Assert.Equal("System.Threading.Tasks.Task A.Main(System.String[] args)", entry.ToTestDisplayString());
+
+ CompileAndVerify(compilation, expectedReturnCode: 0);
+ }
+
+ [Fact]
+ public void MainCanReturnTaskWithArgs_NoAsync()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static Task Main(string[] args)
+ {
+ return Task.Factory.StartNew(() => { });
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ compilation.VerifyDiagnostics();
+ var entry = compilation.GetEntryPoint(CancellationToken.None);
+ Assert.NotNull(entry);
+ Assert.Equal("System.Threading.Tasks.Task A.Main(System.String[] args)", entry.ToTestDisplayString());
+
+ CompileAndVerify(compilation, expectedReturnCode: 0);
+ }
+
+
+ [Fact]
+ public void MainCantBeAsyncWithRefTask()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static ref Task Main(string[] args)
+ {
+ throw new System.Exception();
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ compilation.VerifyDiagnostics(
+ // (6,21): warning CS0028: 'A.Main(string[])' has the wrong signature to be an entry point
+ // static ref Task Main(string[] args)
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main(string[])").WithLocation(6, 21),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MainCantBeAsyncWithArgs_CSharp7()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static Task Main(string[] args)
+ {
+ await Task.Factory.StartNew(() => { });
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
+ compilation.VerifyDiagnostics(
+ // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater.
+ // async static Task Main(string[] args)
+ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 18),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MainCantBeAsyncWithArgs_CSharp7_NoAwait()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static Task Main(string[] args)
+ {
+ return Task.Factory.StartNew(() => { });
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
+ compilation.VerifyDiagnostics(
+ // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater.
+ // async static Task Main(string[] args)
+ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 12),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MainCanReturnTask()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static Task Main()
+ {
+ await Task.Factory.StartNew(() => { });
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ compilation.VerifyDiagnostics();
+ var entry = compilation.GetEntryPoint(CancellationToken.None);
+ Assert.NotNull(entry);
+ Assert.Equal("System.Threading.Tasks.Task A.Main()", entry.ToTestDisplayString());
+ }
+ [Fact]
+ public void MainCanReturnTask_NoAsync()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static Task Main()
+ {
+ return Task.Factory.StartNew(() => { });
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ compilation.VerifyDiagnostics();
+ var entry = compilation.GetEntryPoint(CancellationToken.None);
+ Assert.NotNull(entry);
+ Assert.Equal("System.Threading.Tasks.Task A.Main()", entry.ToTestDisplayString());
+ }
+
+ [Fact]
+ public void MainCantBeAsyncVoid_CSharp7()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static void Main()
+ {
+ await Task.Factory.StartNew(() => { });
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
+ compilation.VerifyDiagnostics(
+ // (6,23): error CS9003: Async Main methods must return Task or Task
+ // async static void Main()
+ Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithArguments("A.Main()").WithLocation(6, 23),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MainCantBeAsyncInt()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static int Main()
+ {
+ return await Task.Factory.StartNew(() => 5);
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ compilation.VerifyDiagnostics(
+ // (6,22): error CS1983: The return type of an async method must be void, Task or Task
+ // async static int Main()
+ Diagnostic(ErrorCode.ERR_BadAsyncReturn, "Main").WithLocation(6, 22),
+ // (6,22): error CS4009: A void or int returning entry point cannot be async
+ // async static int Main()
+ Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithArguments("A.Main()").WithLocation(6, 22),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ var entry = compilation.GetEntryPoint(CancellationToken.None);
+ Assert.Null(entry);
+ }
+
+ [Fact]
+ public void MainCantBeAsyncInt_CSharp7()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static int Main()
+ {
+ return await Task.Factory.StartNew(() => 5);
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
+ compilation.VerifyDiagnostics(
+ // (6,22): error CS1983: The return type of an async method must be void, Task or Task
+ // async static int Main()
+ Diagnostic(ErrorCode.ERR_BadAsyncReturn, "Main").WithLocation(6, 22),
+ // (6,22): error CS9003: Async Main methods must return Task or Task
+ // async static int Main()
+ Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithArguments("A.Main()").WithLocation(6, 22),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MainCanReturnTaskAndGenericOnInt_WithArgs()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static Task Main(string[] args)
+ {
+ return await Task.Factory.StartNew(() => 5);
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ compilation.VerifyDiagnostics();
+ var entry = compilation.GetEntryPoint(CancellationToken.None);
+ Assert.NotNull(entry);
+ Assert.Equal("System.Threading.Tasks.Task A.Main(System.String[] args)", entry.ToTestDisplayString());
+ }
+
+ [Fact]
+ public void MainCanReturnTaskAndGenericOnInt_WithArgs_NoAsync()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static Task Main(string[] args)
+ {
+ return Task.Factory.StartNew(() => 5);
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ compilation.VerifyDiagnostics();
+ var entry = compilation.GetEntryPoint(CancellationToken.None);
+ Assert.NotNull(entry);
+ Assert.Equal("System.Threading.Tasks.Task A.Main(System.String[] args)", entry.ToTestDisplayString());
+ }
+
+ [Fact]
+ public void MainCantBeAsyncAndGenericOnInt_WithArgs_Csharp7()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static Task Main(string[] args)
+ {
+ return await Task.Factory.StartNew(() => 5);
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
+ compilation.VerifyDiagnostics(
+ // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater.
+ // async static Task Main(string[] args)
+ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 18),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MainCantBeAsyncAndGenericOnInt_WithArgs_Csharp7_NoAsync()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static Task Main(string[] args)
+ {
+ return Task.Factory.StartNew(() => 5);
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
+ compilation.VerifyDiagnostics(
+ // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater.
+ // async static Task Main(string[] args)
+ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 12),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MainCanReturnTaskAndGenericOnInt()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static Task Main()
+ {
+ return await Task.Factory.StartNew(() => 5);
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ compilation.VerifyDiagnostics();
+ var entry = compilation.GetEntryPoint(CancellationToken.None);
+ Assert.NotNull(entry);
+ Assert.Equal("System.Threading.Tasks.Task A.Main()", entry.ToTestDisplayString());
+ }
+
+ [Fact]
+ public void MainCanReturnTaskAndGenericOnInt_NoAsync()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static Task Main()
+ {
+ return Task.Factory.StartNew(() => 5);
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ compilation.VerifyDiagnostics();
+ var entry = compilation.GetEntryPoint(CancellationToken.None);
+ Assert.NotNull(entry);
+ Assert.Equal("System.Threading.Tasks.Task A.Main()", entry.ToTestDisplayString());
+ }
+
+ [Fact]
+ public void MainCantBeAsyncAndGenericOnInt_CSharp7()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static Task Main()
+ {
+ return await Task.Factory.StartNew(() => 5);
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
+ compilation.VerifyDiagnostics(
+ // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater.
+ // async static Task Main()
+ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 18),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MainCantBeAsyncAndGenericOnInt_CSharp7_NoAsync()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static Task Main()
+ {
+ return Task.Factory.StartNew(() => 5);
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7));
+ compilation.VerifyDiagnostics(
+ // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater.
+ // async static Task Main()
+ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 12),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MainCantBeAsyncAndGenericOverFloats()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static Task Main()
+ {
+ await Task.Factory.StartNew(() => { });
+ return 0;
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ compilation.VerifyDiagnostics(
+ // (6,30): warning CS0028: 'A.Main()' has the wrong signature to be an entry point
+ // async static Task Main()
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main()").WithLocation(6, 30),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MainCantBeAsync_AndGeneric()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static void Main()
+ {
+ await Task.Factory.StartNew(() => { });
+ }
+}";
+ CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics(
+ // (6,23): warning CS0402: 'A.Main()': an entry point cannot be generic or in a generic type
+ // async static void Main()
+ Diagnostic(ErrorCode.WRN_MainCantBeGeneric, "Main").WithArguments("A.Main()").WithLocation(6, 23),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MainCantBeAsync_AndBadSig()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static void Main(bool truth)
+ {
+ await Task.Factory.StartNew(() => { });
+ }
+}";
+ CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
+ // (6,23): warning CS0028: 'A.Main(bool)' has the wrong signature to be an entry point
+ // async static void Main(bool truth)
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main(bool)").WithLocation(6, 23),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void MainCantBeAsync_AndGeneric_AndBadSig()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static void Main(bool truth)
+ {
+ await Task.Factory.StartNew(() => { });
+ }
+}";
+ CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
+ // (6,23): warning CS0028: 'A.Main(bool)' has the wrong signature to be an entry point
+ // async static void Main(bool truth)
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main(bool)").WithLocation(6, 23),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void TaskMainAndNonTaskMain()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static void Main()
+ {
+ System.Console.WriteLine(""Non Task Main"");
+ }
+ async static Task Main(string[] args)
+ {
+ await Task.Factory.StartNew(() => { });
+ System.Console.WriteLine(""Task Main"");
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)).VerifyDiagnostics();
+ CompileAndVerify(compilation, expectedOutput: "Non Task Main", expectedReturnCode: 0);
+ }
+
+ [Fact]
+ public void TaskMainAndNonTaskMain_CSharp71()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static void Main()
+ {
+ System.Console.WriteLine(""Non Task Main"");
+ }
+ async static Task Main(string[] args)
+ {
+ await Task.Factory.StartNew(() => { });
+ System.Console.WriteLine(""Task Main"");
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics();
+ CompileAndVerify(compilation, expectedOutput: "Non Task Main", expectedReturnCode: 0);
+ }
+
+ [Fact]
+ public void AsyncVoidMain_CSharp7()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static void Main(string[] args)
+ {
+ await Task.Factory.StartNew(() => { });
+ System.Console.WriteLine(""Async Void Main"");
+ }
+ async static int Main()
+ {
+ await Task.Factory.StartNew(() => { });
+ System.Console.WriteLine(""Async Void Main"");
+ return 1;
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
+ // (11,22): error CS1983: The return type of an async method must be void, Task or Task
+ // async static int Main()
+ Diagnostic(ErrorCode.ERR_BadAsyncReturn, "Main").WithLocation(11, 22),
+ // (11,22): error CS4009: A void or int returning entry point cannot be async
+ // async static int Main()
+ Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithArguments("A.Main()").WithLocation(11, 22),
+ // (6,23): error CS4009: A void or int returning entry point cannot be async
+ // async static void Main(string[] args)
+ Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithArguments("A.Main(string[])").WithLocation(6, 23),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void AsyncVoidMain_CSharp71()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static async void Main(string[] args)
+ {
+ await Task.Factory.StartNew(() => { });
+ System.Console.WriteLine(""Async Void Main"");
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics(
+ // (6,23): error CS4009: A void or int returning entry point cannot be async
+ // static async void Main(string[] args)
+ Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithArguments("A.Main(string[])").WithLocation(6, 23),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void TaskMainAndNonTaskMain_WithExplicitMain()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static void Main()
+ {
+ System.Console.WriteLine(""Non Task Main"");
+ }
+ async static Task Main(string[] args)
+ {
+ await Task.Factory.StartNew(() => { });
+ System.Console.WriteLine(""Task Main"");
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithMainTypeName("A")).VerifyDiagnostics();
+ CompileAndVerify(compilation, expectedOutput: "Non Task Main", expectedReturnCode: 0);
+ }
+
+ [Fact]
+ public void TaskIntAndTaskFloat_CSharp7()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ async static Task Main()
+ {
+ System.Console.WriteLine(""Task"");
+ return 0;
+ }
+
+ async static Task Main(string[] args)
+ {
+ System.Console.WriteLine(""Task"");
+ return 0.0F;
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseDebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)).VerifyDiagnostics(
+ // (6,28): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
+ // async static Task Main()
+ Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Main").WithLocation(6, 28),
+ // (12,30): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
+ // async static Task Main(string[] args)
+ Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Main").WithLocation(12, 30),
+ // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater.
+ // async static Task Main()
+ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 18),
+ // (12,30): warning CS0028: 'A.Main(string[])' has the wrong signature to be an entry point
+ // async static Task Main(string[] args)
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main(string[])").WithLocation(12, 30),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void TaskIntAndTaskFloat_CSharp7_NoAsync()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static Task Main()
+ {
+ System.Console.WriteLine(""Task"");
+ return Task.FromResult(0);
+ }
+
+ static Task Main(string[] args)
+ {
+ System.Console.WriteLine(""Task"");
+ return Task.FromResult(0.0F);
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseDebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)).VerifyDiagnostics(
+ // (6,12): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater.
+ // static Task Main()
+ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 12),
+ // (12,24): warning CS0028: 'A.Main(string[])' has the wrong signature to be an entry point
+ // static Task Main(string[] args)
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main(string[])").WithLocation(12, 24),
+ // error CS5001: Program does not contain a static 'Main' method suitable for an entry point
+ Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1));
+ }
+
+ [Fact]
+ public void TaskOfFloatMainAndNonTaskMain()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static void Main()
+ {
+ System.Console.WriteLine(""Non Task Main"");
+ }
+
+ async static Task Main(string[] args)
+ {
+ await Task.Factory.StartNew(() => { });
+ System.Console.WriteLine(""Task Main"");
+ return 0.0f;
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe).VerifyDiagnostics(
+ // (10,30): warning CS0028: 'A.Main(string[])' has the wrong signature to be an entry point
+ // async static Task Main(string[] args)
+ Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main(string[])").WithLocation(11, 30));
+ CompileAndVerify(compilation, expectedOutput: "Non Task Main", expectedReturnCode: 0);
+ }
+
+ [Fact]
+ public void TaskOfFloatMainAndNonTaskMain_WithExplicitMain()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+class A
+{
+ static void Main()
+ {
+ System.Console.WriteLine(""Non Task Main"");
+ }
+
+ async static Task Main(string[] args)
+ {
+ await Task.Factory.StartNew(() => { });
+ System.Console.WriteLine(""Task Main"");
+ return 0.0f;
+ }
+}";
+ var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithMainTypeName("A")).VerifyDiagnostics();
+ CompileAndVerify(compilation, expectedOutput: "Non Task Main", expectedReturnCode: 0);
+ }
+
+ [Fact]
+ public void ImplementGetAwaiterGetResultViaExtensionMethods()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+namespace System.Runtime.CompilerServices {
+ public class ExtensionAttribute {}
+}
+
+namespace System.Runtime.CompilerServices {
+ public interface INotifyCompletion {
+ void OnCompleted(Action action);
+ }
+}
+
+namespace System.Threading.Tasks {
+ public class Awaiter: System.Runtime.CompilerServices.INotifyCompletion {
+ public bool IsCompleted => true;
+ public void OnCompleted(Action action) {}
+ public void GetResult() {
+ System.Console.Write(""GetResult called"");
+ }
+ }
+ public class Task {}
+}
+
+public static class MyExtensions {
+ public static Awaiter GetAwaiter(this Task task) {
+ System.Console.Write(""GetAwaiter called | "");
+ return new Awaiter();
+ }
+}
+
+static class Program {
+ static Task Main() {
+ return new Task();
+ }
+}";
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ var verifier = sourceCompilation.VerifyEmitDiagnostics(
+ // (26,43): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // public static Awaiter GetAwaiter(this Task task) {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(26, 43),
+ // (33,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(33, 12),
+ // (34,20): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // return new Task();
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(34, 20));
+ CompileAndVerify(sourceCompilation, expectedOutput: "GetAwaiter called | GetResult called");
+ }
+
+ [Fact]
+ public void ImplementGetAwaiterGetResultViaExtensionMethods_Obsolete()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+namespace System.Runtime.CompilerServices {
+ public class ExtensionAttribute {}
+}
+
+namespace System.Runtime.CompilerServices {
+ public interface INotifyCompletion {
+ void OnCompleted(Action action);
+ }
+}
+
+namespace System.Threading.Tasks {
+ public class Awaiter: System.Runtime.CompilerServices.INotifyCompletion {
+ public bool IsCompleted => true;
+ public void OnCompleted(Action action) {}
+ public void GetResult() {
+ System.Console.Write(""GetResult called"");
+ }
+ }
+ public class Task {}
+}
+
+public static class MyExtensions {
+ [System.Obsolete(""test"")]
+ public static Awaiter GetAwaiter(this Task task) {
+ System.Console.Write(""GetAwaiter called | "");
+ return new Awaiter();
+ }
+}
+
+static class Program {
+ static Task Main() {
+ return new Task();
+ }
+}";
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ var verifier = sourceCompilation.VerifyEmitDiagnostics(
+ // (34,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(34, 12),
+ // (27,43): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // public static Awaiter GetAwaiter(this Task task) {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(27, 43),
+ // (35,20): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // return new Task();
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(35, 20),
+ // (34,12): warning CS0618: 'MyExtensions.GetAwaiter(Task)' is obsolete: 'test'
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "Task").WithArguments("MyExtensions.GetAwaiter(System.Threading.Tasks.Task)", "test").WithLocation(34, 12));
+
+ CompileAndVerify(sourceCompilation, expectedOutput: "GetAwaiter called | GetResult called");
+ }
+
+ [Fact]
+ public void ImplementGetAwaiterGetResultViaExtensionMethods_ObsoleteFailing()
+ {
+ var source = @"
+using System.Threading.Tasks;
+
+namespace System.Runtime.CompilerServices {
+ public class ExtensionAttribute {}
+}
+
+namespace System.Runtime.CompilerServices {
+ public interface INotifyCompletion {
+ void OnCompleted(Action action);
+ }
+}
+
+namespace System.Threading.Tasks {
+ public class Awaiter: System.Runtime.CompilerServices.INotifyCompletion {
+ public bool IsCompleted => true;
+ public void OnCompleted(Action action) {}
+ public void GetResult() {}
+ }
+ public class Task {}
+}
+
+public static class MyExtensions {
+ [System.Obsolete(""test"", true)]
+ public static Awaiter GetAwaiter(this Task task) {
+ return null;
+ }
+}
+
+static class Program {
+ static Task Main() {
+ return new Task();
+ }
+}";
+ var sourceCompilation = CreateStandardCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1));
+ var verifier = sourceCompilation.VerifyEmitDiagnostics(
+ // (25,43): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // public static Awaiter GetAwaiter(this Task task) {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(25, 43),
+ // (31,12): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // static Task Main() {
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(31, 12),
+ // (32,20): warning CS0436: The type 'Task' in '' conflicts with the imported type 'Task' in 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Using the type defined in ''.
+ // return new Task();
+ Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Task").WithArguments("", "System.Threading.Tasks.Task", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Threading.Tasks.Task").WithLocation(32, 20),
+ // (31,12): warning CS0618: 'MyExtensions.GetAwaiter(Task)' is obsolete: 'test'
+ // static Task Main() {
+ Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Task").WithArguments("MyExtensions.GetAwaiter(System.Threading.Tasks.Task)", "test").WithLocation(31, 12));
+ }
+ }
+}
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenCheckedTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenCheckedTests.cs
index b6ad41829bbd3..1886c8c03e445 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenCheckedTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenCheckedTests.cs
@@ -2367,5 +2367,416 @@ .locals init (int V_0)
}
");
}
+
+ [Fact]
+ public void CheckedConversionsInExpressionTrees_Implicit()
+ {
+ // char
+ CheckedConversionInExpressionTree_Implicit("char", "char", ConvertMethod.None);
+ CheckedConversionInExpressionTree_Implicit("char", "ushort", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("char", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("char", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("char", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("char", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("char", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("char", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("char", "double", ConvertMethod.Convert);
+
+ // sbyte
+ CheckedConversionInExpressionTree_Implicit("sbyte", "sbyte", ConvertMethod.None);
+ CheckedConversionInExpressionTree_Implicit("sbyte", "short", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("sbyte", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("sbyte", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("sbyte", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("sbyte", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("sbyte", "double", ConvertMethod.Convert);
+
+ // byte
+ CheckedConversionInExpressionTree_Implicit("byte", "byte", ConvertMethod.None);
+ CheckedConversionInExpressionTree_Implicit("byte", "short", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("byte", "ushort", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("byte", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("byte", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("byte", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("byte", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("byte", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("byte", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("byte", "double", ConvertMethod.Convert);
+
+ // short
+ CheckedConversionInExpressionTree_Implicit("short", "short", ConvertMethod.None);
+ CheckedConversionInExpressionTree_Implicit("short", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("short", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("short", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("short", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("short", "double", ConvertMethod.Convert);
+
+ // ushort
+ CheckedConversionInExpressionTree_Implicit("ushort", "ushort", ConvertMethod.None);
+ CheckedConversionInExpressionTree_Implicit("ushort", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("ushort", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("ushort", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("ushort", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("ushort", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("ushort", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("ushort", "double", ConvertMethod.Convert);
+
+ // int
+ CheckedConversionInExpressionTree_Implicit("int", "int", ConvertMethod.None);
+ CheckedConversionInExpressionTree_Implicit("int", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("int", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("int", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("int", "double", ConvertMethod.Convert);
+
+ // uint
+ CheckedConversionInExpressionTree_Implicit("uint", "uint", ConvertMethod.None);
+ CheckedConversionInExpressionTree_Implicit("uint", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("uint", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Implicit("uint", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("uint", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("uint", "double", ConvertMethod.Convert);
+
+ // long
+ CheckedConversionInExpressionTree_Implicit("long", "long", ConvertMethod.None);
+ CheckedConversionInExpressionTree_Implicit("long", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("long", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("long", "double", ConvertMethod.Convert);
+
+ // ulong
+ CheckedConversionInExpressionTree_Implicit("ulong", "ulong", ConvertMethod.None);
+ CheckedConversionInExpressionTree_Implicit("ulong", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("ulong", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("ulong", "double", ConvertMethod.Convert);
+
+ // decimal
+ CheckedConversionInExpressionTree_Implicit("decimal", "decimal", ConvertMethod.None);
+
+ // float
+ CheckedConversionInExpressionTree_Implicit("float", "float", ConvertMethod.None);
+ CheckedConversionInExpressionTree_Implicit("float", "double", ConvertMethod.Convert);
+
+ // double
+ CheckedConversionInExpressionTree_Implicit("double", "double", ConvertMethod.None);
+
+ // object
+ CheckedConversionInExpressionTree_Implicit("int", "object", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Implicit("string", "object", ConvertMethod.None);
+
+ // Nullable<>
+ CheckedConversionInExpressionTree_Implicit("int", "int?", "arg => F(Convert(arg))");
+ CheckedConversionInExpressionTree_Implicit("int", "long?", "arg => F(ConvertChecked(ConvertChecked(arg)))");
+ }
+
+ [Fact]
+ [WorkItem(18459, "https://github.com/dotnet/roslyn/issues/18459")]
+ public void CheckedConversionsInExpressionTrees_ImplicitTuple()
+ {
+ CheckedConversionInExpressionTree_Implicit("(int, int)", "(int, int)?", ConvertMethod.Convert);
+ }
+
+ [Fact]
+ public void CheckedConversionsInExpressionTrees_Explicit()
+ {
+ // char
+ CheckedConversionInExpressionTree_Explicit("char", "char", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("char", "sbyte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("char", "byte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("char", "short", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("char", "ushort", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("char", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("char", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("char", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("char", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("char", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("char", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("char", "double", ConvertMethod.Convert);
+
+ // sbyte
+ CheckedConversionInExpressionTree_Explicit("sbyte", "char", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("sbyte", "sbyte", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("sbyte", "byte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("sbyte", "short", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("sbyte", "ushort", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("sbyte", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("sbyte", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("sbyte", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("sbyte", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("sbyte", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("sbyte", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("sbyte", "double", ConvertMethod.Convert);
+
+ // byte
+ CheckedConversionInExpressionTree_Explicit("byte", "char", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("byte", "sbyte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("byte", "byte", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("byte", "short", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("byte", "ushort", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("byte", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("byte", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("byte", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("byte", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("byte", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("byte", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("byte", "double", ConvertMethod.Convert);
+
+ // short
+ CheckedConversionInExpressionTree_Explicit("short", "char", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("short", "sbyte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("short", "byte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("short", "short", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("short", "ushort", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("short", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("short", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("short", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("short", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("short", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("short", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("short", "double", ConvertMethod.Convert);
+
+ // ushort
+ CheckedConversionInExpressionTree_Explicit("ushort", "char", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ushort", "sbyte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ushort", "byte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ushort", "short", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ushort", "ushort", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("ushort", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ushort", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ushort", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ushort", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ushort", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("ushort", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("ushort", "double", ConvertMethod.Convert);
+
+ // int
+ CheckedConversionInExpressionTree_Explicit("int", "char", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("int", "sbyte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("int", "byte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("int", "short", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("int", "ushort", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("int", "int", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("int", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("int", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("int", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("int", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("int", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("int", "double", ConvertMethod.Convert);
+
+ // uint
+ CheckedConversionInExpressionTree_Explicit("uint", "char", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("uint", "sbyte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("uint", "byte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("uint", "short", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("uint", "ushort", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("uint", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("uint", "uint", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("uint", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("uint", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("uint", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("uint", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("uint", "double", ConvertMethod.Convert);
+
+ // long
+ CheckedConversionInExpressionTree_Explicit("long", "char", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("long", "sbyte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("long", "byte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("long", "short", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("long", "ushort", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("long", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("long", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("long", "long", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("long", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("long", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("long", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("long", "double", ConvertMethod.Convert);
+
+ // ulong
+ CheckedConversionInExpressionTree_Explicit("ulong", "char", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ulong", "sbyte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ulong", "byte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ulong", "short", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ulong", "ushort", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ulong", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ulong", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ulong", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("ulong", "ulong", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("ulong", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("ulong", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("ulong", "double", ConvertMethod.Convert);
+
+ // decimal
+ CheckedConversionInExpressionTree_Explicit("decimal", "char", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("decimal", "sbyte", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("decimal", "byte", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("decimal", "short", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("decimal", "ushort", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("decimal", "int", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("decimal", "uint", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("decimal", "long", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("decimal", "ulong", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("decimal", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("decimal", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("decimal", "double", ConvertMethod.Convert);
+
+ // float
+ CheckedConversionInExpressionTree_Explicit("float", "char", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("float", "sbyte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("float", "byte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("float", "short", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("float", "ushort", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("float", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("float", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("float", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("float", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("float", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("float", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("float", "double", ConvertMethod.Convert);
+
+ // double
+ CheckedConversionInExpressionTree_Explicit("double", "char", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("double", "sbyte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("double", "byte", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("double", "short", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("double", "ushort", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("double", "int", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("double", "uint", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("double", "long", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("double", "ulong", ConvertMethod.ConvertChecked);
+ CheckedConversionInExpressionTree_Explicit("double", "decimal", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("double", "float", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("double", "double", ConvertMethod.Convert);
+
+ // enum
+ CheckedConversionInExpressionTree_Explicit("E", "int", ConvertMethod.ConvertChecked, "enum E { }");
+ CheckedConversionInExpressionTree_Explicit("int", "E", ConvertMethod.ConvertChecked, "enum E { }");
+ CheckedConversionInExpressionTree_Explicit("E", "int", ConvertMethod.ConvertChecked, "enum E : short { }");
+ CheckedConversionInExpressionTree_Explicit("int", "E", ConvertMethod.ConvertChecked, "enum E : short { }");
+
+ // object
+ CheckedConversionInExpressionTree_Explicit("int", "object", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("object", "int", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("string", "object", ConvertMethod.Convert);
+ CheckedConversionInExpressionTree_Explicit("object", "string", ConvertMethod.Convert);
+
+ // Nullable<>
+ CheckedConversionInExpressionTree_Explicit("int", "byte?", "arg => ConvertChecked(arg)");
+ CheckedConversionInExpressionTree_Explicit("int", "int?", "arg => ConvertChecked(arg)");
+ CheckedConversionInExpressionTree_Explicit("int", "long?", "arg => ConvertChecked(ConvertChecked(arg))");
+ }
+
+ [Fact]
+ public void CheckedConversionsInExpressionTrees_ExplicitTuple()
+ {
+ CheckedConversionInExpressionTree_Explicit("(int, int)", "(int, int)?", ConvertMethod.Convert);
+ }
+
+ private enum ConvertMethod
+ {
+ None,
+ Convert,
+ ConvertChecked,
+ }
+
+ private void CheckedConversionInExpressionTree_Implicit(string fromType, string toType, ConvertMethod expectedMethod, string additionalTypes = "")
+ {
+ var source = CheckedConversionInExpressionTree_ImplicitSource(fromType, toType, additionalTypes);
+ var compilation = CreateCompilationWithMscorlibAndSystemCore(source, options: TestOptions.ReleaseExe, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
+ string expectedOutput;
+ switch (expectedMethod)
+ {
+ default:
+ expectedOutput = "arg => F(arg)";
+ break;
+ case ConvertMethod.Convert:
+ expectedOutput = "arg => F(Convert(arg))";
+ break;
+ case ConvertMethod.ConvertChecked:
+ expectedOutput = "arg => F(ConvertChecked(arg))";
+ break;
+ }
+ var verifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
+ // Since Expression.ConvertChecked can generate a Checked result
+ // (rather than ConvertChecked), verify the correct method was called.
+ VerifyConversionInExpressionTreeIL(verifier.TestData.GetMethodData("C.Main").GetMethodIL(), expectedMethod);
+ }
+
+ private void CheckedConversionInExpressionTree_Implicit(string fromType, string toType, string expectedOutput)
+ {
+ var source = CheckedConversionInExpressionTree_ImplicitSource(fromType, toType, additionalTypes: "");
+ var compilation = CreateCompilationWithMscorlibAndSystemCore(source, options: TestOptions.ReleaseExe);
+ CompileAndVerify(compilation, expectedOutput: expectedOutput);
+ }
+
+ private static string CheckedConversionInExpressionTree_ImplicitSource(string fromType, string toType, string additionalTypes)
+ {
+ return
+$@"using System;
+using System.Linq.Expressions;
+{additionalTypes}
+class C
+{{
+ static {toType} F({toType} arg) => arg;
+ static void Main()
+ {{
+ Expression> e = arg => checked(F(arg));
+ Console.WriteLine(e);
+ }}
+}}";
+ }
+
+ private void CheckedConversionInExpressionTree_Explicit(string fromType, string toType, ConvertMethod expectedMethod, string additionalTypes = "")
+ {
+ var source = CheckedConversionInExpressionTree_ExplicitSource(fromType, toType, additionalTypes);
+ var compilation = CreateCompilationWithMscorlibAndSystemCore(source, options: TestOptions.ReleaseExe, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
+ string expectedOutput;
+ switch (expectedMethod)
+ {
+ default:
+ expectedOutput = "arg => arg";
+ break;
+ case ConvertMethod.Convert:
+ expectedOutput = "arg => Convert(arg)";
+ break;
+ case ConvertMethod.ConvertChecked:
+ expectedOutput = "arg => ConvertChecked(arg)";
+ break;
+ }
+ var verifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
+ // Since Expression.ConvertChecked can generate a Checked result
+ // (rather than ConvertChecked), verify the correct method was called.
+ VerifyConversionInExpressionTreeIL(verifier.TestData.GetMethodData("C.Main").GetMethodIL(), expectedMethod);
+ }
+
+ private void CheckedConversionInExpressionTree_Explicit(string fromType, string toType, string expectedOutput)
+ {
+ var source = CheckedConversionInExpressionTree_ExplicitSource(fromType, toType, additionalTypes: "");
+ var compilation = CreateCompilationWithMscorlibAndSystemCore(source, options: TestOptions.ReleaseExe);
+ CompileAndVerify(compilation, expectedOutput: expectedOutput);
+ }
+
+ private static string CheckedConversionInExpressionTree_ExplicitSource(string fromType, string toType, string additionalTypes)
+ {
+ return
+$@"using System;
+using System.Linq.Expressions;
+{additionalTypes}
+class C
+{{
+ static void Main()
+ {{
+ Expression> e = arg => checked(({toType})arg);
+ Console.WriteLine(e);
+ }}
+}}";
+ }
+
+ private static void VerifyConversionInExpressionTreeIL(string actualIL, ConvertMethod expectedMethod)
+ {
+ Assert.Equal(
+ actualIL.Contains($"System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, "),
+ expectedMethod == ConvertMethod.Convert);
+ Assert.Equal(
+ actualIL.Contains($"System.Linq.Expressions.Expression.ConvertChecked(System.Linq.Expressions.Expression, "),
+ expectedMethod == ConvertMethod.ConvertChecked);
+ }
}
}
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs
index 75a50e471aa80..0f1e7cddca389 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs
@@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
public static class LocalFunctionTestsUtil
{
- public static IMethodSymbol FindLocalFunction(this CommonTestBase.CompilationVerifier verifier, string localFunctionName)
+ public static IMethodSymbol FindLocalFunction(this CompilationVerifier verifier, string localFunctionName)
{
localFunctionName = (char)GeneratedNameKind.LocalFunction + "__" + localFunctionName;
var methods = verifier.TestData.GetMethodsByName();
@@ -4038,7 +4038,7 @@ .locals init (Program.<>c__DisplayClass0_0 V_0, //CS$<>8__locals0
}
");
}
-
+
internal CompilationVerifier VerifyOutput(string source, string output, CSharpCompilationOptions options)
{
var comp = CreateCompilationWithMscorlib45AndCSruntime(source, options: options);
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLockTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLockTests.cs
index 6a0f3d1eeba35..7bca136e11e92 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLockTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLockTests.cs
@@ -57,7 +57,7 @@ .locals init (object V_0,
IL_0023: brfalse.s IL_002b
IL_0025: ldloc.0
IL_0026: call ""void System.Threading.Monitor.Exit(object)""
- IL_002b: endfinally
+ ~IL_002b: endfinally
}
-IL_002c: ldstr ""After""
IL_0031: call ""void System.Console.WriteLine(string)""
@@ -112,7 +112,7 @@ .locals init (object V_0,
IL_0027: brfalse.s IL_002f
IL_0029: ldloc.0
IL_002a: call ""void System.Threading.Monitor.Exit(object)""
- IL_002f: endfinally
+ ~IL_002f: endfinally
}
-IL_0030: ldstr ""After""
IL_0035: call ""void System.Console.WriteLine(string)""
@@ -387,7 +387,7 @@ .locals init (object V_0,
IL_0027: brfalse.s IL_002f
IL_0029: ldloc.0
IL_002a: call ""void System.Threading.Monitor.Exit(object)""
- IL_002f: endfinally
+ ~IL_002f: endfinally
}
-IL_0030: ldstr ""After""
IL_0035: call ""void System.Console.WriteLine(string)""
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs
index 31b15e6ec6269..b8eac7aeae28b 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs
@@ -12826,6 +12826,7 @@ static System.Action M()
compilation: compilation,
moduleBeingBuiltOpt: module,
emittingPdb: false,
+ emitTestCoverageData: false,
hasDeclarationErrors: false,
diagnostics: diagnostics,
filterOpt: null,
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTryFinally.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTryFinally.cs
index 57b7dd3f995d6..02b7133564480 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTryFinally.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTryFinally.cs
@@ -2442,6 +2442,281 @@ .locals init (int V_0) //x
");
}
+ [WorkItem(18678, "https://github.com/dotnet/roslyn/issues/18678")]
+ [Fact]
+ public void TryCatchConstantFalseFilter1()
+ {
+ var src = @"
+using System;
+class C
+{
+ static void Main()
+ {
+ try
+ {
+ throw new Exception();
+ }
+ catch (Exception) when (false)
+ {
+ Console.Write(""Catch"");
+ }
+ }
+}";
+ var comp = CompileAndVerify(src);
+ comp.VerifyIL("C.Main", @"
+{
+ // Code size 6 (0x6)
+ .maxstack 1
+ IL_0000: newobj ""System.Exception..ctor()""
+ IL_0005: throw
+}");
+ }
+
+ [WorkItem(18678, "https://github.com/dotnet/roslyn/issues/18678")]
+ [Fact]
+ public void TryCatchConstantFalseFilter2()
+ {
+ var src = @"
+using System;
+class C
+{
+ static void Main()
+ {
+ try
+ {
+ throw new Exception();
+ }
+ catch (NullReferenceException) when (false)
+ {
+ Console.Write(""Catch1"");
+ }
+ catch (Exception) when (false)
+ {
+ Console.Write(""Catch2"");
+ }
+ catch when (false)
+ {
+ Console.Write(""Catch"");
+ }
+ }
+}";
+ var comp = CompileAndVerify(src);
+ comp.VerifyIL("C.Main", @"
+{
+ // Code size 6 (0x6)
+ .maxstack 1
+ IL_0000: newobj ""System.Exception..ctor()""
+ IL_0005: throw
+}");
+ }
+
+ [WorkItem(18678, "https://github.com/dotnet/roslyn/issues/18678")]
+ [Fact]
+ public void TryCatchConstantFalseFilter3()
+ {
+ var src = @"
+using System;
+class C
+{
+ static void Main()
+ {
+ try
+ {
+ throw new Exception();
+ }
+ catch (NullReferenceException) when ((1+1) == 2)
+ {
+ Console.Write(""Catch1"");
+ }
+ catch (Exception) when (true == false)
+ {
+ Console.Write(""Catch2"");
+ }
+ catch when ((1+1) != 2)
+ {
+ Console.Write(""Catch"");
+ }
+ }
+}";
+ var comp = CompileAndVerify(src);
+ comp.VerifyIL("C.Main", @"
+{
+ // Code size 39 (0x27)
+ .maxstack 2
+ .try
+ {
+ IL_0000: newobj ""System.Exception..ctor()""
+ IL_0005: throw
+ }
+ filter
+ {
+ IL_0006: isinst ""System.NullReferenceException""
+ IL_000b: dup
+ IL_000c: brtrue.s IL_0012
+ IL_000e: pop
+ IL_000f: ldc.i4.0
+ IL_0010: br.s IL_0017
+ IL_0012: pop
+ IL_0013: ldc.i4.1
+ IL_0014: ldc.i4.0
+ IL_0015: cgt.un
+ IL_0017: endfilter
+ } // end filter
+ { // handler
+ IL_0019: pop
+ IL_001a: ldstr ""Catch1""
+ IL_001f: call ""void System.Console.Write(string)""
+ IL_0024: leave.s IL_0026
+ }
+ IL_0026: ret
+}");
+ }
+
+ [WorkItem(18678, "https://github.com/dotnet/roslyn/issues/18678")]
+ [Fact]
+ public void TryCatchConstantFalseFilterCombined()
+ {
+ var src = @"
+using System;
+class C
+{
+ static void Main()
+ {
+ var message = ""ExceptionMessage"";
+ try
+ {
+ throw new Exception(message);
+ }
+ catch (NullReferenceException) when (false)
+ {
+ Console.Write(""NullReferenceCatch"");
+ }
+ catch (Exception e) when (e.Message == message)
+ {
+ Console.Write(""ExceptionFilter"");
+ }
+ catch (Exception)
+ {
+ Console.Write(""ExceptionCatch"");
+ }
+ catch when (false)
+ {
+ Console.Write(""Catch"");
+ }
+ }
+}";
+ var comp = CompileAndVerify(src, expectedOutput: "ExceptionFilter");
+ comp.VerifyIL("C.Main", @"
+{
+ // Code size 68 (0x44)
+ .maxstack 2
+ .locals init (string V_0) //message
+ IL_0000: ldstr ""ExceptionMessage""
+ IL_0005: stloc.0
+ .try
+ {
+ IL_0006: ldloc.0
+ IL_0007: newobj ""System.Exception..ctor(string)""
+ IL_000c: throw
+ }
+ filter
+ {
+ IL_000d: isinst ""System.Exception""
+ IL_0012: dup
+ IL_0013: brtrue.s IL_0019
+ IL_0015: pop
+ IL_0016: ldc.i4.0
+ IL_0017: br.s IL_0027
+ IL_0019: callvirt ""string System.Exception.Message.get""
+ IL_001e: ldloc.0
+ IL_001f: call ""bool string.op_Equality(string, string)""
+ IL_0024: ldc.i4.0
+ IL_0025: cgt.un
+ IL_0027: endfilter
+ } // end filter
+ { // handler
+ IL_0029: pop
+ IL_002a: ldstr ""ExceptionFilter""
+ IL_002f: call ""void System.Console.Write(string)""
+ IL_0034: leave.s IL_0043
+ }
+ catch System.Exception
+ {
+ IL_0036: pop
+ IL_0037: ldstr ""ExceptionCatch""
+ IL_003c: call ""void System.Console.Write(string)""
+ IL_0041: leave.s IL_0043
+ }
+ IL_0043: ret
+}");
+ }
+
+ [WorkItem(18678, "https://github.com/dotnet/roslyn/issues/18678")]
+ [Fact]
+ public void TryCatchFinallyConstantFalseFilter()
+ {
+ var src = @"
+using System;
+class C
+{
+ static void Main()
+ {
+ try
+ {
+
+ try
+ {
+ throw new Exception();
+ }
+ catch (NullReferenceException) when (false)
+ {
+ Console.Write(""Catch1"");
+ }
+ catch (Exception) when (false)
+ {
+ Console.Write(""Catch2"");
+ }
+ finally
+ {
+ Console.Write(""Finally"");
+ }
+ }
+ catch
+ {
+ Console.Write(""OuterCatch"");
+ }
+ }
+}";
+ var comp = CompileAndVerify(src, expectedOutput: "FinallyOuterCatch");
+ comp.VerifyIL("C.Main", @"
+{
+ // Code size 31 (0x1f)
+ .maxstack 1
+ .try
+ {
+ .try
+ {
+ IL_0000: newobj ""System.Exception..ctor()""
+ IL_0005: throw
+ }
+ finally
+ {
+ IL_0006: ldstr ""Finally""
+ IL_000b: call ""void System.Console.Write(string)""
+ IL_0010: endfinally
+ }
+ }
+ catch object
+ {
+ IL_0011: pop
+ IL_0012: ldstr ""OuterCatch""
+ IL_0017: call ""void System.Console.Write(string)""
+ IL_001c: leave.s IL_001e
+ }
+ IL_001e: ret
+}");
+ }
+
[Fact]
public void TryCatchWithReturnValue()
{
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
index 4448de074facf..7675c2e870bfb 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
@@ -20470,7 +20470,7 @@ static void Main()
{
var reader = block.MetadataReader;
AssertEx.SetEqual(new[] { "mscorlib 4.0", "System.ValueTuple 4.0" }, reader.DumpAssemblyReferences());
- Assert.Contains("ValueTuple`2, System, AssemblyRef:System.ValueTuple", reader.DumpTypeReferences());
+ Assert.Contains("ValueTuple`2, System, AssemblyReference:System.ValueTuple", reader.DumpTypeReferences());
}
// emit with pdb
@@ -20479,7 +20479,7 @@ static void Main()
{
var reader = assembly.GetMetadataReader();
AssertEx.SetEqual(new[] { "mscorlib 4.0", "System.ValueTuple 4.0" }, reader.DumpAssemblyReferences());
- Assert.Contains("ValueTuple`2, System, AssemblyRef:System.ValueTuple", reader.DumpTypeReferences());
+ Assert.Contains("ValueTuple`2, System, AssemblyReference:System.ValueTuple", reader.DumpTypeReferences());
});
// no assertion in MetadataWriter
}
@@ -20510,7 +20510,7 @@ static void Main()
{
var reader = block.MetadataReader;
AssertEx.SetEqual(new[] { "mscorlib 4.0", "lib 0.0" }, reader.DumpAssemblyReferences());
- Assert.Contains("ReferencedType, , AssemblyRef:lib", reader.DumpTypeReferences());
+ Assert.Contains("ReferencedType, , AssemblyReference:lib", reader.DumpTypeReferences());
}
// emit with pdb
@@ -20519,7 +20519,7 @@ static void Main()
{
var reader = assembly.GetMetadataReader();
AssertEx.SetEqual(new[] { "mscorlib 4.0", "lib 0.0" }, reader.DumpAssemblyReferences());
- Assert.Contains("ReferencedType, , AssemblyRef:lib", reader.DumpTypeReferences());
+ Assert.Contains("ReferencedType, , AssemblyReference:lib", reader.DumpTypeReferences());
});
// no assertion in MetadataWriter
}
@@ -22751,7 +22751,6 @@ static void Main()
// System.Console.WriteLine(notAliteral.M());
Diagnostic(ErrorCode.ERR_BadExtensionArgTypes, "M").WithArguments("(int A, int B)", "M", "C.M((int x, long y))").WithLocation(23, 46)
);
-
}
[Fact]
@@ -22872,5 +22871,210 @@ void M()
Diagnostic(ErrorCode.ERR_TypelessTupleInAs, "(0, null) as (int, T)?").WithLocation(6, 17)
);
}
+
+ [Fact]
+ public void CheckedConstantConversions()
+ {
+ var source =
+@"#pragma warning disable 219
+class C
+{
+ static void Main()
+ {
+ unchecked
+ {
+ var u = ((byte, byte))(0, -1);
+ var (a, b) = ((byte, byte))(0, -2);
+ }
+ checked
+ {
+ var c = ((byte, byte))(0, -1);
+ var (a, b) = ((byte, byte))(0, -2);
+ }
}
-}
\ No newline at end of file
+}";
+ var comp = CreateStandardCompilation(
+ source,
+ references: new[] { ValueTupleRef, SystemRuntimeFacadeRef },
+ options: TestOptions.ReleaseExe);
+ comp.VerifyDiagnostics(
+ // (13,39): error CS0221: Constant value '-1' cannot be converted to a 'byte' (use 'unchecked' syntax to override)
+ // var c = ((byte, byte))(0, -1);
+ Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "-1").WithArguments("-1", "byte").WithLocation(13, 39),
+ // (14,44): error CS0221: Constant value '-2' cannot be converted to a 'byte' (use 'unchecked' syntax to override)
+ // var (a, b) = ((byte, byte))(0, -2);
+ Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "-2").WithArguments("-2", "byte").WithLocation(14, 44));
+ }
+
+ [Fact]
+ [WorkItem(18459, "https://github.com/dotnet/roslyn/issues/18459")]
+ public void CheckedConversions()
+ {
+ var source =
+@"using System;
+class C
+{
+ static (long, byte) Default((int, int) t)
+ {
+ return ((long, byte))t;
+ }
+ static (long, byte) Unchecked((int, int) t)
+ {
+ unchecked
+ {
+ return ((long, byte))t;
+ }
+ }
+ static (long, byte) Checked((int, int) t)
+ {
+ checked
+ {
+ return ((long, byte))t;
+ }
+ }
+ static void Main()
+ {
+ var d = Default((-1, -1));
+ Console.Write(d);
+ var u = Unchecked((-1, -1));
+ Console.Write(u);
+ try
+ {
+ var c = Checked((-1, -1));
+ Console.Write(c);
+ }
+ catch (OverflowException)
+ {
+ Console.Write(""overflow"");
+ }
+ }
+}";
+ var comp = CreateStandardCompilation(
+ source,
+ references: new[] { ValueTupleRef, SystemRuntimeFacadeRef },
+ options: TestOptions.ReleaseExe);
+ var verifier = CompileAndVerify(comp, expectedOutput: @"(-1, 255)(-1, 255)overflow");
+ verifier.VerifyIL("C.Default",
+@"{
+ // Code size 22 (0x16)
+ .maxstack 2
+ .locals init (System.ValueTuple V_0)
+ IL_0000: ldarg.0
+ IL_0001: stloc.0
+ IL_0002: ldloc.0
+ IL_0003: ldfld ""int System.ValueTuple.Item1""
+ IL_0008: conv.i8
+ IL_0009: ldloc.0
+ IL_000a: ldfld ""int System.ValueTuple.Item2""
+ IL_000f: conv.u1
+ IL_0010: newobj ""System.ValueTuple..ctor(long, byte)""
+ IL_0015: ret
+}");
+ verifier.VerifyIL("C.Unchecked",
+@"{
+ // Code size 22 (0x16)
+ .maxstack 2
+ .locals init (System.ValueTuple V_0)
+ IL_0000: ldarg.0
+ IL_0001: stloc.0
+ IL_0002: ldloc.0
+ IL_0003: ldfld ""int System.ValueTuple.Item1""
+ IL_0008: conv.i8
+ IL_0009: ldloc.0
+ IL_000a: ldfld ""int System.ValueTuple.Item2""
+ IL_000f: conv.u1
+ IL_0010: newobj ""System.ValueTuple..ctor(long, byte)""
+ IL_0015: ret
+}");
+ verifier.VerifyIL("C.Checked",
+@"{
+ // Code size 22 (0x16)
+ .maxstack 2
+ .locals init (System.ValueTuple V_0)
+ IL_0000: ldarg.0
+ IL_0001: stloc.0
+ IL_0002: ldloc.0
+ IL_0003: ldfld ""int System.ValueTuple.Item1""
+ IL_0008: conv.i8
+ IL_0009: ldloc.0
+ IL_000a: ldfld ""int System.ValueTuple.Item2""
+ IL_000f: conv.ovf.u1
+ IL_0010: newobj ""System.ValueTuple..ctor(long, byte)""
+ IL_0015: ret
+}");
+ }
+
+ [Fact]
+ [WorkItem(19434, "https://github.com/dotnet/roslyn/issues/19434")]
+ public void ExplicitTupleLiteralConversionWithNullable01()
+ {
+ var source = @"
+class C
+{
+ static void Main()
+ {
+ int x = 1;
+ var y = ((byte, byte)?)(x, x);
+ System.Console.WriteLine(y.Value);
+ }
+}
+";
+
+ var comp = CompileAndVerify(source,
+ additionalRefs: s_valueTupleRefs, options: TestOptions.DebugExe, expectedOutput:
+@"(1, 1)");
+
+ comp.VerifyIL("C.Main()", @"
+{
+ // Code size 38 (0x26)
+ .maxstack 3
+ .locals init (int V_0, //x
+ (byte, byte)? V_1) //y
+ IL_0000: nop
+ IL_0001: ldc.i4.1
+ IL_0002: stloc.0
+ IL_0003: ldloca.s V_1
+ IL_0005: ldloc.0
+ IL_0006: conv.u1
+ IL_0007: ldloc.0
+ IL_0008: conv.u1
+ IL_0009: newobj ""System.ValueTuple..ctor(byte, byte)""
+ IL_000e: call ""(byte, byte)?..ctor((byte, byte))""
+ IL_0013: ldloca.s V_1
+ IL_0015: call ""(byte, byte) (byte, byte)?.Value.get""
+ IL_001a: box ""System.ValueTuple""
+ IL_001f: call ""void System.Console.WriteLine(object)""
+ IL_0024: nop
+ IL_0025: ret
+}
+");
+
+ comp = CompileAndVerify(source,
+ additionalRefs: s_valueTupleRefs, options: TestOptions.ReleaseExe, expectedOutput:
+@"(1, 1)");
+
+ comp.VerifyIL("C.Main()", @"
+{
+ // Code size 36 (0x24)
+ .maxstack 3
+ .locals init (int V_0, //x
+ (byte, byte)? V_1) //y
+ IL_0000: ldc.i4.1
+ IL_0001: stloc.0
+ IL_0002: ldloca.s V_1
+ IL_0004: ldloc.0
+ IL_0005: conv.u1
+ IL_0006: ldloc.0
+ IL_0007: conv.u1
+ IL_0008: newobj ""System.ValueTuple..ctor(byte, byte)""
+ IL_000d: call ""(byte, byte)?..ctor((byte, byte))""
+ IL_0012: ldloca.s V_1
+ IL_0014: call ""(byte, byte) (byte, byte)?.Value.get""
+ IL_0019: box ""System.ValueTuple""
+ IL_001e: call ""void System.Console.WriteLine(object)""
+ IL_0023: ret
+}
+");
+ }
+ }
+}
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/GotoTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/GotoTest.cs
index 146fddc1aa862..284bf20c025c6 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/GotoTest.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/GotoTest.cs
@@ -2,6 +2,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
+using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
@@ -703,14 +704,6 @@ public static IEnumerable Power(int number, int exponent)
CompileAndVerify(text, expectedOutput: expectedOutput);
}
- // When ReflectionEmit supports writing exception handler info, this method
- // can be removed and CompileAndVerify references above will resolve to
- // the overload that emits with both CCI and ReflectionEmit. (Bug #7012)
- private CompilationVerifier CompileAndVerify(string source, string expectedOutput = null)
- {
- return base.CompileAndVerify(source: source, expectedOutput: expectedOutput);
- }
-
[WorkItem(540719, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540719")]
[Fact]
public void LabelBetweenLocalAndInitialize()
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs
index 39c1c7f56c87b..3472ef5b26ed6 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs
@@ -7735,46 +7735,43 @@ .locals init (int? V_0,
expectedOutput: "null1");
compVerifier.VerifyIL("Program.M",
@"{
- // Code size 69 (0x45)
+ // Code size 65 (0x41)
.maxstack 1
.locals init (int? V_0,
int V_1,
- int? V_2,
- int V_3, //i
- int? V_4,
- int? V_5)
+ int V_2, //i
+ int? V_3,
+ int? V_4)
IL_0000: nop
IL_0001: ldarg.0
- IL_0002: stloc.2
- IL_0003: ldloc.2
- IL_0004: stloc.s V_4
- IL_0006: ldloc.s V_4
- IL_0008: stloc.0
- IL_0009: ldloca.s V_0
- IL_000b: call ""bool int?.HasValue.get""
- IL_0010: brtrue.s IL_0014
- IL_0012: br.s IL_0037
- IL_0014: ldloc.0
- IL_0015: stloc.s V_5
- IL_0017: ldloca.s V_5
- IL_0019: call ""int int?.GetValueOrDefault()""
- IL_001e: stloc.1
- IL_001f: ldloca.s V_5
- IL_0021: call ""bool int?.HasValue.get""
- IL_0026: brfalse.s IL_002a
+ IL_0002: stloc.3
+ IL_0003: ldloc.3
+ IL_0004: stloc.0
+ IL_0005: ldloca.s V_0
+ IL_0007: call ""bool int?.HasValue.get""
+ IL_000c: brtrue.s IL_0010
+ IL_000e: br.s IL_0033
+ IL_0010: ldloc.0
+ IL_0011: stloc.s V_4
+ IL_0013: ldloca.s V_4
+ IL_0015: call ""int int?.GetValueOrDefault()""
+ IL_001a: stloc.1
+ IL_001b: ldloca.s V_4
+ IL_001d: call ""bool int?.HasValue.get""
+ IL_0022: brfalse.s IL_0026
+ IL_0024: br.s IL_0026
+ IL_0026: ldloc.1
+ IL_0027: stloc.2
IL_0028: br.s IL_002a
- IL_002a: ldloc.1
- IL_002b: stloc.3
- IL_002c: br.s IL_002e
- IL_002e: ldloc.3
- IL_002f: call ""void System.Console.Write(int)""
- IL_0034: nop
- IL_0035: br.s IL_0044
- IL_0037: ldstr ""null""
- IL_003c: call ""void System.Console.Write(string)""
- IL_0041: nop
- IL_0042: br.s IL_0044
- IL_0044: ret
+ IL_002a: ldloc.2
+ IL_002b: call ""void System.Console.Write(int)""
+ IL_0030: nop
+ IL_0031: br.s IL_0040
+ IL_0033: ldstr ""null""
+ IL_0038: call ""void System.Console.Write(string)""
+ IL_003d: nop
+ IL_003e: br.s IL_0040
+ IL_0040: ret
}"
);
}
@@ -7821,32 +7818,29 @@ .locals init (System.IComparable V_0)
expectedOutput: "1");
compVerifier.VerifyIL("Program.M",
@"{
- // Code size 32 (0x20)
+ // Code size 28 (0x1c)
.maxstack 1
.locals init (int V_0,
System.IComparable V_1,
- int V_2,
- System.IComparable V_3, //i
- int V_4)
+ System.IComparable V_2, //i
+ int V_3)
IL_0000: nop
IL_0001: ldarg.0
- IL_0002: stloc.2
- IL_0003: ldloc.2
- IL_0004: stloc.s V_4
- IL_0006: ldloc.s V_4
- IL_0008: stloc.0
- IL_0009: ldloc.0
- IL_000a: box ""int""
- IL_000f: stloc.1
+ IL_0002: stloc.3
+ IL_0003: ldloc.3
+ IL_0004: stloc.0
+ IL_0005: ldloc.0
+ IL_0006: box ""int""
+ IL_000b: stloc.1
+ IL_000c: br.s IL_000e
+ IL_000e: ldloc.1
+ IL_000f: stloc.2
IL_0010: br.s IL_0012
- IL_0012: ldloc.1
- IL_0013: stloc.3
- IL_0014: br.s IL_0016
- IL_0016: ldloc.3
- IL_0017: call ""void System.Console.Write(object)""
- IL_001c: nop
- IL_001d: br.s IL_001f
- IL_001f: ret
+ IL_0012: ldloc.2
+ IL_0013: call ""void System.Console.Write(object)""
+ IL_0018: nop
+ IL_0019: br.s IL_001b
+ IL_001b: ret
}"
);
}
@@ -7900,37 +7894,34 @@ .locals init (int? V_0,
expectedOutput: "1");
compVerifier.VerifyIL("Program.M",
@"{
- // Code size 45 (0x2d)
+ // Code size 41 (0x29)
.maxstack 1
.locals init (int? V_0,
System.IComparable V_1,
- int? V_2,
- System.IComparable V_3, //i
- int? V_4)
+ System.IComparable V_2, //i
+ int? V_3)
IL_0000: nop
IL_0001: ldarg.0
- IL_0002: stloc.2
- IL_0003: ldloc.2
- IL_0004: stloc.s V_4
- IL_0006: ldloc.s V_4
- IL_0008: stloc.0
- IL_0009: ldloca.s V_0
- IL_000b: call ""bool int?.HasValue.get""
- IL_0010: brtrue.s IL_0014
- IL_0012: br.s IL_001d
- IL_0014: ldloc.0
- IL_0015: box ""int?""
- IL_001a: stloc.1
- IL_001b: br.s IL_001f
- IL_001d: br.s IL_002c
- IL_001f: ldloc.1
- IL_0020: stloc.3
- IL_0021: br.s IL_0023
- IL_0023: ldloc.3
- IL_0024: call ""void System.Console.Write(object)""
- IL_0029: nop
- IL_002a: br.s IL_002c
- IL_002c: ret
+ IL_0002: stloc.3
+ IL_0003: ldloc.3
+ IL_0004: stloc.0
+ IL_0005: ldloca.s V_0
+ IL_0007: call ""bool int?.HasValue.get""
+ IL_000c: brtrue.s IL_0010
+ IL_000e: br.s IL_0019
+ IL_0010: ldloc.0
+ IL_0011: box ""int?""
+ IL_0016: stloc.1
+ IL_0017: br.s IL_001b
+ IL_0019: br.s IL_0028
+ IL_001b: ldloc.1
+ IL_001c: stloc.2
+ IL_001d: br.s IL_001f
+ IL_001f: ldloc.2
+ IL_0020: call ""void System.Console.Write(object)""
+ IL_0025: nop
+ IL_0026: br.s IL_0028
+ IL_0028: ret
}"
);
}
@@ -7992,44 +7983,41 @@ .locals init (object V_0,
expectedOutput: "1");
compVerifier.VerifyIL("Program.M",
@"{
- // Code size 62 (0x3e)
+ // Code size 58 (0x3a)
.maxstack 1
.locals init (object V_0,
int V_1,
- object V_2,
- int V_3, //i
- object V_4,
- int? V_5)
+ int V_2, //i
+ object V_3,
+ int? V_4)
IL_0000: nop
IL_0001: ldarg.0
- IL_0002: stloc.2
- IL_0003: ldloc.2
- IL_0004: stloc.s V_4
- IL_0006: ldloc.s V_4
- IL_0008: stloc.0
- IL_0009: ldloc.0
- IL_000a: brtrue.s IL_000e
- IL_000c: br.s IL_002e
- IL_000e: ldloc.0
- IL_000f: isinst ""int?""
- IL_0014: unbox.any ""int?""
- IL_0019: stloc.s V_5
- IL_001b: ldloca.s V_5
- IL_001d: call ""int int?.GetValueOrDefault()""
- IL_0022: stloc.1
- IL_0023: ldloca.s V_5
- IL_0025: call ""bool int?.HasValue.get""
- IL_002a: brfalse.s IL_002e
- IL_002c: br.s IL_0030
- IL_002e: br.s IL_003d
- IL_0030: ldloc.1
- IL_0031: stloc.3
- IL_0032: br.s IL_0034
- IL_0034: ldloc.3
- IL_0035: call ""void System.Console.Write(int)""
- IL_003a: nop
- IL_003b: br.s IL_003d
- IL_003d: ret
+ IL_0002: stloc.3
+ IL_0003: ldloc.3
+ IL_0004: stloc.0
+ IL_0005: ldloc.0
+ IL_0006: brtrue.s IL_000a
+ IL_0008: br.s IL_002a
+ IL_000a: ldloc.0
+ IL_000b: isinst ""int?""
+ IL_0010: unbox.any ""int?""
+ IL_0015: stloc.s V_4
+ IL_0017: ldloca.s V_4
+ IL_0019: call ""int int?.GetValueOrDefault()""
+ IL_001e: stloc.1
+ IL_001f: ldloca.s V_4
+ IL_0021: call ""bool int?.HasValue.get""
+ IL_0026: brfalse.s IL_002a
+ IL_0028: br.s IL_002c
+ IL_002a: br.s IL_0039
+ IL_002c: ldloc.1
+ IL_002d: stloc.2
+ IL_002e: br.s IL_0030
+ IL_0030: ldloc.2
+ IL_0031: call ""void System.Console.Write(int)""
+ IL_0036: nop
+ IL_0037: br.s IL_0039
+ IL_0039: ret
}"
);
}
@@ -8101,52 +8089,49 @@ .locals init (object V_0,
expectedOutput: "1");
compVerifier.VerifyIL("Program.M",
@"{
- // Code size 75 (0x4b)
+ // Code size 71 (0x47)
.maxstack 2
.locals init (object V_0,
T V_1,
- object V_2,
- T V_3, //i
+ T V_2, //i
+ object V_3,
object V_4,
- object V_5,
- T V_6)
+ T V_5)
IL_0000: nop
IL_0001: ldarg.0
- IL_0002: stloc.2
- IL_0003: ldloc.2
- IL_0004: stloc.s V_4
- IL_0006: ldloc.s V_4
- IL_0008: stloc.0
- IL_0009: ldloc.0
- IL_000a: brtrue.s IL_000e
- IL_000c: br.s IL_0036
- IL_000e: ldloc.0
- IL_000f: stloc.s V_5
- IL_0011: ldloc.s V_5
- IL_0013: isinst ""T""
- IL_0018: ldnull
- IL_0019: cgt.un
- IL_001b: dup
- IL_001c: brtrue.s IL_002a
- IL_001e: ldloca.s V_6
- IL_0020: initobj ""T""
- IL_0026: ldloc.s V_6
- IL_0028: br.s IL_0031
- IL_002a: ldloc.s V_5
- IL_002c: unbox.any ""T""
- IL_0031: stloc.1
- IL_0032: brfalse.s IL_0036
- IL_0034: br.s IL_0038
- IL_0036: br.s IL_004a
- IL_0038: ldloc.1
- IL_0039: stloc.3
- IL_003a: br.s IL_003c
- IL_003c: ldloc.3
- IL_003d: box ""T""
- IL_0042: call ""void System.Console.Write(object)""
- IL_0047: nop
- IL_0048: br.s IL_004a
- IL_004a: ret
+ IL_0002: stloc.3
+ IL_0003: ldloc.3
+ IL_0004: stloc.0
+ IL_0005: ldloc.0
+ IL_0006: brtrue.s IL_000a
+ IL_0008: br.s IL_0032
+ IL_000a: ldloc.0
+ IL_000b: stloc.s V_4
+ IL_000d: ldloc.s V_4
+ IL_000f: isinst ""T""
+ IL_0014: ldnull
+ IL_0015: cgt.un
+ IL_0017: dup
+ IL_0018: brtrue.s IL_0026
+ IL_001a: ldloca.s V_5
+ IL_001c: initobj ""T""
+ IL_0022: ldloc.s V_5
+ IL_0024: br.s IL_002d
+ IL_0026: ldloc.s V_4
+ IL_0028: unbox.any ""T""
+ IL_002d: stloc.1
+ IL_002e: brfalse.s IL_0032
+ IL_0030: br.s IL_0034
+ IL_0032: br.s IL_0046
+ IL_0034: ldloc.1
+ IL_0035: stloc.2
+ IL_0036: br.s IL_0038
+ IL_0038: ldloc.2
+ IL_0039: box ""T""
+ IL_003e: call ""void System.Console.Write(object)""
+ IL_0043: nop
+ IL_0044: br.s IL_0046
+ IL_0046: ret
}"
);
}
@@ -8218,52 +8203,49 @@ .locals init (System.IComparable V_0,
expectedOutput: "1");
compVerifier.VerifyIL("Program.M",
@"{
- // Code size 75 (0x4b)
+ // Code size 71 (0x47)
.maxstack 2
.locals init (System.IComparable V_0,
T V_1,
- System.IComparable V_2,
- T V_3, //i
- System.IComparable V_4,
- object V_5,
- T V_6)
+ T V_2, //i
+ System.IComparable V_3,
+ object V_4,
+ T V_5)
IL_0000: nop
IL_0001: ldarg.0
- IL_0002: stloc.2
- IL_0003: ldloc.2
- IL_0004: stloc.s V_4
- IL_0006: ldloc.s V_4
- IL_0008: stloc.0
- IL_0009: ldloc.0
- IL_000a: brtrue.s IL_000e
- IL_000c: br.s IL_0036
- IL_000e: ldloc.0
- IL_000f: stloc.s V_5
- IL_0011: ldloc.s V_5
- IL_0013: isinst ""T""
- IL_0018: ldnull
- IL_0019: cgt.un
- IL_001b: dup
- IL_001c: brtrue.s IL_002a
- IL_001e: ldloca.s V_6
- IL_0020: initobj ""T""
- IL_0026: ldloc.s V_6
- IL_0028: br.s IL_0031
- IL_002a: ldloc.s V_5
- IL_002c: unbox.any ""T""
- IL_0031: stloc.1
- IL_0032: brfalse.s IL_0036
- IL_0034: br.s IL_0038
- IL_0036: br.s IL_004a
- IL_0038: ldloc.1
- IL_0039: stloc.3
- IL_003a: br.s IL_003c
- IL_003c: ldloc.3
- IL_003d: box ""T""
- IL_0042: call ""void System.Console.Write(object)""
- IL_0047: nop
- IL_0048: br.s IL_004a
- IL_004a: ret
+ IL_0002: stloc.3
+ IL_0003: ldloc.3
+ IL_0004: stloc.0
+ IL_0005: ldloc.0
+ IL_0006: brtrue.s IL_000a
+ IL_0008: br.s IL_0032
+ IL_000a: ldloc.0
+ IL_000b: stloc.s V_4
+ IL_000d: ldloc.s V_4
+ IL_000f: isinst ""T""
+ IL_0014: ldnull
+ IL_0015: cgt.un
+ IL_0017: dup
+ IL_0018: brtrue.s IL_0026
+ IL_001a: ldloca.s V_5
+ IL_001c: initobj ""T""
+ IL_0022: ldloc.s V_5
+ IL_0024: br.s IL_002d
+ IL_0026: ldloc.s V_4
+ IL_0028: unbox.any ""T""
+ IL_002d: stloc.1
+ IL_002e: brfalse.s IL_0032
+ IL_0030: br.s IL_0034
+ IL_0032: br.s IL_0046
+ IL_0034: ldloc.1
+ IL_0035: stloc.2
+ IL_0036: br.s IL_0038
+ IL_0038: ldloc.2
+ IL_0039: box ""T""
+ IL_003e: call ""void System.Console.Write(object)""
+ IL_0043: nop
+ IL_0044: br.s IL_0046
+ IL_0046: ret
}"
);
}
@@ -8337,54 +8319,51 @@ .locals init (U V_0,
expectedOutput: "1");
compVerifier.VerifyIL("Program.M",
@"{
- // Code size 85 (0x55)
+ // Code size 81 (0x51)
.maxstack 2
.locals init (U V_0,
T V_1,
- U V_2,
- T V_3, //i
- U V_4,
- object V_5,
- T V_6)
+ T V_2, //i
+ U V_3,
+ object V_4,
+ T V_5)
IL_0000: nop
IL_0001: ldarg.0
- IL_0002: stloc.2
- IL_0003: ldloc.2
- IL_0004: stloc.s V_4
- IL_0006: ldloc.s V_4
- IL_0008: stloc.0
- IL_0009: ldloc.0
- IL_000a: box ""U""
- IL_000f: brtrue.s IL_0013
- IL_0011: br.s IL_0040
- IL_0013: ldloc.0
- IL_0014: box ""U""
- IL_0019: stloc.s V_5
- IL_001b: ldloc.s V_5
- IL_001d: isinst ""T""
- IL_0022: ldnull
- IL_0023: cgt.un
- IL_0025: dup
- IL_0026: brtrue.s IL_0034
- IL_0028: ldloca.s V_6
- IL_002a: initobj ""T""
- IL_0030: ldloc.s V_6
- IL_0032: br.s IL_003b
- IL_0034: ldloc.s V_5
- IL_0036: unbox.any ""T""
- IL_003b: stloc.1
- IL_003c: brfalse.s IL_0040
- IL_003e: br.s IL_0042
- IL_0040: br.s IL_0054
- IL_0042: ldloc.1
- IL_0043: stloc.3
- IL_0044: br.s IL_0046
- IL_0046: ldloc.3
- IL_0047: box ""T""
- IL_004c: call ""void System.Console.Write(object)""
- IL_0051: nop
- IL_0052: br.s IL_0054
- IL_0054: ret
+ IL_0002: stloc.3
+ IL_0003: ldloc.3
+ IL_0004: stloc.0
+ IL_0005: ldloc.0
+ IL_0006: box ""U""
+ IL_000b: brtrue.s IL_000f
+ IL_000d: br.s IL_003c
+ IL_000f: ldloc.0
+ IL_0010: box ""U""
+ IL_0015: stloc.s V_4
+ IL_0017: ldloc.s V_4
+ IL_0019: isinst ""T""
+ IL_001e: ldnull
+ IL_001f: cgt.un
+ IL_0021: dup
+ IL_0022: brtrue.s IL_0030
+ IL_0024: ldloca.s V_5
+ IL_0026: initobj ""T""
+ IL_002c: ldloc.s V_5
+ IL_002e: br.s IL_0037
+ IL_0030: ldloc.s V_4
+ IL_0032: unbox.any ""T""
+ IL_0037: stloc.1
+ IL_0038: brfalse.s IL_003c
+ IL_003a: br.s IL_003e
+ IL_003c: br.s IL_0050
+ IL_003e: ldloc.1
+ IL_003f: stloc.2
+ IL_0040: br.s IL_0042
+ IL_0042: ldloc.2
+ IL_0043: box ""T""
+ IL_0048: call ""void System.Console.Write(object)""
+ IL_004d: nop
+ IL_004e: br.s IL_0050
+ IL_0050: ret
}"
);
}
@@ -8598,57 +8577,54 @@ .locals init (T V_0, //t
);
compVerifier.VerifyIL("Program.M2",
@"{
- // Code size 82 (0x52)
+ // Code size 78 (0x4e)
.maxstack 2
.locals init (System.ValueType V_0,
T V_1,
- System.ValueType V_2,
- T V_3, //t
- System.ValueType V_4,
- object V_5,
- T V_6,
- T V_7)
+ T V_2, //t
+ System.ValueType V_3,
+ object V_4,
+ T V_5,
+ T V_6)
IL_0000: nop
IL_0001: ldarg.0
- IL_0002: stloc.2
- IL_0003: ldloc.2
- IL_0004: stloc.s V_4
- IL_0006: ldloc.s V_4
- IL_0008: stloc.0
- IL_0009: ldloc.0
- IL_000a: brtrue.s IL_000e
- IL_000c: br.s IL_0036
- IL_000e: ldloc.0
- IL_000f: stloc.s V_5
- IL_0011: ldloc.s V_5
- IL_0013: isinst ""T""
- IL_0018: ldnull
- IL_0019: cgt.un
- IL_001b: dup
- IL_001c: brtrue.s IL_002a
- IL_001e: ldloca.s V_6
- IL_0020: initobj ""T""
- IL_0026: ldloc.s V_6
- IL_0028: br.s IL_0031
- IL_002a: ldloc.s V_5
- IL_002c: unbox.any ""T""
- IL_0031: stloc.1
- IL_0032: brfalse.s IL_0036
- IL_0034: br.s IL_0038
- IL_0036: br.s IL_0041
- IL_0038: ldloc.1
- IL_0039: stloc.3
- IL_003a: br.s IL_003c
- IL_003c: ldloc.3
- IL_003d: stloc.s V_7
- IL_003f: br.s IL_004f
- IL_0041: ldloca.s V_6
- IL_0043: initobj ""T""
- IL_0049: ldloc.s V_6
- IL_004b: stloc.s V_7
- IL_004d: br.s IL_004f
- IL_004f: ldloc.s V_7
- IL_0051: ret
+ IL_0002: stloc.3
+ IL_0003: ldloc.3
+ IL_0004: stloc.0
+ IL_0005: ldloc.0
+ IL_0006: brtrue.s IL_000a
+ IL_0008: br.s IL_0032
+ IL_000a: ldloc.0
+ IL_000b: stloc.s V_4
+ IL_000d: ldloc.s V_4
+ IL_000f: isinst ""T""
+ IL_0014: ldnull
+ IL_0015: cgt.un
+ IL_0017: dup
+ IL_0018: brtrue.s IL_0026
+ IL_001a: ldloca.s V_5
+ IL_001c: initobj ""T""
+ IL_0022: ldloc.s V_5
+ IL_0024: br.s IL_002d
+ IL_0026: ldloc.s V_4
+ IL_0028: unbox.any ""T""
+ IL_002d: stloc.1
+ IL_002e: brfalse.s IL_0032
+ IL_0030: br.s IL_0034
+ IL_0032: br.s IL_003d
+ IL_0034: ldloc.1
+ IL_0035: stloc.2
+ IL_0036: br.s IL_0038
+ IL_0038: ldloc.2
+ IL_0039: stloc.s V_6
+ IL_003b: br.s IL_004b
+ IL_003d: ldloca.s V_5
+ IL_003f: initobj ""T""
+ IL_0045: ldloc.s V_5
+ IL_0047: stloc.s V_6
+ IL_0049: br.s IL_004b
+ IL_004b: ldloc.s V_6
+ IL_004d: ret
}"
);
}
@@ -8780,50 +8756,47 @@ .locals init (int V_0, //t
);
compVerifier.VerifyIL("Program.M2",
@"{
- // Code size 75 (0x4b)
+ // Code size 71 (0x47)
.maxstack 1
.locals init (T V_0,
int V_1,
- T V_2,
- int V_3, //t
- T V_4,
- int? V_5,
- int V_6)
+ int V_2, //t
+ T V_3,
+ int? V_4,
+ int V_5)
IL_0000: nop
IL_0001: ldarg.0
- IL_0002: stloc.2
- IL_0003: ldloc.2
- IL_0004: stloc.s V_4
- IL_0006: ldloc.s V_4
- IL_0008: stloc.0
- IL_0009: ldloc.0
- IL_000a: box ""T""
- IL_000f: brtrue.s IL_0013
- IL_0011: br.s IL_0038
- IL_0013: ldloc.0
- IL_0014: box ""T""
- IL_0019: isinst ""int?""
- IL_001e: unbox.any ""int?""
- IL_0023: stloc.s V_5
- IL_0025: ldloca.s V_5
- IL_0027: call ""int int?.GetValueOrDefault()""
- IL_002c: stloc.1
- IL_002d: ldloca.s V_5
- IL_002f: call ""bool int?.HasValue.get""
- IL_0034: brfalse.s IL_0038
- IL_0036: br.s IL_003a
- IL_0038: br.s IL_0043
- IL_003a: ldloc.1
- IL_003b: stloc.3
- IL_003c: br.s IL_003e
- IL_003e: ldloc.3
- IL_003f: stloc.s V_6
- IL_0041: br.s IL_0048
- IL_0043: ldc.i4.0
- IL_0044: stloc.s V_6
- IL_0046: br.s IL_0048
- IL_0048: ldloc.s V_6
- IL_004a: ret
+ IL_0002: stloc.3
+ IL_0003: ldloc.3
+ IL_0004: stloc.0
+ IL_0005: ldloc.0
+ IL_0006: box ""T""
+ IL_000b: brtrue.s IL_000f
+ IL_000d: br.s IL_0034
+ IL_000f: ldloc.0
+ IL_0010: box ""T""
+ IL_0015: isinst ""int?""
+ IL_001a: unbox.any ""int?""
+ IL_001f: stloc.s V_4
+ IL_0021: ldloca.s V_4
+ IL_0023: call ""int int?.GetValueOrDefault()""
+ IL_0028: stloc.1
+ IL_0029: ldloca.s V_4
+ IL_002b: call ""bool int?.HasValue.get""
+ IL_0030: brfalse.s IL_0034
+ IL_0032: br.s IL_0036
+ IL_0034: br.s IL_003f
+ IL_0036: ldloc.1
+ IL_0037: stloc.2
+ IL_0038: br.s IL_003a
+ IL_003a: ldloc.2
+ IL_003b: stloc.s V_5
+ IL_003d: br.s IL_0044
+ IL_003f: ldc.i4.0
+ IL_0040: stloc.s V_5
+ IL_0042: br.s IL_0044
+ IL_0044: ldloc.s V_5
+ IL_0046: ret
}"
);
}
@@ -9125,81 +9098,497 @@ public static string M2(object o)
compVerifier.VerifyDiagnostics();
compVerifier.VerifyIL("Program.M2",
@"{
- // Code size 154 (0x9a)
+ // Code size 150 (0x96)
.maxstack 2
.locals init (object V_0,
Generic.Color V_1,
Generic.Color V_2,
- object V_3,
- Generic.Color V_4, //c
- object V_5,
- Generic.Color? V_6,
- Generic.Color? V_7,
- int V_8,
- string V_9)
+ Generic.Color V_3, //c
+ object V_4,
+ Generic.Color? V_5,
+ Generic.Color? V_6,
+ int V_7,
+ string V_8)
IL_0000: nop
IL_0001: ldarg.0
- IL_0002: stloc.3
- IL_0003: ldloc.3
- IL_0004: stloc.s V_5
- IL_0006: ldloc.s V_5
- IL_0008: stloc.0
- IL_0009: ldloc.0
- IL_000a: brtrue.s IL_000e
- IL_000c: br.s IL_0060
- IL_000e: ldloc.0
- IL_000f: isinst ""Generic.Color?""
- IL_0014: unbox.any ""Generic.Color?""
- IL_0019: stloc.s V_6
- IL_001b: ldloca.s V_6
- IL_001d: call ""Generic.Color Generic.Color?.GetValueOrDefault()""
- IL_0022: stloc.1
- IL_0023: ldloca.s V_6
- IL_0025: call ""bool Generic.Color?.HasValue.get""
- IL_002a: brfalse.s IL_002e
- IL_002c: br.s IL_0062
- IL_002e: ldloc.0
- IL_002f: isinst ""Generic.Color?""
- IL_0034: unbox.any ""Generic.Color?""
- IL_0039: stloc.s V_7
- IL_003b: ldloca.s V_7
- IL_003d: call ""Generic.Color Generic.Color?.GetValueOrDefault()""
- IL_0042: stloc.2
+ IL_0002: stloc.s V_4
+ IL_0004: ldloc.s V_4
+ IL_0006: stloc.0
+ IL_0007: ldloc.0
+ IL_0008: brtrue.s IL_000c
+ IL_000a: br.s IL_005e
+ IL_000c: ldloc.0
+ IL_000d: isinst ""Generic.Color?""
+ IL_0012: unbox.any ""Generic.Color?""
+ IL_0017: stloc.s V_5
+ IL_0019: ldloca.s V_5
+ IL_001b: call ""Generic.Color Generic.Color?.GetValueOrDefault()""
+ IL_0020: stloc.1
+ IL_0021: ldloca.s V_5
+ IL_0023: call ""bool Generic.Color?.HasValue.get""
+ IL_0028: brfalse.s IL_002c
+ IL_002a: br.s IL_0060
+ IL_002c: ldloc.0
+ IL_002d: isinst ""Generic.Color?""
+ IL_0032: unbox.any ""Generic.Color?""
+ IL_0037: stloc.s V_6
+ IL_0039: ldloca.s V_6
+ IL_003b: call ""Generic.Color Generic.Color?.GetValueOrDefault()""
+ IL_0040: stloc.2
+ IL_0041: ldloca.s V_6
+ IL_0043: call ""bool Generic.Color?.HasValue.get""
+ IL_0048: brfalse.s IL_005e
+ IL_004a: ldloc.2
+ IL_004b: stloc.s V_7
+ IL_004d: ldloc.s V_7
+ IL_004f: brfalse.s IL_005a
+ IL_0051: br.s IL_0053
+ IL_0053: ldloc.s V_7
+ IL_0055: ldc.i4.1
+ IL_0056: beq.s IL_005c
+ IL_0058: br.s IL_005e
+ IL_005a: br.s IL_0078
+ IL_005c: br.s IL_0081
+ IL_005e: br.s IL_008a
+ IL_0060: ldloc.1
+ IL_0061: stloc.3
+ IL_0062: br.s IL_0064
+ IL_0064: ldstr ""Generic.Color.""
+ IL_0069: ldloc.3
+ IL_006a: box ""Generic.Color""
+ IL_006f: call ""string string.Concat(object, object)""
+ IL_0074: stloc.s V_8
+ IL_0076: br.s IL_0093
+ IL_0078: ldstr ""Generic.Color.Red""
+ IL_007d: stloc.s V_8
+ IL_007f: br.s IL_0093
+ IL_0081: ldstr ""Generic.Color.Blue""
+ IL_0086: stloc.s V_8
+ IL_0088: br.s IL_0093
+ IL_008a: ldstr ""None""
+ IL_008f: stloc.s V_8
+ IL_0091: br.s IL_0093
+ IL_0093: ldloc.s V_8
+ IL_0095: ret
+}"
+ );
+ }
+
+ [Fact, WorkItem(19280, "https://github.com/dotnet/roslyn/issues/19280")]
+ public void ShareLikeKindedTemps_01()
+ {
+ var source = @"using System;
+
+public class Program
+{
+ public static void Main()
+ {
+ }
+ static bool b = false;
+ public static void M(object o)
+ {
+ switch (o)
+ {
+ case int i when b: break;
+ case var _ when b: break;
+ case int i when b: break;
+ case var _ when b: break;
+ case int i when b: break;
+ case var _ when b: break;
+ case int i when b: break;
+ case var _ when b: break;
+ }
+ }
+}";
+ var compVerifier = CompileAndVerify(source,
+ options: TestOptions.ReleaseDll.WithOutputKind(OutputKind.ConsoleApplication),
+ expectedOutput: "");
+ compVerifier.VerifyIL("Program.M",
+@"{
+ // Code size 203 (0xcb)
+ .maxstack 1
+ .locals init (object V_0,
+ int V_1,
+ int? V_2)
+ IL_0000: ldarg.0
+ IL_0001: stloc.0
+ IL_0002: ldloc.0
+ IL_0003: brfalse IL_0094
+ IL_0008: ldloc.0
+ IL_0009: isinst ""int?""
+ IL_000e: unbox.any ""int?""
+ IL_0013: stloc.2
+ IL_0014: ldloca.s V_2
+ IL_0016: call ""int int?.GetValueOrDefault()""
+ IL_001b: stloc.1
+ IL_001c: ldloca.s V_2
+ IL_001e: call ""bool int?.HasValue.get""
+ IL_0023: brfalse.s IL_0094
+ IL_0025: br.s IL_008d
+ IL_0027: ldloc.0
+ IL_0028: brfalse.s IL_00a4
+ IL_002a: ldloc.0
+ IL_002b: isinst ""int?""
+ IL_0030: unbox.any ""int?""
+ IL_0035: stloc.2
+ IL_0036: ldloca.s V_2
+ IL_0038: call ""int int?.GetValueOrDefault()""
+ IL_003d: stloc.1
+ IL_003e: ldloca.s V_2
+ IL_0040: call ""bool int?.HasValue.get""
+ IL_0045: brfalse.s IL_00a4
+ IL_0047: br.s IL_009d
+ IL_0049: ldloc.0
+ IL_004a: brfalse.s IL_00b4
+ IL_004c: ldloc.0
+ IL_004d: isinst ""int?""
+ IL_0052: unbox.any ""int?""
+ IL_0057: stloc.2
+ IL_0058: ldloca.s V_2
+ IL_005a: call ""int int?.GetValueOrDefault()""
+ IL_005f: stloc.1
+ IL_0060: ldloca.s V_2
+ IL_0062: call ""bool int?.HasValue.get""
+ IL_0067: brfalse.s IL_00b4
+ IL_0069: br.s IL_00ad
+ IL_006b: ldloc.0
+ IL_006c: brfalse.s IL_00c4
+ IL_006e: ldloc.0
+ IL_006f: isinst ""int?""
+ IL_0074: unbox.any ""int?""
+ IL_0079: stloc.2
+ IL_007a: ldloca.s V_2
+ IL_007c: call ""int int?.GetValueOrDefault()""
+ IL_0081: stloc.1
+ IL_0082: ldloca.s V_2
+ IL_0084: call ""bool int?.HasValue.get""
+ IL_0089: brfalse.s IL_00c4
+ IL_008b: br.s IL_00bd
+ IL_008d: ldsfld ""bool Program.b""
+ IL_0092: brtrue.s IL_00ca
+ IL_0094: ldsfld ""bool Program.b""
+ IL_0099: brtrue.s IL_00ca
+ IL_009b: br.s IL_0027
+ IL_009d: ldsfld ""bool Program.b""
+ IL_00a2: brtrue.s IL_00ca
+ IL_00a4: ldsfld ""bool Program.b""
+ IL_00a9: brtrue.s IL_00ca
+ IL_00ab: br.s IL_0049
+ IL_00ad: ldsfld ""bool Program.b""
+ IL_00b2: brtrue.s IL_00ca
+ IL_00b4: ldsfld ""bool Program.b""
+ IL_00b9: brtrue.s IL_00ca
+ IL_00bb: br.s IL_006b
+ IL_00bd: ldsfld ""bool Program.b""
+ IL_00c2: brtrue.s IL_00ca
+ IL_00c4: ldsfld ""bool Program.b""
+ IL_00c9: pop
+ IL_00ca: ret
+}"
+ );
+ compVerifier = CompileAndVerify(source,
+ options: TestOptions.DebugDll.WithOutputKind(OutputKind.ConsoleApplication),
+ expectedOutput: "");
+ compVerifier.VerifyIL("Program.M",
+@"{
+ // Code size 276 (0x114)
+ .maxstack 1
+ .locals init (object V_0,
+ int V_1,
+ int V_2, //i
+ int V_3, //i
+ int V_4, //i
+ int V_5, //i
+ object V_6,
+ int? V_7)
+ IL_0000: nop
+ IL_0001: ldarg.0
+ IL_0002: stloc.s V_6
+ IL_0004: ldloc.s V_6
+ IL_0006: stloc.0
+ IL_0007: ldloc.0
+ IL_0008: brtrue.s IL_000c
+ IL_000a: br.s IL_002c
+ IL_000c: ldloc.0
+ IL_000d: isinst ""int?""
+ IL_0012: unbox.any ""int?""
+ IL_0017: stloc.s V_7
+ IL_0019: ldloca.s V_7
+ IL_001b: call ""int int?.GetValueOrDefault()""
+ IL_0020: stloc.1
+ IL_0021: ldloca.s V_7
+ IL_0023: call ""bool int?.HasValue.get""
+ IL_0028: brfalse.s IL_002c
+ IL_002a: br.s IL_00a8
+ IL_002c: br IL_00b8
+ IL_0031: ldloc.0
+ IL_0032: brtrue.s IL_0036
+ IL_0034: br.s IL_0056
+ IL_0036: ldloc.0
+ IL_0037: isinst ""int?""
+ IL_003c: unbox.any ""int?""
+ IL_0041: stloc.s V_7
IL_0043: ldloca.s V_7
- IL_0045: call ""bool Generic.Color?.HasValue.get""
- IL_004a: brfalse.s IL_0060
- IL_004c: ldloc.2
- IL_004d: stloc.s V_8
- IL_004f: ldloc.s V_8
- IL_0051: brfalse.s IL_005c
- IL_0053: br.s IL_0055
- IL_0055: ldloc.s V_8
- IL_0057: ldc.i4.1
- IL_0058: beq.s IL_005e
- IL_005a: br.s IL_0060
- IL_005c: br.s IL_007c
- IL_005e: br.s IL_0085
- IL_0060: br.s IL_008e
- IL_0062: ldloc.1
- IL_0063: stloc.s V_4
- IL_0065: br.s IL_0067
- IL_0067: ldstr ""Generic