diff --git a/.vsts-dotnet.yml b/.vsts-dotnet.yml
new file mode 100644
index 0000000000000..32d2ba1f9e975
--- /dev/null
+++ b/.vsts-dotnet.yml
@@ -0,0 +1,129 @@
+phases:
+- phase: Windows_Desktop_Unit_Tests
+ queue:
+ name: Helix
+ timeoutInMinutes: 90
+ parallel: 4
+ matrix:
+ debug_32:
+ _configuration: Debug
+ _testKind: Test32
+ debug_64:
+ _configuration: Debug
+ _testKind: Test64
+ release_32:
+ _configuration: Release
+ _testKind: Test32
+ release_64:
+ _configuration: Release
+ _testKind: Test64
+
+ steps:
+ - script: build/scripts/cibuild.cmd -$(_configuration) -testDesktop -$(_testKind)
+
+ - task: PublishTestResults@1
+ inputs:
+ testRunner: XUnit
+ testResultsFiles: '**/xUnitResults/*.xml'
+ mergeTestResults: true
+ testRunTitle: 'Windows Desktop $(_configuration) $(_testKind)'
+ condition: succeededOrFailed()
+
+ - task: PublishBuildArtifacts@1
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\Binaries\$(_configuration)\Logs'
+ ArtifactName: 'Windows Desktop $(_configuration) $(_testKind)'
+ publishLocation: Container
+ continueOnError: true
+ condition: failed()
+
+- phase: Windows_CoreClr_Unit_Tests
+ queue:
+ name: Helix
+ timeoutInMinutes: 90
+ parallel: 2
+ matrix:
+ debug:
+ _configuration: Debug
+ release:
+ _configuration: Release
+
+ steps:
+ - script: build/scripts/cibuild.cmd -$(_configuration) -testCoreClr -buildCoreClr
+
+ - task: PublishTestResults@1
+ inputs:
+ testRunner: XUnit
+ testResultsFiles: '**/xUnitResults/*.xml'
+ mergeTestResults: true
+ testRunTitle: 'Windows CoreClr $(_configuration)'
+ condition: succeededOrFailed()
+
+ - task: PublishBuildArtifacts@1
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\Binaries\$(_configuration)\Logs'
+ ArtifactName: 'Windows CoreClr $(_configuration)'
+ publishLocation: Container
+ continueOnError: true
+ condition: failed()
+
+- phase: Windows_Determinism_Test
+ queue:
+ name: Helix
+ timeoutInMinutes: 90
+ steps:
+ - script: build/scripts/cibuild.cmd -testDeterminism
+
+ - task: PublishBuildArtifacts@1
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\Binaries\Debug\Logs'
+ ArtifactName: 'Build Determinism Files'
+ publishLocation: Container
+ continueOnError: true
+ condition: failed()
+
+- phase: Windows_Correctness_Test
+ queue:
+ name: Helix
+ timeoutInMinutes: 90
+ steps:
+ - script: build/scripts/test-build-correctness.cmd -cibuild -release
+
+ - task: PublishBuildArtifacts@1
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\Binaries\Release\Logs'
+ ArtifactName: 'Build Correctness Files'
+ publishLocation: Container
+ continueOnError: true
+ condition: failed()
+
+- phase: Linux_Test
+ queue:
+ name: DotNetCore-Linux
+ timeoutInMinutes: 90
+ parallel: 2
+ matrix:
+ coreclr:
+ _args: --debug
+ _name: CoreClr
+ mono:
+ _args: --debug --docker --mono
+ _name: Mono
+ steps:
+ - script: ./build/scripts/cibuild.sh $(_args)
+ - task: PublishTestResults@1
+ inputs:
+ testRunner: XUnit
+ testResultsFiles: '**/xUnitResults/*.xml'
+ mergeTestResults: true
+ testRunTitle: 'Linux $(_name)'
+ condition: succeededOrFailed()
+
+ - task: PublishBuildArtifacts@1
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/Binaries/$(_configuration)/Logs'
+ ArtifactName: 'Linux $(_name)'
+ publishLocation: Container
+ continueOnError: true
+ condition: failed()
+
diff --git a/build/Targets/Settings.props b/build/Targets/Settings.props
index 4fcc6aadef6a6..d8462519692f7 100644
--- a/build/Targets/Settings.props
+++ b/build/Targets/Settings.props
@@ -24,8 +24,11 @@
false
true
+ false
+ true
false
- true
+ true
+ false
true
$(RepoRoot)nuget.exe
diff --git a/build/scripts/build-utils.ps1 b/build/scripts/build-utils.ps1
index e34d6c88d406e..f90a0fd0edf64 100644
--- a/build/scripts/build-utils.ps1
+++ b/build/scripts/build-utils.ps1
@@ -148,6 +148,7 @@ function Ensure-DotnetSdk() {
Create-Directory $cliDir
Create-Directory $toolsDir
$destFile = Join-Path $toolsDir "dotnet-install.ps1"
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$webClient = New-Object -TypeName "System.Net.WebClient"
$webClient.DownloadFile("https://dot.net/v1/dotnet-install.ps1", $destFile)
Exec-Block { & $destFile -Version $sdkVersion -InstallDir $cliDir } | Out-Null
diff --git a/build/scripts/build.ps1 b/build/scripts/build.ps1
index 902dad6163131..78f6136baf793 100644
--- a/build/scripts/build.ps1
+++ b/build/scripts/build.ps1
@@ -367,7 +367,7 @@ function Build-InsertionItems() {
}
function Build-Installer () {
- # Copying Artifacts
+ ## Copying Artifacts
$installerDir = Join-Path $configDir "Installer"
Create-Directory $installerDir
diff --git a/build/scripts/test-determinism.ps1 b/build/scripts/test-determinism.ps1
index cd5963864b609..17b1335a51e5b 100644
--- a/build/scripts/test-determinism.ps1
+++ b/build/scripts/test-determinism.ps1
@@ -1,6 +1,15 @@
+####
+#
+# $bootstrapDir: directory containing the bootstrap compiler
+# $release: whether to build a debug or release build
+# $altRootDrive: the drive we build on (via subst) for verifying pathmap implementation
+#
+####
[CmdletBinding(PositionalBinding=$false)]
param ( [string]$bootstrapDir = "",
- [switch]$debugDeterminism = $false)
+ [switch]$release = $false,
+ [string]$altRootDrive = "q:")
+
Set-StrictMode -version 2.0
$ErrorActionPreference = "Stop"
@@ -12,26 +21,25 @@ $ErrorActionPreference = "Stop"
$script:skipList = @()
# Location that deterministic error information should be written to.
-[string]$script:errorDir = ""
-[string]$script:errorDirLeft = ""
-[string]$script:errorDirRight = ""
+[string]$errorDir = ""
+[string]$errorDirLeft = ""
+[string]$errorDirRight = ""
-function Run-Build([string]$rootDir, [switch]$restore = $false, [string]$logFile = $null) {
+function Run-Build([string]$rootDir, [string]$logFile = $null) {
Push-Location $rootDir
try {
# Clean out the previous run
Write-Host "Cleaning the Binaries"
- Exec-Console $msbuild "/nologo /v:m /nodeReuse:false /t:clean Roslyn.sln"
+ Remove-Item -Recurse (Get-ConfigDir $rootDir)
+ Remove-Item -Recurse (Get-ObjDir $rootDir)
- if ($restore) {
- Write-Host "Restoring the packages"
- Restore-Project $dotnet "Roslyn.sln"
- }
+ Write-Host "Restoring the packages"
+ Restore-Project $dotnet "Roslyn.sln"
- $args = "/nologo /v:m /nodeReuse:false /m /p:DebugDeterminism=true /p:BootstrapBuildPath=$script:bootstrapDir /p:Features=`"debug-determinism`" /p:UseRoslynAnalyzers=false /p:DeployExtension=false Roslyn.sln"
+ $args = "/nologo /v:m /nodeReuse:false /m /p:DebugDeterminism=true /p:DeveloperBuild=false /p:BootstrapBuildPath=$script:bootstrapDir /p:Features=`"debug-determinism`" /p:UseRoslynAnalyzers=false /p:DeployExtension=false Roslyn.sln"
if ($logFile -ne $null) {
- $logFile = Join-Path $binariesDir $logFile
+ $logFile = Join-Path $logDir $logFile
$args += " /bl:$logFile"
}
@@ -47,27 +55,45 @@ function Get-ObjDir([string]$rootDir) {
return Join-Path $rootDir "Binaries\Obj"
}
+function Get-ConfigDir([string]$rootDir) {
+ return Join-Path $rootDir "Binaries\$buildConfiguration"
+}
+
# Return all of the files that need to be processed for determinism under the given
# directory.
function Get-FilesToProcess([string]$rootDir) {
$objDir = Get-ObjDir $rootDir
- foreach ($item in Get-ChildItem -re -in *.dll,*.exe,*.pdb $objDir) {
- $fileFullName = $item.FullName
- $fileName = Split-Path -leaf $fileFullName
+ foreach ($item in Get-ChildItem -re -in *.dll,*.exe,*.pdb,*.sourcelink.json $objDir) {
+ $filePath = $item.FullName
+ $fileName = Split-Path -leaf $filePath
if ($skipList.Contains($fileName)) {
continue;
}
- $fileId = $fileFullName.Substring($objDir.Length).Replace("\", ".")
- $fileHash = (Get-FileHash $fileFullName -algorithm MD5).Hash
+ $fileId = $filePath.Substring($objDir.Length).Replace("\", ".")
+ $fileHash = (Get-FileHash $filePath -algorithm MD5).Hash
$data = @{}
$data.Hash = $fileHash
- $data.Content = [IO.File]::ReadAllBytes($fileFullName)
+ $data.Content = [IO.File]::ReadAllBytes($filePath)
$data.FileId = $fileId
$data.FileName = $fileName
- $data.FileFullName = $fileFullName
+ $data.FilePath = $filePath
+
+ $keyFilePath = $filePath + ".key"
+ $keyFileName = Split-Path -leaf $keyFilePath
+ if (Test-Path $keyFilePath) {
+ $data.KeyFileName = $keyFileName
+ $data.KeyFilePath = $keyFilePath
+ $data.KeyFileContent = [IO.File]::ReadAllBytes($keyFilePath)
+ }
+ else {
+ $data.KeyFileName = ""
+ $data.KeyFilePath = ""
+ $data.KeyFileContent = $null
+ }
+
Write-Output $data
}
}
@@ -117,8 +143,8 @@ function Test-MapContents($dataMap) {
}
}
-function Test-Build([string]$rootDir, $dataMap, [string]$logFile, [switch]$restore = $false) {
- Run-Build $rootDir -logFile $logFile -restore:$restore
+function Test-Build([string]$rootDir, $dataMap, [string]$logFile) {
+ Run-Build $rootDir -logFile $logFile
$errorList = @()
$allGood = $true
@@ -127,10 +153,10 @@ function Test-Build([string]$rootDir, $dataMap, [string]$logFile, [switch]$resto
foreach ($fileData in Get-FilesToProcess $rootDir) {
$fileId = $fileData.FileId
$fileName = $fileData.FileName
- $fileFullName = $fileData.FileFullName
+ $filePath = $fileData.FilePath
if (-not $dataMap.Contains($fileId)) {
- Write-Host "ERROR! Missing entry in map $fileId->$fileFullName"
+ Write-Host "ERROR! Missing entry in map $fileId->$filePath"
$allGood = $false
continue
}
@@ -142,8 +168,16 @@ function Test-Build([string]$rootDir, $dataMap, [string]$logFile, [switch]$resto
$errorList += $fileName
# Save out the original and baseline so Jenkins will archive them for investigation
- [IO.File]::WriteAllBytes((Join-Path $script:errorDirLeft $fileName), $oldFileData.Content)
- Copy-Item $fileFullName (Join-Path $script:errorDirRight $fileName)
+ [IO.File]::WriteAllBytes((Join-Path $errorDirLeft $fileName), $oldFileData.Content)
+ Copy-Item $filePath (Join-Path $errorDirRight $fileName)
+
+ # Copy the key files if available too
+ $keyFileName = $oldFileData.KeyFileName
+ if ($keyFileName -ne "") {
+ [IO.File]::WriteAllBytes((Join-Path $errorDirLeft $keyFileName), $oldFileData.KeyFileContent)
+ Copy-Item $fileData.KeyFilePath (Join-Path $errorDirRight $keyFileName)
+ }
+
continue
}
@@ -157,7 +191,7 @@ function Test-Build([string]$rootDir, $dataMap, [string]$logFile, [switch]$resto
}
Write-Host "Archiving failure information"
- $zipFile = Join-Path $repoDir "Binaries\determinism.zip"
+ $zipFile = Join-Path $logDir "determinism.zip"
Add-Type -Assembly "System.IO.Compression.FileSystem";
[System.IO.Compression.ZipFile]::CreateFromDirectory($script:errorDir, $zipFile, "Fastest", $true);
@@ -169,14 +203,6 @@ function Test-Build([string]$rootDir, $dataMap, [string]$logFile, [switch]$resto
function Run-Test() {
$rootDir = $repoDir
- # Ensure the error directory is written for all analysis to use.
- $script:errorDir = Join-Path $repoDir "Binaries\Determinism"
- $script:errorDirLeft = Join-Path $script:errorDir "Left"
- $script:errorDirRight = Join-Path $script:errorDir "Right"
- Create-Directory $script:errorDir
- Create-Directory $script:errorDirLeft
- Create-Directory $script:errorDirRight
-
# Run the initial build so that we can populate the maps
Run-Build $repoDir -logFile "initial.binlog"
$dataMap = Record-Binaries $repoDir
@@ -188,19 +214,30 @@ function Run-Test() {
# Run another build in a different source location and verify that path mapping
# allows the build to be identical. To do this we'll copy the entire source
# tree under the Binaries\q directory and run a build from there.
- $altRootDir = Join-Path "$repoDir\Binaries" "q"
- Remove-Item -re -fo $altRootDir -ErrorAction SilentlyContinue
- & robocopy $repoDir $altRootDir /E /XD $binariesDir /XD ".git" /njh /njs /ndl /nc /ns /np /nfl
-
- # Symlink the .git directory to make SourceLink think Binaries/q is the repo root:
- & cmd /c mklink /d (Join-Path $altRootDir ".git") (Join-Path $repoDir ".git")
-
- Test-Build -rootDir $altRootDir -dataMap $dataMap -logFile "test2.binlog" -restore
+ Write-Host "Building in a different directory"
+ Exec-Command "subst" "$altRootDrive $(Split-Path -parent $repoDir)"
+ try {
+ $altRootDir = Join-Path "$($altRootDrive)\" (Split-Path -leaf $repoDir)
+ Test-Build -rootDir $altRootDir -dataMap $dataMap -logFile "test2.binlog"
+ }
+ finally {
+ Exec-Command "subst" "$altRootDrive /d"
+ }
}
try {
. (Join-Path $PSScriptRoot "build-utils.ps1")
+ # Create all of the logging directories
+ $buildConfiguration = if ($release) { "Release" } else { "Debug" }
+ $logDir = Join-Path (Get-ConfigDir $repoDir) "Logs"
+ $errorDir = Join-Path $binariesDir "Determinism"
+ $errorDirLeft = Join-Path $errorDir "Left"
+ $errorDirRight = Join-Path $errorDir "Right"
+ Create-Directory $logDir
+ Create-Directory $errorDirLeft
+ Create-Directory $errorDirRight
+
$dotnet = Ensure-DotnetSdk
$msbuild = Ensure-MSBuild
if (($bootstrapDir -eq "") -or (-not ([IO.Path]::IsPathRooted($script:bootstrapDir)))) {
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.NamespaceOrTypeOrAliasSymbolWithAnnotations.cs b/src/Compilers/CSharp/Portable/Binder/Binder.NamespaceOrTypeOrAliasSymbolWithAnnotations.cs
index e7034128399d9..725edb4a5c734 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder.NamespaceOrTypeOrAliasSymbolWithAnnotations.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder.NamespaceOrTypeOrAliasSymbolWithAnnotations.cs
@@ -9,21 +9,23 @@ internal partial class Binder
{
internal struct NamespaceOrTypeOrAliasSymbolWithAnnotations
{
- private readonly object _symbolOrTypeSymbolWithAnnotations;
+ private readonly TypeSymbolWithAnnotations _type;
+ private readonly Symbol _symbol;
- private NamespaceOrTypeOrAliasSymbolWithAnnotations(object symbolOrTypeSymbolWithAnnotations)
+ private NamespaceOrTypeOrAliasSymbolWithAnnotations(TypeSymbolWithAnnotations type, Symbol symbol)
{
- Debug.Assert(symbolOrTypeSymbolWithAnnotations != null);
- Debug.Assert(!(symbolOrTypeSymbolWithAnnotations is TypeSymbol));
- _symbolOrTypeSymbolWithAnnotations = symbolOrTypeSymbolWithAnnotations;
+ Debug.Assert(type.IsNull != (symbol is null));
+ Debug.Assert(!(symbol is TypeSymbol));
+ _type = type;
+ _symbol = symbol;
}
- internal TypeSymbolWithAnnotations Type => _symbolOrTypeSymbolWithAnnotations as TypeSymbolWithAnnotations;
- internal Symbol Symbol => _symbolOrTypeSymbolWithAnnotations as Symbol ?? Type?.TypeSymbol;
- internal bool IsType => !(Type is null);
- internal bool IsAlias => (_symbolOrTypeSymbolWithAnnotations as Symbol)?.Kind == SymbolKind.Alias;
+ internal TypeSymbolWithAnnotations Type => _type;
+ internal Symbol Symbol => _symbol ?? Type.TypeSymbol;
+ internal bool IsType => !_type.IsNull;
+ internal bool IsAlias => _symbol?.Kind == SymbolKind.Alias;
internal NamespaceOrTypeSymbol NamespaceOrTypeSymbol => Symbol as NamespaceOrTypeSymbol;
- internal bool IsDefault => _symbolOrTypeSymbolWithAnnotations is null;
+ internal bool IsDefault => _type.IsNull && _symbol is null;
internal static NamespaceOrTypeOrAliasSymbolWithAnnotations CreateUnannotated(INonNullTypesContext nonNullTypesContext, Symbol symbol)
{
@@ -32,16 +34,14 @@ internal static NamespaceOrTypeOrAliasSymbolWithAnnotations CreateUnannotated(IN
return default;
}
var type = symbol as TypeSymbol;
- if (type is null)
- {
- return new NamespaceOrTypeOrAliasSymbolWithAnnotations(symbol);
- }
- return new NamespaceOrTypeOrAliasSymbolWithAnnotations(TypeSymbolWithAnnotations.CreateUnannotated(nonNullTypesContext, type));
+ return type is null ?
+ new NamespaceOrTypeOrAliasSymbolWithAnnotations(default, symbol) :
+ new NamespaceOrTypeOrAliasSymbolWithAnnotations(TypeSymbolWithAnnotations.CreateUnannotated(nonNullTypesContext, type), null);
}
public static implicit operator NamespaceOrTypeOrAliasSymbolWithAnnotations(TypeSymbolWithAnnotations type)
{
- return new NamespaceOrTypeOrAliasSymbolWithAnnotations(type);
+ return new NamespaceOrTypeOrAliasSymbolWithAnnotations(type, null);
}
}
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
index e25e5ae00f728..bf255beb1643d 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
@@ -916,7 +916,7 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV
// change from Dev10 which reports this error for struct types only,
// not for type parameters constrained to "struct".
- Debug.Assert((object)propertySymbol.Type != null);
+ Debug.Assert(!propertySymbol.Type.IsNull);
Error(diagnostics, ErrorCode.ERR_ReturnNotLValue, expr.Syntax, propertySymbol);
}
else
@@ -1622,7 +1622,7 @@ private static void ReportReadOnlyFieldError(FieldSymbol field, SyntaxNode node,
{
Debug.Assert((object)field != null);
Debug.Assert(RequiresAssignableVariable(kind));
- Debug.Assert((object)field.Type != null);
+ Debug.Assert(!field.Type.IsNull);
// It's clearer to say that the address can't be taken than to say that the field can't be modified
// (even though the latter message gives more explanation of why).
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs
index 2ca6ec2293c99..09b5d1bc16c2a 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs
@@ -239,7 +239,7 @@ private void ValidateTypeForAttributeParameters(ImmutableArray
foreach (var parameter in parameters)
{
var paramType = parameter.Type;
- Debug.Assert((object)paramType != null);
+ Debug.Assert(!paramType.IsNull);
if (!paramType.TypeSymbol.IsValidAttributeParameterType(Compilation))
{
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs
index 43e6e86e97e8e..43972efe5f121 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs
@@ -740,7 +740,7 @@ private static ImmutableArray PerformCrefOverloadResolution(ArrayBuilder
containingType: null,
name: null,
refKind: RefKind.None,
- returnType: null,
+ returnType: default,
refCustomModifiers: ImmutableArray.Empty,
explicitInterfaceImplementations: ImmutableArray.Empty);
break;
@@ -755,7 +755,7 @@ private static ImmutableArray PerformCrefOverloadResolution(ArrayBuilder
containingType: null,
name: null,
refKind: RefKind.None,
- type: null,
+ type: default,
refCustomModifiers: ImmutableArray.Empty,
isStatic: false,
explicitInterfaceImplementations: ImmutableArray.Empty);
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
index 415f2da9765d8..f7e9480108c8b 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
@@ -726,7 +726,7 @@ private DeconstructionVariable BindDeconstructionVariables(
bool isConst = false;
AliasSymbol alias;
var declType = BindVariableType(component.Designation, diagnostics, component.Type, ref isConst, out isVar, out alias);
- Debug.Assert(isVar == ((object)declType == null));
+ Debug.Assert(isVar == declType.IsNull);
if (component.Designation.Kind() == SyntaxKind.ParenthesizedVariableDesignation && !isVar)
{
// An explicit is not allowed with a parenthesized designation
@@ -800,7 +800,7 @@ private static BoundDiscardExpression BindDiscardExpression(
SyntaxNode syntax,
TypeSymbolWithAnnotations declType)
{
- return new BoundDiscardExpression(syntax, declType?.TypeSymbol);
+ return new BoundDiscardExpression(syntax, declType.TypeSymbol);
}
///
@@ -824,7 +824,7 @@ private BoundExpression BindDeconstructionVariable(
// might own nested scope.
var hasErrors = localSymbol.ScopeBinder.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics);
- if ((object)declType != null)
+ if (!declType.IsNull)
{
return new BoundLocal(syntax, localSymbol, BoundLocalDeclarationKind.WithExplicitType, constantValueOpt: null, isNullableUnknown: false, type: declType.TypeSymbol, hasErrors: hasErrors);
}
@@ -844,7 +844,7 @@ private BoundExpression BindDeconstructionVariable(
BoundThisReference receiver = ThisReference(designation, this.ContainingType, hasErrors: false,
wasCompilerGenerated: true);
- if ((object)declType != null)
+ if (!declType.IsNull)
{
var fieldType = field.GetFieldType(this.FieldsBeingBound);
Debug.Assert(declType.TypeSymbol == fieldType.TypeSymbol);
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
index 27745ce2d1827..f49bfda43f095 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
@@ -676,7 +676,7 @@ private BoundExpression BindDeclarationExpression(DeclarationExpressionSyntax no
///
private BoundExpression BindDeclarationVariables(TypeSymbolWithAnnotations declType, VariableDesignationSyntax node, CSharpSyntaxNode syntax, DiagnosticBag diagnostics)
{
- declType = declType ?? TypeSymbolWithAnnotations.Create(CreateErrorType("var"));
+ declType = declType.IsNull ? TypeSymbolWithAnnotations.Create(CreateErrorType("var")) : declType;
switch (node.Kind())
{
case SyntaxKind.SingleVariableDesignation:
@@ -783,7 +783,7 @@ private BoundExpression BindTupleExpression(TupleExpressionSyntax node, Diagnost
var elementType = boundArgument.GetTypeAndNullability(includeNullability);
elementTypes.Add(elementType);
- if ((object)elementType == null)
+ if (elementType.IsNull)
{
hasNaturalType = false;
}
@@ -2056,7 +2056,7 @@ private void GenerateExplicitConversionErrorsForTupleLiteralArguments(
///
private BoundExpression BindExplicitNullableCastFromNonNullable(ExpressionSyntax node, BoundExpression operand, TypeSymbolWithAnnotations targetType, DiagnosticBag diagnostics)
{
- Debug.Assert((object)targetType != null && targetType.IsNullableType());
+ Debug.Assert(!targetType.IsNull && targetType.IsNullableType());
Debug.Assert(operand.Type != null && !operand.Type.IsNullableType());
// Section 6.2.3 of the spec only applies when the non-null version of the types involved have a
@@ -2310,9 +2310,9 @@ private BoundExpression BindOutDeclarationArgument(DeclarationExpressionSyntax d
bool isConst = false;
AliasSymbol alias;
var declType = BindVariableType(designation, diagnostics, typeSyntax, ref isConst, out isVar, out alias);
- Debug.Assert(isVar == ((object)declType == null));
+ Debug.Assert(isVar == declType.IsNull);
- return new BoundDiscardExpression(declarationExpression, declType?.TypeSymbol);
+ return new BoundDiscardExpression(declarationExpression, declType.TypeSymbol);
}
case SyntaxKind.SingleVariableDesignation:
return BindOutVariableDeclarationArgument(declarationExpression, diagnostics);
@@ -2563,7 +2563,7 @@ private void CoerceArguments(
else if (argument.Kind == BoundKind.DiscardExpression && !argument.HasExpressionType())
{
TypeSymbolWithAnnotations parameterType = GetCorrespondingParameterType(ref result, parameters, arg);
- Debug.Assert((object)parameterType != null);
+ Debug.Assert(!parameterType.IsNull);
arguments[arg] = ((BoundDiscardExpression)argument).SetInferredType(parameterType);
}
}
@@ -2711,7 +2711,7 @@ private BoundExpression BindImplicitArrayCreationExpression(ImplicitArrayCreatio
useSiteDiagnostics: ref useSiteDiagnostics);
diagnostics.Add(node, useSiteDiagnostics);
- if ((object)bestType == null || bestType.SpecialType == SpecialType.System_Void) // Dev10 also reports ERR_ImplicitlyTypedArrayNoBestType for void.
+ if (bestType.IsNull || bestType.SpecialType == SpecialType.System_Void) // Dev10 also reports ERR_ImplicitlyTypedArrayNoBestType for void.
{
Error(diagnostics, ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, node);
bestType = TypeSymbolWithAnnotations.Create(CreateErrorType());
@@ -2737,7 +2737,7 @@ private BoundExpression BindImplicitStackAllocArrayCreationExpression(ImplicitSt
TypeSymbolWithAnnotations bestType = BestTypeInferrer.InferBestType(boundInitializerExpressions, this.Conversions, out bool hadMultipleCandidates, ref useSiteDiagnostics);
diagnostics.Add(node, useSiteDiagnostics);
- if ((object)bestType == null || bestType.SpecialType == SpecialType.System_Void)
+ if (bestType.IsNull || bestType.SpecialType == SpecialType.System_Void)
{
Error(diagnostics, ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, node);
bestType = TypeSymbolWithAnnotations.Create(CreateErrorType());
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs
index af95bddeb89e9..d4a2f8b209683 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs
@@ -113,7 +113,7 @@ private Tuple, ImmutableArray
}
var typeSyntax = p.Type;
- TypeSymbolWithAnnotations type = null;
+ TypeSymbolWithAnnotations type = default;
var refKind = RefKind.None;
if (typeSyntax == null)
@@ -228,7 +228,7 @@ private UnboundLambda BindAnonymousFunction(CSharpSyntaxNode syntax, DiagnosticB
foreach (var type in types)
{
// UNDONE: Where do we report improper use of pointer types?
- if ((object)type != null && type.IsStatic)
+ if (!type.IsNull && type.IsStatic)
{
Error(diagnostics, ErrorCode.ERR_ParameterIsStaticClass, syntax, type.TypeSymbol);
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
index 114534c7bc5f9..6e554dc3644ee 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
@@ -3645,7 +3645,7 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node
useSiteDiagnostics: ref useSiteDiagnostics);
diagnostics.Add(node, useSiteDiagnostics);
- if ((object)bestType == null)
+ if (bestType.IsNull)
{
// CONSIDER: Dev10 suppresses ERR_InvalidQM unless the following is true for both trueType and falseType
// (!T->type->IsErrorType() || T->type->AsErrorType()->HasTypeParent() || T->type->AsErrorType()->HasNSParent())
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
index 9c7cdc1bac391..7dd94310dbb06 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
@@ -253,7 +253,7 @@ private BoundPattern BindDeclarationPattern(
declType = TypeSymbolWithAnnotations.CreateUnannotated(NonNullTypesContext, operandType);
}
- if (declType == (object)null)
+ if (declType.IsNull)
{
Debug.Assert(hasErrors);
declType = TypeSymbolWithAnnotations.CreateUnannotated(NonNullTypesContext, this.CreateErrorType("var"));
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
index c1807d3b0a377..9259f405922af 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
@@ -664,7 +664,7 @@ declarationNode is VariableDesignationSyntax ||
// we want to treat the declaration as an explicitly typed declaration.
TypeSymbolWithAnnotations declType = BindTypeOrVarKeyword(typeSyntax.SkipRef(out _), diagnostics, out isVar, out alias);
- Debug.Assert((object)declType != null || isVar);
+ Debug.Assert(!declType.IsNull || isVar);
if (isVar)
{
@@ -851,7 +851,7 @@ protected BoundLocalDeclaration BindVariableDeclaration(
CSharpSyntaxNode associatedSyntaxNode = null)
{
Debug.Assert(declarator != null);
- Debug.Assert((object)declTypeOpt != null || isVar);
+ Debug.Assert(!declTypeOpt.IsNull || isVar);
Debug.Assert(typeSyntax != null);
var localDiagnostics = DiagnosticBag.GetInstance();
@@ -934,7 +934,7 @@ protected BoundLocalDeclaration BindVariableDeclaration(
}
}
- Debug.Assert((object)declTypeOpt != null);
+ Debug.Assert(!declTypeOpt.IsNull);
if (kind == LocalDeclarationKind.FixedVariable)
{
@@ -2336,7 +2336,7 @@ internal BoundStatement BindForOrUsingOrFixedDeclarations(VariableDeclarationSyn
bool isVar;
TypeSymbolWithAnnotations declType = BindTypeOrVarKeyword(typeSyntax, diagnostics, out isVar, out alias);
- Debug.Assert((object)declType != null || isVar);
+ Debug.Assert(!declType.IsNull || isVar);
var variables = nodeOpt.Variables;
int count = variables.Count;
@@ -2475,7 +2475,7 @@ protected virtual TypeSymbol GetCurrentReturnType(out RefKind refKind)
TypeSymbolWithAnnotations returnType = symbol.ReturnType;
- if ((object)returnType == null || (object)returnType == LambdaSymbol.ReturnTypeIsBeingInferred)
+ if (returnType.IsNull || (object)returnType.TypeSymbol == LambdaSymbol.ReturnTypeIsBeingInferred)
{
return null;
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
index 60dc985d4f69a..a80989af35998 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
@@ -32,7 +32,7 @@ internal TypeSymbolWithAnnotations BindTypeOrVarKeyword(TypeSyntax syntax, Diagn
{
var symbol = BindTypeOrAliasOrVarKeyword(syntax, diagnostics, out isVar);
Debug.Assert(isVar == symbol.IsDefault);
- return isVar ? null : UnwrapAlias(symbol, diagnostics, syntax).Type;
+ return isVar ? default : UnwrapAlias(symbol, diagnostics, syntax).Type;
}
///
@@ -52,7 +52,7 @@ internal TypeSymbolWithAnnotations BindTypeOrUnmanagedKeyword(TypeSyntax syntax,
{
var symbol = BindTypeOrAliasOrUnmanagedKeyword(syntax, diagnostics, out isUnmanaged);
Debug.Assert(isUnmanaged == symbol.IsDefault);
- return isUnmanaged ? null : UnwrapAlias(symbol, diagnostics, syntax).Type;
+ return isUnmanaged ? default : UnwrapAlias(symbol, diagnostics, syntax).Type;
}
///
@@ -76,7 +76,7 @@ internal TypeSymbolWithAnnotations BindTypeOrVarKeyword(TypeSyntax syntax, Diagn
if (isVar)
{
alias = null;
- return null;
+ return default;
}
else
{
@@ -327,7 +327,7 @@ internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeSymbol(E
internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeSymbol(ExpressionSyntax syntax, DiagnosticBag diagnostics, ConsList basesBeingResolved, bool suppressUseSiteDiagnostics)
{
var result = BindNamespaceOrTypeOrAliasSymbol(syntax, diagnostics, basesBeingResolved, suppressUseSiteDiagnostics);
- Debug.Assert((object)result != null);
+ Debug.Assert(!result.IsDefault);
return UnwrapAlias(result, diagnostics, syntax, basesBeingResolved);
}
@@ -1166,7 +1166,8 @@ private NamedTypeSymbol ConstructNamedType(
if (ShouldCheckConstraints)
{
- type.CheckConstraintsForNonTuple(this.Conversions, typeSyntax, typeArgumentsSyntax, this.Compilation, basesBeingResolved, diagnostics);
+ bool includeNullability = Compilation.IsFeatureEnabled(MessageID.IDS_FeatureStaticNullChecking);
+ type.CheckConstraintsForNonTuple(this.Conversions.WithNullability(includeNullability), typeSyntax, typeArgumentsSyntax, this.Compilation, basesBeingResolved, diagnostics);
}
type = (NamedTypeSymbol)TupleTypeSymbol.TransformToTupleIfCompatible(type);
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs
index 5e788df4a8e94..0329ab515c96d 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs
@@ -386,7 +386,7 @@ private static (ImmutableArray Elements, ImmutableArray
// placeholder bound nodes with the proper types are sufficient to bind the element-wise binary operators
TypeSymbol tupleType = expr.Type.StrippedType();
ImmutableArray placeholders = tupleType.TupleElementTypes
- .SelectAsArray((t, s) => (BoundExpression)new BoundTupleOperandPlaceholder(s, t?.TypeSymbol), expr.Syntax);
+ .SelectAsArray((t, s) => (BoundExpression)new BoundTupleOperandPlaceholder(s, t.TypeSymbol), expr.Syntax);
return (placeholders, tupleType.TupleElementNames);
}
diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachEnumeratorInfo.cs b/src/Compilers/CSharp/Portable/Binder/ForEachEnumeratorInfo.cs
index acc1399276ab1..518f5dc6e949d 100644
--- a/src/Compilers/CSharp/Portable/Binder/ForEachEnumeratorInfo.cs
+++ b/src/Compilers/CSharp/Portable/Binder/ForEachEnumeratorInfo.cs
@@ -48,7 +48,7 @@ private ForEachEnumeratorInfo(
BinderFlags location)
{
Debug.Assert((object)collectionType != null, "Field 'collectionType' cannot be null");
- Debug.Assert((object)elementType != null, "Field 'elementType' cannot be null");
+ Debug.Assert(!elementType.IsNull, "Field 'elementType' cannot be null");
Debug.Assert((object)getEnumeratorMethod != null, "Field 'getEnumeratorMethod' cannot be null");
Debug.Assert((object)currentPropertyGetter != null, "Field 'currentPropertyGetter' cannot be null");
Debug.Assert((object)moveNextMethod != null, "Field 'moveNextMethod' cannot be null");
diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
index 76d31caaf2d08..618022d5f9c59 100644
--- a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
@@ -170,7 +170,7 @@ internal override BoundStatement BindForEachDeconstruction(DiagnosticBag diagnos
ExpressionSyntax variables = ((ForEachVariableStatementSyntax)_syntax).Variable;
// Tracking narrowest safe-to-escape scope by default, the proper val escape will be set when doing full binding of the foreach statement
- var valuePlaceholder = new BoundDeconstructValuePlaceholder(_syntax.Expression, this.LocalScopeDepth, inferredType?.TypeSymbol ?? CreateErrorType("var"));
+ var valuePlaceholder = new BoundDeconstructValuePlaceholder(_syntax.Expression, this.LocalScopeDepth, inferredType.TypeSymbol ?? CreateErrorType("var"));
DeclarationExpressionSyntax declaration = null;
ExpressionSyntax expression = null;
@@ -226,11 +226,11 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
if (isVar)
{
- declType = inferredType ?? TypeSymbolWithAnnotations.Create(CreateErrorType("var"), isNullableIfReferenceType: null);
+ declType = inferredType.IsNull ? TypeSymbolWithAnnotations.Create(CreateErrorType("var"), isNullableIfReferenceType: null) : inferredType;
}
else
{
- Debug.Assert((object)declType != null);
+ Debug.Assert(!declType.IsNull);
}
iterationVariableType = declType.TypeSymbol;
@@ -289,7 +289,7 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
case SyntaxKind.ForEachVariableStatement:
{
var node = (ForEachVariableStatementSyntax)_syntax;
- iterationVariableType = inferredType?.TypeSymbol ?? CreateErrorType("var");
+ iterationVariableType = inferredType.TypeSymbol ?? CreateErrorType("var");
var variables = node.Variable;
if (variables.IsDeconstructionLeft())
@@ -492,7 +492,7 @@ private bool GetEnumeratorInfoAndInferCollectionElementType(ref ForEachEnumerato
if (!gotInfo)
{
- inferredType = null;
+ inferredType = default;
}
else if (collectionExpr.HasDynamicType())
{
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs
index 6fe145add0f87..a136b9e0c53b5 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs
@@ -19,7 +19,7 @@ public static TypeSymbolWithAnnotations InferBestType(ImmutableArray useSiteDiagnostics)
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs
index 32017d08dcdfc..1b0d270614b8b 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs
@@ -20,15 +20,45 @@ internal abstract partial class ConversionsBase
internal readonly bool IncludeNullability;
- protected ConversionsBase(AssemblySymbol corLibrary, int currentRecursionDepth, bool includeNullability)
+ ///
+ /// An optional clone of this instance with distinct IncludeNullability.
+ /// Used to avoid unnecessary allocations when calling WithNullability() repeatedly.
+ ///
+ private ConversionsBase _lazyOtherNullability;
+
+ protected ConversionsBase(AssemblySymbol corLibrary, int currentRecursionDepth, bool includeNullability, ConversionsBase otherNullabilityOpt)
{
Debug.Assert((object)corLibrary != null);
+ Debug.Assert(otherNullabilityOpt == null || includeNullability != otherNullabilityOpt.IncludeNullability);
+ Debug.Assert(otherNullabilityOpt == null || currentRecursionDepth == otherNullabilityOpt.currentRecursionDepth);
this.corLibrary = corLibrary;
this.currentRecursionDepth = currentRecursionDepth;
IncludeNullability = includeNullability;
+ _lazyOtherNullability = otherNullabilityOpt;
}
+ ///
+ /// Returns this instance if includeNullability is correct, and returns a
+ /// cached clone of this instance with distinct includeNullability otherwise.
+ ///
+ internal ConversionsBase WithNullability(bool includeNullability)
+ {
+ if (IncludeNullability == includeNullability)
+ {
+ return this;
+ }
+ if (_lazyOtherNullability == null)
+ {
+ _lazyOtherNullability = WithNullabilityCore(includeNullability);
+ }
+ Debug.Assert(_lazyOtherNullability.IncludeNullability == includeNullability);
+ Debug.Assert(_lazyOtherNullability._lazyOtherNullability == this);
+ return _lazyOtherNullability;
+ }
+
+ protected abstract ConversionsBase WithNullabilityCore(bool includeNullability);
+
public abstract Conversion GetMethodGroupConversion(BoundMethodGroup source, TypeSymbol destination, ref HashSet useSiteDiagnostics);
public abstract Conversion GetStackAllocConversion(BoundStackAllocArrayCreation sourceExpression, TypeSymbol destination, ref HashSet useSiteDiagnostics);
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/TypeConversions.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/TypeConversions.cs
index 284e00923be97..c9490059d762c 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/TypeConversions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/TypeConversions.cs
@@ -4,24 +4,31 @@
using Roslyn.Utilities;
using System;
using System.Collections.Generic;
+using System.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed class TypeConversions : ConversionsBase
{
public TypeConversions(AssemblySymbol corLibrary)
- : this(corLibrary, currentRecursionDepth: 0, includeNullability: false)
+ : this(corLibrary, currentRecursionDepth: 0, includeNullability: false, otherNullabilityOpt: null)
{
}
- private TypeConversions(AssemblySymbol corLibrary, int currentRecursionDepth, bool includeNullability)
- : base(corLibrary, currentRecursionDepth, includeNullability)
+ private TypeConversions(AssemblySymbol corLibrary, int currentRecursionDepth, bool includeNullability, TypeConversions otherNullabilityOpt)
+ : base(corLibrary, currentRecursionDepth, includeNullability, otherNullabilityOpt)
{
}
protected override ConversionsBase CreateInstance(int currentRecursionDepth)
{
- return new TypeConversions(this.corLibrary, currentRecursionDepth, IncludeNullability);
+ return new TypeConversions(this.corLibrary, currentRecursionDepth, IncludeNullability, otherNullabilityOpt: null);
+ }
+
+ protected override ConversionsBase WithNullabilityCore(bool includeNullability)
+ {
+ Debug.Assert(IncludeNullability != includeNullability);
+ return new TypeConversions(corLibrary, currentRecursionDepth, includeNullability, this);
}
public override Conversion GetMethodGroupConversion(BoundMethodGroup source, TypeSymbol destination, ref HashSet useSiteDiagnostics)
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/INonNullTypesContext.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/INonNullTypesContext.cs
index 8359cfa3629e6..24e928978a523 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/INonNullTypesContext.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/INonNullTypesContext.cs
@@ -26,4 +26,10 @@ internal sealed class NonNullTypesFalseContext : INonNullTypesContext
public static readonly INonNullTypesContext Instance = new NonNullTypesFalseContext();
public bool? NonNullTypes => false;
}
+
+ internal sealed class NonNullTypesUnusedContext : INonNullTypesContext
+ {
+ public static readonly INonNullTypesContext Instance = new NonNullTypesUnusedContext();
+ public bool? NonNullTypes => throw ExceptionUtilities.Unreachable;
+ }
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs
index 10ba03e27fb43..fde80b0006d4e 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs
@@ -332,7 +332,7 @@ internal string Dump()
var fixedType = _fixedResults[i];
- if ((object)fixedType == null)
+ if (fixedType.IsNull)
{
sb.Append("UNFIXED ");
}
@@ -378,7 +378,7 @@ private ImmutableArray GetResults()
for (int i = 0; i < _methodTypeParameters.Length; i++)
{
- if ((object)_fixedResults[i] != null)
+ if (!_fixedResults[i].IsNull)
{
if (!_fixedResults[i].IsErrorType())
{
@@ -405,12 +405,12 @@ private bool ValidIndex(int index)
private bool IsUnfixed(int methodTypeParameterIndex)
{
Debug.Assert(ValidIndex(methodTypeParameterIndex));
- return (object)_fixedResults[methodTypeParameterIndex] == null;
+ return _fixedResults[methodTypeParameterIndex].IsNull;
}
private bool IsUnfixedTypeParameter(TypeSymbolWithAnnotations type)
{
- Debug.Assert((object)type != null);
+ Debug.Assert(!type.IsNull);
if (type.TypeKind != TypeKind.TypeParameter) return false;
@@ -1217,7 +1217,7 @@ private bool AnyDependsOn(int iParam)
private void OutputTypeInference(Binder binder, BoundExpression expression, bool? isNullable, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics)
{
Debug.Assert(expression != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!target.IsNull);
// SPEC: An output type inference is made from an expression E to a type T
// SPEC: in the following way:
@@ -1240,7 +1240,7 @@ private void OutputTypeInference(Binder binder, BoundExpression expression, bool
// SPEC: * Otherwise, if E is an expression with type U then a lower-bound
// SPEC: inference is made from U to T.
var sourceType = TypeSymbolWithAnnotations.Create(expression.Type, isNullable);
- if ((object)sourceType != null)
+ if (!sourceType.IsNull)
{
LowerBoundInference(sourceType, target, ref useSiteDiagnostics);
}
@@ -1250,7 +1250,7 @@ private void OutputTypeInference(Binder binder, BoundExpression expression, bool
private bool InferredReturnTypeInference(BoundExpression source, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics)
{
Debug.Assert(source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!target.IsNull);
// SPEC: * If E is an anonymous function with inferred return type U and
// SPEC: T is a delegate type or expression tree with return type Tb
// SPEC: then a lower bound inference is made from U to Tb.
@@ -1266,13 +1266,13 @@ private bool InferredReturnTypeInference(BoundExpression source, TypeSymbolWithA
Debug.Assert((object)delegateType.DelegateInvokeMethod != null && !delegateType.DelegateInvokeMethod.HasUseSiteError,
"This method should only be called for valid delegate types.");
var returnType = delegateType.DelegateInvokeMethod.ReturnType;
- if ((object)returnType == null || returnType.SpecialType == SpecialType.System_Void)
+ if (returnType.IsNull || returnType.SpecialType == SpecialType.System_Void)
{
return false;
}
var inferredReturnType = InferReturnType(source, delegateType, ref useSiteDiagnostics);
- if ((object)inferredReturnType == null)
+ if (inferredReturnType.IsNull)
{
return false;
}
@@ -1309,7 +1309,7 @@ private bool MethodGroupReturnTypeInference(Binder binder, BoundExpression sourc
"This method should only be called for valid delegate types");
TypeSymbolWithAnnotations delegateReturnType = delegateInvokeMethod.ReturnType;
- if ((object)delegateReturnType == null || delegateReturnType.SpecialType == SpecialType.System_Void)
+ if (delegateReturnType.IsNull || delegateReturnType.SpecialType == SpecialType.System_Void)
{
return false;
}
@@ -1372,7 +1372,7 @@ private static TypeSymbol MethodGroupReturnType(
private void ExplicitParameterTypeInference(BoundExpression source, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics)
{
Debug.Assert(source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!target.IsNull);
// SPEC: An explicit type parameter type inference is made from an expression
// SPEC: E to a type T in the following way.
@@ -1430,8 +1430,8 @@ private void ExplicitParameterTypeInference(BoundExpression source, TypeSymbolWi
//
private void ExactInference(TypeSymbolWithAnnotations source, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics)
{
- Debug.Assert((object)source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!source.IsNull);
+ Debug.Assert(!target.IsNull);
// SPEC: An exact inference from a type U to a type V is made as follows:
@@ -1482,8 +1482,8 @@ private void ExactInference(TypeSymbolWithAnnotations source, TypeSymbolWithAnno
private bool ExactTypeParameterInference(TypeSymbolWithAnnotations source, TypeSymbolWithAnnotations target)
{
- Debug.Assert((object)source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!source.IsNull);
+ Debug.Assert(!target.IsNull);
// SPEC: * If V is one of the unfixed Xi then U is added to the set of bounds
// SPEC: for Xi.
@@ -1497,8 +1497,8 @@ private bool ExactTypeParameterInference(TypeSymbolWithAnnotations source, TypeS
private bool ExactArrayInference(TypeSymbolWithAnnotations source, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics)
{
- Debug.Assert((object)source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!source.IsNull);
+ Debug.Assert(!target.IsNull);
// SPEC: * Otherwise, if U is an array type UE[...] and V is an array type VE[...]
// SPEC: of the same rank then an exact inference from UE to VE is made.
@@ -1543,8 +1543,8 @@ private void ExactOrBoundsInference(ExactOrBoundsKind kind, TypeSymbolWithAnnota
private bool ExactOrBoundsNullableInference(ExactOrBoundsKind kind, TypeSymbolWithAnnotations source, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics)
{
- Debug.Assert((object)source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!source.IsNull);
+ Debug.Assert(!target.IsNull);
if (source.IsNullableType() && target.IsNullableType())
{
@@ -1568,8 +1568,8 @@ private bool ExactNullableInference(TypeSymbolWithAnnotations source, TypeSymbol
private bool ExactOrBoundsTupleInference(ExactOrBoundsKind kind, TypeSymbolWithAnnotations source, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics)
{
- Debug.Assert((object)source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!source.IsNull);
+ Debug.Assert(!target.IsNull);
// NOTE: we are losing tuple element names when unwrapping tuple types to underlying types.
// that is ok, because we are inferring type parameters used in the matching elements,
@@ -1600,8 +1600,8 @@ private bool ExactTupleInference(TypeSymbolWithAnnotations source, TypeSymbolWit
private bool ExactConstructedInference(TypeSymbolWithAnnotations source, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics)
{
- Debug.Assert((object)source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!source.IsNull);
+ Debug.Assert(!target.IsNull);
// SPEC: * Otherwise, if V is a constructed type C and U is a constructed
// SPEC: type C then an exact inference
@@ -1668,8 +1668,8 @@ private void ExactTypeArgumentInference(NamedTypeSymbol source, NamedTypeSymbol
//
private void LowerBoundInference(TypeSymbolWithAnnotations source, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics)
{
- Debug.Assert((object)source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!source.IsNull);
+ Debug.Assert(!target.IsNull);
// SPEC: A lower-bound inference from a type U to a type V is made as follows:
@@ -1750,8 +1750,8 @@ private void LowerBoundInference(TypeSymbolWithAnnotations source, TypeSymbolWit
private bool LowerBoundTypeParameterInference(TypeSymbolWithAnnotations source, TypeSymbolWithAnnotations target)
{
- Debug.Assert((object)source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!source.IsNull);
+ Debug.Assert(!target.IsNull);
// SPEC: * If V is one of the unfixed Xi then U is added to the set of bounds
// SPEC: for Xi.
@@ -1774,7 +1774,7 @@ private static TypeSymbolWithAnnotations GetMatchingElementType(ArrayTypeSymbol
var arrayTarget = (ArrayTypeSymbol)target;
if (!arrayTarget.HasSameShapeAs(source))
{
- return null;
+ return default;
}
return arrayTarget.ElementType;
}
@@ -1783,7 +1783,7 @@ private static TypeSymbolWithAnnotations GetMatchingElementType(ArrayTypeSymbol
if (!source.IsSZArray)
{
- return null;
+ return default;
}
// Arrays are specified as being convertible to IEnumerable, ICollection and
@@ -1792,7 +1792,7 @@ private static TypeSymbolWithAnnotations GetMatchingElementType(ArrayTypeSymbol
if (!target.IsPossibleArrayGenericInterface())
{
- return null;
+ return default;
}
return ((NamedTypeSymbol)target).TypeArgumentWithDefinitionUseSiteDiagnostics(0, ref useSiteDiagnostics);
@@ -1819,7 +1819,7 @@ private bool LowerBoundArrayInference(TypeSymbol source, TypeSymbol target, ref
var arraySource = (ArrayTypeSymbol)source;
var elementSource = arraySource.ElementType;
var elementTarget = GetMatchingElementType(arraySource, target, ref useSiteDiagnostics);
- if ((object)elementTarget == null)
+ if (elementTarget.IsNull)
{
return false;
}
@@ -2062,8 +2062,8 @@ private void LowerBoundTypeArgumentInference(NamedTypeSymbol source, NamedTypeSy
//
private void UpperBoundInference(TypeSymbolWithAnnotations source, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics)
{
- Debug.Assert((object)source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!source.IsNull);
+ Debug.Assert(!target.IsNull);
// SPEC: An upper-bound inference from a type U to a type V is made as follows:
@@ -2118,8 +2118,8 @@ private void UpperBoundInference(TypeSymbolWithAnnotations source, TypeSymbolWit
private bool UpperBoundTypeParameterInference(TypeSymbolWithAnnotations source, TypeSymbolWithAnnotations target)
{
- Debug.Assert((object)source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!source.IsNull);
+ Debug.Assert(!target.IsNull);
// SPEC: * If V is one of the unfixed Xi then U is added to the set of upper bounds
// SPEC: for Xi.
if (IsUnfixedTypeParameter(target))
@@ -2132,8 +2132,8 @@ private bool UpperBoundTypeParameterInference(TypeSymbolWithAnnotations source,
private bool UpperBoundArrayInference(TypeSymbolWithAnnotations source, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics)
{
- Debug.Assert((object)source != null);
- Debug.Assert((object)target != null);
+ Debug.Assert(!source.IsNull);
+ Debug.Assert(!target.IsNull);
// SPEC: * Otherwise, if V is an array type Ve[...] and U is an array
// SPEC: type Ue[...] of the same rank, or if V is a one-dimensional array
@@ -2150,7 +2150,7 @@ private bool UpperBoundArrayInference(TypeSymbolWithAnnotations source, TypeSymb
var arrayTarget = (ArrayTypeSymbol)target.TypeSymbol;
var elementTarget = arrayTarget.ElementType;
var elementSource = GetMatchingElementType(arrayTarget, source.TypeSymbol, ref useSiteDiagnostics);
- if ((object)elementSource == null)
+ if (elementSource.IsNull)
{
return false;
}
@@ -2174,8 +2174,8 @@ private bool UpperBoundNullableInference(TypeSymbolWithAnnotations source, TypeS
private bool UpperBoundConstructedInference(TypeSymbolWithAnnotations sourceWithAnnotations, TypeSymbolWithAnnotations targetWithAnnotations, ref HashSet useSiteDiagnostics)
{
- Debug.Assert((object)sourceWithAnnotations != null);
- Debug.Assert((object)targetWithAnnotations != null);
+ Debug.Assert(!sourceWithAnnotations.IsNull);
+ Debug.Assert(!targetWithAnnotations.IsNull);
var source = sourceWithAnnotations.TypeSymbol.TupleUnderlyingTypeOrSelf();
var target = targetWithAnnotations.TypeSymbol.TupleUnderlyingTypeOrSelf();
@@ -2371,7 +2371,7 @@ private bool Fix(int iParam, ref HashSet useSiteDiagnostics)
var withoutNullability = Fix(exact, lower, upper, ref useSiteDiagnostics, _conversions, includeNullability: false);
var best = withNullability;
- if ((object)best == null)
+ if (best.IsNull)
{
best = withoutNullability;
}
@@ -2391,7 +2391,7 @@ private bool Fix(int iParam, ref HashSet useSiteDiagnostics)
}
}
- if ((object)best == null)
+ if (best.IsNull)
{
return false;
}
@@ -2442,13 +2442,13 @@ private static TypeSymbolWithAnnotations Fix(
candidates.AddAll(exact, conversions);
if (candidates.Count >= 2)
{
- return null;
+ return default;
}
}
if (candidates.Count == 0)
{
- return null;
+ return default;
}
// Don't mutate the collection as we're iterating it.
@@ -2510,7 +2510,7 @@ private static TypeSymbolWithAnnotations Fix(
// SPEC: * If among the remaining candidate types there is a unique type V to
// SPEC: which there is an implicit conversion from all the other candidate
// SPEC: types, then the parameter is fixed to V.
- TypeSymbolWithAnnotations best = null;
+ TypeSymbolWithAnnotations best = default;
foreach (var candidate in initialCandidates)
{
foreach (var candidate2 in initialCandidates)
@@ -2522,7 +2522,7 @@ private static TypeSymbolWithAnnotations Fix(
}
}
- if ((object)best == null)
+ if (best.IsNull)
{
best = candidate;
}
@@ -2542,7 +2542,7 @@ private static TypeSymbolWithAnnotations Fix(
else
{
// best candidate is not unique
- best = null;
+ best = default;
break;
}
@@ -2706,7 +2706,7 @@ private TypeSymbolWithAnnotations InferReturnType(BoundExpression source, NamedT
if (source.Kind != BoundKind.UnboundLambda)
{
- return null;
+ return default;
}
var anonymousFunction = (UnboundLambda)source;
@@ -2723,12 +2723,12 @@ private TypeSymbolWithAnnotations InferReturnType(BoundExpression source, NamedT
var originalDelegateParameters = target.DelegateParameters();
if (originalDelegateParameters.IsDefault)
{
- return null;
+ return default;
}
if (originalDelegateParameters.Length != anonymousFunction.ParameterCount)
{
- return null;
+ return default;
}
}
@@ -2745,12 +2745,12 @@ private TypeSymbolWithAnnotations InferReturnType(BoundExpression source, NamedT
{
if (!anonymousFunction.ParameterType(p).TypeSymbol.Equals(fixedDelegateParameters[p].Type.TypeSymbol, TypeCompareKind.IgnoreDynamicAndTupleNames))
{
- return null;
+ return default;
}
}
}
- // Future optimization: We could return null if the delegate has out or ref parameters
+ // Future optimization: We could return default if the delegate has out or ref parameters
// and the anonymous function is an implicitly typed lambda. It will not be applicable.
// We have an entirely fixed delegate parameter list, which is of the same arity as
@@ -2781,7 +2781,7 @@ private static NamedTypeSymbol GetInterfaceInferenceBound(ImmutableArray GetInferredTypeArguments()
var builder = ArrayBuilder.GetInstance();
foreach (var fixedResult in _fixedResults)
{
- builder.Add(fixedResult?.TypeSymbol);
+ builder.Add(fixedResult.TypeSymbol);
}
return builder.ToImmutableAndFree();
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs
index 33a49a3bbd399..6bce354372692 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs
@@ -386,6 +386,7 @@ private bool FailsConstraintChecks(MethodSymbol method, out ArrayBuilder
/// True if the conversion is an explicit conversion.
///
- internal bool IsExplicitConversion => (object)ExplicitType != null;
+ internal bool IsExplicitConversion => !ExplicitType.IsNull;
///
/// The conversion (from Conversions.ClassifyConversionFromExpression for
@@ -43,7 +43,7 @@ internal ConversionGroup(Conversion conversion, TypeSymbolWithAnnotations explic
internal string GetDebuggerDisplay()
{
var str = $"#{_id} {Conversion}";
- if ((object)ExplicitType != null)
+ if (!ExplicitType.IsNull)
{
str += $" ({ExplicitType})";
}
diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs
index 832fe6897d8ed..abbab2997dd6f 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs
@@ -98,7 +98,7 @@ public TypeSymbolWithAnnotations GetInferredReturnType(ref HashSet
/// Indicates the type of return statement with no expression. Used in InferReturnType.
///
- internal static readonly TypeSymbolWithAnnotations NoReturnExpression = TypeSymbolWithAnnotations.Create(new UnsupportedMetadataTypeSymbol());
+ internal static readonly TypeSymbol NoReturnExpression = new UnsupportedMetadataTypeSymbol();
///
/// Behavior of this function should be kept aligned with .
@@ -126,7 +126,7 @@ internal static InferredLambdaReturnType InferReturnType(ArrayBuilder<(RefKind,
{
refKind = rk;
}
- if ((object)type == NoReturnExpression)
+ if ((object)type.TypeSymbol == NoReturnExpression)
{
hasReturnWithoutArgument = true;
}
@@ -152,7 +152,7 @@ private static TypeSymbolWithAnnotations CalculateReturnType(
TypeSymbolWithAnnotations bestResultType;
if (resultTypes.IsDefaultOrEmpty)
{
- bestResultType = null;
+ bestResultType = default;
}
else if (resultTypes.Length == 1)
{
@@ -196,11 +196,11 @@ private static TypeSymbolWithAnnotations CalculateReturnType(
return TypeSymbolWithAnnotations.Create(resultType);
}
- if ((object)bestResultType == null || bestResultType.SpecialType == SpecialType.System_Void)
+ if (bestResultType.IsNull || bestResultType.SpecialType == SpecialType.System_Void)
{
// If the best type was 'void', ERR_CantReturnVoid is reported while binding the "return void"
// statement(s).
- return null;
+ return default;
}
// Some non-void best type T was found; use delegate InvokeMethod
@@ -251,7 +251,7 @@ public override BoundNode VisitReturnStatement(BoundReturnStatement node)
{
var expression = node.ExpressionOpt;
var type = (expression is null) ?
- NoReturnExpression :
+ TypeSymbolWithAnnotations.CreateUnannotated(NonNullTypesUnusedContext.Instance, NoReturnExpression) :
TypeSymbolWithAnnotations.Create(expression.Type?.SetUnknownNullabilityForReferenceTypes());
_builder.Add((node.RefKind, type));
return null;
@@ -378,7 +378,7 @@ internal IEnumerable InferredReturnTypes()
foreach (var lambda in _returnInferenceCache.Values)
{
var type = lambda.InferredReturnType.Type;
- if ((object)type != null)
+ if (!type.IsNull)
{
any = true;
yield return type.TypeSymbol;
@@ -388,7 +388,7 @@ internal IEnumerable InferredReturnTypes()
if (!any)
{
var type = BindForErrorRecovery().InferredReturnType.Type;
- if ((object)type != null)
+ if (!type.IsNull)
{
yield return type.TypeSymbol;
}
@@ -405,7 +405,7 @@ private TypeSymbolWithAnnotations DelegateReturnType(MethodSymbol invokeMethod,
if ((object)invokeMethod == null)
{
refKind = CodeAnalysis.RefKind.None;
- return null;
+ return default;
}
refKind = invokeMethod.RefKind;
return invokeMethod.ReturnType;
@@ -448,7 +448,7 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType)
{
lambdaSymbol = returnInferenceLambda.Symbol;
var lambdaReturnType = lambdaSymbol.ReturnType;
- if ((object)LambdaSymbol.InferenceFailureReturnType != lambdaReturnType &&
+ if ((object)LambdaSymbol.InferenceFailureReturnType != lambdaReturnType.TypeSymbol &&
lambdaReturnType.Equals(returnType, TypeCompareKind.CompareNullableModifiersForReferenceTypes) && lambdaSymbol.RefKind == refKind)
{
lambdaBodyBinder = returnInferenceLambda.Binder;
@@ -478,10 +478,10 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType)
var lambdaParameters = lambdaSymbol.Parameters;
ParameterHelpers.EnsureIsReadOnlyAttributeExists(lambdaParameters, diagnostics, modifyCompilation: false);
- if ((object)returnType != null)
+ if (!returnType.IsNull)
{
returnType.ReportAnnotatedUnconstrainedTypeParameterIfAny(lambdaSymbol.DiagnosticLocation, diagnostics);
- if (returnType.ContainsNullableReferenceTypes() == true)
+ if (returnType.ContainsNullableReferenceTypes())
{
binder.Compilation.EnsureNullableAttributeExists(diagnostics, lambdaSymbol.DiagnosticLocation, modifyCompilation: false);
}
@@ -513,7 +513,7 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType)
if (IsAsync && !ErrorFacts.PreventsSuccessfulDelegateConversion(diagnostics))
{
- if ((object)returnType != null && // Can be null if "delegateType" is not actually a delegate type.
+ if (!returnType.IsNull && // Can be null if "delegateType" is not actually a delegate type.
returnType.SpecialType != SpecialType.System_Void &&
!returnType.TypeSymbol.IsNonGenericTaskType(binder.Compilation) &&
!returnType.TypeSymbol.IsGenericTaskType(binder.Compilation))
@@ -570,7 +570,7 @@ private BoundLambda ReallyInferReturnType(NamedTypeSymbol delegateType, Immutabl
parameterTypes,
parameterRefKinds,
refKind: CodeAnalysis.RefKind.None,
- returnType: null,
+ returnType: default,
diagnostics: diagnostics);
Binder lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder));
var block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics);
@@ -582,7 +582,11 @@ private BoundLambda ReallyInferReturnType(NamedTypeSymbol delegateType, Immutabl
{ WasCompilerGenerated = _unboundLambda.WasCompilerGenerated };
// TODO: Should InferredReturnType.UseSiteDiagnostics be merged into BoundLambda.Diagnostics?
- var returnType = inferredReturnType.Type ?? LambdaSymbol.InferenceFailureReturnType;
+ var returnType = inferredReturnType.Type;
+ if (returnType.IsNull)
+ {
+ returnType = TypeSymbolWithAnnotations.CreateUnannotated(NonNullTypesFalseContext.Instance, LambdaSymbol.InferenceFailureReturnType);
+ }
lambdaSymbol.SetInferredReturnType(inferredReturnType.RefKind, returnType);
return result;
@@ -788,7 +792,7 @@ private static string GetLambdaSortString(LambdaSymbol lambda)
builder.Builder.Append(parameter.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat));
}
- if ((object)lambda.ReturnType != null)
+ if (!lambda.ReturnType.IsNull)
{
builder.Builder.Append(lambda.ReturnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
}
diff --git a/src/Compilers/CSharp/Portable/BoundTree/VariablePendingInference.cs b/src/Compilers/CSharp/Portable/BoundTree/VariablePendingInference.cs
index 12526860d9e3d..138bab24a71af 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/VariablePendingInference.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/VariablePendingInference.cs
@@ -22,19 +22,19 @@ internal partial class VariablePendingInference : BoundExpression
{
internal BoundExpression SetInferredType(TypeSymbolWithAnnotations type, DiagnosticBag diagnosticsOpt)
{
- Debug.Assert((object)type != null);
+ Debug.Assert(!type.IsNull);
return SetInferredType(type, null, diagnosticsOpt);
}
internal BoundExpression SetInferredType(TypeSymbolWithAnnotations type, Binder binderOpt, DiagnosticBag diagnosticsOpt)
{
- Debug.Assert(binderOpt != null || (object)type != null);
+ Debug.Assert(binderOpt != null || !type.IsNull);
Debug.Assert(this.Syntax.Kind() == SyntaxKind.SingleVariableDesignation ||
(this.Syntax.Kind() == SyntaxKind.DeclarationExpression &&
((DeclarationExpressionSyntax)this.Syntax).Designation.Kind() == SyntaxKind.SingleVariableDesignation));
- bool inferenceFailed = ((object)type == null);
+ bool inferenceFailed = type.IsNull;
if (inferenceFailed)
{
@@ -93,7 +93,7 @@ internal BoundExpression SetInferredType(TypeSymbolWithAnnotations type, Binder
internal BoundExpression FailInference(Binder binder, DiagnosticBag diagnosticsOpt)
{
- return this.SetInferredType(null, binder, diagnosticsOpt);
+ return this.SetInferredType(default, binder, diagnosticsOpt);
}
private void ReportInferenceFailure(DiagnosticBag diagnostics)
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
index 838d9c8052682..0d0a6e729e493 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
+++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
@@ -14621,6 +14621,24 @@ internal static string WRN_NullabilityMismatchInTypeOnOverride_Title {
}
}
+ ///
+ /// Looks up a localized string similar to The type '{3}' cannot be used as type parameter '{2}' in the generic type or method '{0}'. Nullability of type argument '{3}' doesn't match constraint type '{1}'..
+ ///
+ internal static string WRN_NullabilityMismatchInTypeParameterConstraint {
+ get {
+ return ResourceManager.GetString("WRN_NullabilityMismatchInTypeParameterConstraint", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match constraint type..
+ ///
+ internal static string WRN_NullabilityMismatchInTypeParameterConstraint_Title {
+ get {
+ return ResourceManager.GetString("WRN_NullabilityMismatchInTypeParameterConstraint_Title", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Cannot convert null literal to non-nullable reference or unconstrained type parameter..
///
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index f2e35f9bc0a48..18f98fab1e667 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -5363,6 +5363,12 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
Cannot use a nullable reference type in object creation.
+
+ The type '{3}' cannot be used as type parameter '{2}' in the generic type or method '{0}'. Nullability of type argument '{3}' doesn't match constraint type '{1}'.
+
+
+ The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match constraint type.
+
Explicit application of 'System.Runtime.CompilerServices.NullableAttribute' is not allowed.
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
index f73e226bf75ae..da2b6239e124e 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
@@ -1615,6 +1615,7 @@ internal enum ErrorCode
ERR_AnnotationDisallowedInObjectCreation = 8628,
WRN_MissingNonNullTypesContext = 8629,
ERR_NonNullTypesNotAvailable = 8630,
+ WRN_NullabilityMismatchInTypeParameterConstraint = 8631,
}
// Note: you will need to re-generate compiler code after adding warnings (build\scripts\generate-compiler-code.cmd)
}
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
index ac771c16e8d51..412e076a3a835 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
@@ -342,6 +342,7 @@ internal static int GetWarningLevel(ErrorCode code)
case ErrorCode.WRN_NullabilityMismatchInParameterTypeOfTargetDelegate:
case ErrorCode.WRN_NullAsNonNullable:
case ErrorCode.WRN_NoBestNullabilityConditionalExpression:
+ case ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint:
case ErrorCode.WRN_Experimental:
case ErrorCode.WRN_AttributesOnBackingFieldsNotAvailable:
case ErrorCode.WRN_TupleBinopLiteralNameMismatch:
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs
index 22a03f329c249..57789b3dcc3a5 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.LocalFunctions.cs
@@ -222,7 +222,7 @@ private void RecordReadInLocalFunction(int slot)
// fields we need to record each field assignment separately,
// since some fields may be assigned when this read is replayed
VariableIdentifier id = variableBySlot[slot];
- var type = VariableType(id.Symbol)?.TypeSymbol;
+ var type = VariableType(id.Symbol).TypeSymbol;
Debug.Assert(!_emptyStructTypeCache.IsEmptyStructType(type));
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs
index 0ef92c741d5b1..4e24163f81b73 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs
@@ -883,7 +883,7 @@ protected virtual void ReportUnassigned(Symbol symbol, SyntaxNode node, int slot
// We've already reported the use of a local before its declaration. No need to emit
// another diagnostic for the same issue.
}
- else if (!_alreadyReported[slot] && VariableType(symbol)?.IsErrorType() != true)
+ else if (!_alreadyReported[slot] && !VariableType(symbol).IsErrorType())
{
// CONSIDER: could suppress this diagnostic in cases where the local was declared in a using
// or fixed statement because there's a special error code for not initializing those.
@@ -1197,7 +1197,7 @@ private bool FieldsAllSet(int containingSlot, LocalState state)
Debug.Assert(containingSlot != -1);
Debug.Assert(!state.IsAssigned(containingSlot));
VariableIdentifier variable = variableBySlot[containingSlot];
- NamedTypeSymbol structType = (NamedTypeSymbol)VariableType(variable.Symbol)?.TypeSymbol;
+ NamedTypeSymbol structType = (NamedTypeSymbol)VariableType(variable.Symbol).TypeSymbol;
foreach (var field in _emptyStructTypeCache.GetStructInstanceFields(structType))
{
if (_emptyStructTypeCache.IsEmptyStructType(field.Type.TypeSymbol)) continue;
@@ -1225,7 +1225,7 @@ private void SetSlotAssigned(int slot, ref LocalState state)
{
if (slot < 0) return;
VariableIdentifier id = variableBySlot[slot];
- TypeSymbol type = VariableType(id.Symbol)?.TypeSymbol;
+ TypeSymbol type = VariableType(id.Symbol).TypeSymbol;
Debug.Assert(!_emptyStructTypeCache.IsEmptyStructType(type));
if (slot >= state.Assigned.Capacity) Normalize(ref state);
if (state.IsAssigned(slot)) return; // was already fully assigned.
@@ -1261,7 +1261,7 @@ private void SetSlotUnassigned(int slot, ref LocalState state)
{
if (slot < 0) return;
VariableIdentifier id = variableBySlot[slot];
- TypeSymbol type = VariableType(id.Symbol)?.TypeSymbol;
+ TypeSymbol type = VariableType(id.Symbol).TypeSymbol;
Debug.Assert(!_emptyStructTypeCache.IsEmptyStructType(type));
if (!state.IsAssigned(slot)) return; // was already unassigned
state.Unassign(slot);
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPassBase.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPassBase.cs
index c1e543565ef3d..0950ea6f48431 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPassBase.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPassBase.cs
@@ -101,7 +101,7 @@ protected int GetOrCreateSlot(Symbol symbol, int containingSlot = 0)
// Since analysis may proceed in multiple passes, it is possible the slot is already assigned.
if (!_variableSlot.TryGetValue(identifier, out slot))
{
- var variableType = VariableType(symbol)?.TypeSymbol;
+ var variableType = VariableType(symbol).TypeSymbol;
if (_emptyStructTypeCache.IsEmptyStructType(variableType))
{
return -1;
@@ -239,7 +239,7 @@ protected static TypeSymbolWithAnnotations VariableType(Symbol s)
return ((ParameterSymbol)s).Type;
case SymbolKind.Method:
Debug.Assert(((MethodSymbol)s).MethodKind == MethodKind.LocalFunction);
- return null;
+ return default;
case SymbolKind.Property:
return ((PropertySymbol)s).Type;
case SymbolKind.Event:
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
index 02feb43411a60..10b53aef0ef35 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
@@ -141,7 +141,7 @@ private NullableWalker(
// If so, are we interested in an InMethodBinder specifically?
_binder = compilation.GetBinderFactory(node.SyntaxTree).GetBinder(node.Syntax);
Debug.Assert(!_binder.Conversions.IncludeNullability);
- _conversions = _binder.Conversions.WithNullability(true);
+ _conversions = (Conversions)_binder.Conversions.WithNullability(true);
_useMethodSignatureReturnType = (object)methodSignatureOpt != null && useMethodSignatureReturnType;
_useMethodSignatureParameterTypes = (object)methodSignatureOpt != null && useMethodSignatureParameterTypes;
_methodSignatureOpt = methodSignatureOpt;
@@ -319,20 +319,22 @@ private void Populate(ref LocalState state, int start)
}
// PROTOTYPE(NullableReferenceTypes): Consider setting treatUnconstrainedTypeParameterAsNullable during initial binding, and removing this method.
- private static TypeSymbolWithAnnotations GetAdjustedType(TypeSymbolWithAnnotations initialType)
+ private static TypeSymbolWithAnnotations GetAdjustedType(TypeSymbolWithAnnotations? initialType)
{
// If the initial type was an unconstrained type parameter, we want to treat it as nullable, overriding
// the annotated state.
- if (initialType is null)
+ if (initialType is null || initialType.Value.IsNull)
{
- return null;
+ return default;
}
- return initialType.TypeSymbol.IsUnconstrainedTypeParameter() &&
- initialType.NonNullTypesContext.NonNullTypes == true &&
- initialType.IsNullable != true ?
- initialType.AsNullableReferenceType() :
- initialType;
+ TypeSymbolWithAnnotations initialTypeNonNull = initialType.Value;
+
+ return initialTypeNonNull.TypeSymbol.IsUnconstrainedTypeParameter() &&
+ initialTypeNonNull.NonNullTypesContext.NonNullTypes == true &&
+ initialTypeNonNull.IsNullable != true ?
+ initialTypeNonNull.AsNullableReferenceType() :
+ initialTypeNonNull;
}
protected override bool TryGetReceiverAndMember(BoundExpression expr, out BoundExpression receiver, out Symbol member)
@@ -505,7 +507,7 @@ private bool ReportNullReferenceAssignmentIfNecessary(BoundExpression value, Typ
Debug.Assert(value != null);
Debug.Assert(!IsConditionalState);
- if (targetType is null || valueType is null)
+ if (targetType.IsNull || valueType.IsNull)
{
return false;
}
@@ -533,7 +535,7 @@ private void ReportAssignmentWarnings(BoundExpression value, TypeSymbolWithAnnot
if (this.State.Reachable)
{
- if (targetType is null || valueType is null)
+ if (targetType.IsNull || valueType.IsNull)
{
return;
}
@@ -553,7 +555,7 @@ private void TrackNullableStateForAssignment(BoundExpression value, TypeSymbolWi
if (this.State.Reachable)
{
- if ((object)targetType == null)
+ if (targetType.IsNull)
{
return;
}
@@ -570,7 +572,7 @@ private void TrackNullableStateForAssignment(BoundExpression value, TypeSymbolWi
// Since reference can point to the heap, we cannot assume the value is not null after this assignment,
// regardless of what value is being assigned.
(targetType.IsNullable == true) ? (bool?)false : null :
- !valueType?.IsNullable;
+ !valueType.IsNullable;
// PROTOTYPE(NullableReferenceTypes): Might this clear state that
// should be copied in InheritNullableStateOfTrackableType?
@@ -588,7 +590,7 @@ private void TrackNullableStateForAssignment(BoundExpression value, TypeSymbolWi
// }
// For now, we copy a limited set of BoundNode types that shouldn't contain cycles.
if ((value.Kind == BoundKind.ObjectCreationExpression || value.Kind == BoundKind.AnonymousObjectCreationExpression || value.Kind == BoundKind.DynamicObjectCreationExpression || targetType.TypeSymbol.IsAnonymousType) &&
- targetType.TypeSymbol.Equals(valueType?.TypeSymbol, TypeCompareKind.ConsiderEverything)) // PROTOTYPE(NullableReferenceTypes): Allow assignment to base type.
+ targetType.TypeSymbol.Equals(valueType.TypeSymbol, TypeCompareKind.ConsiderEverything)) // PROTOTYPE(NullableReferenceTypes): Allow assignment to base type.
{
if (valueSlot > 0)
{
@@ -597,7 +599,7 @@ private void TrackNullableStateForAssignment(BoundExpression value, TypeSymbolWi
}
}
else if (EmptyStructTypeCache.IsTrackableStructType(targetType.TypeSymbol) &&
- targetType.TypeSymbol.Equals(valueType?.TypeSymbol, TypeCompareKind.ConsiderEverything))
+ targetType.TypeSymbol.Equals(valueType.TypeSymbol, TypeCompareKind.ConsiderEverything))
{
InheritNullableStateOfTrackableStruct(targetType.TypeSymbol, targetSlot, valueSlot, IsByRefTarget(targetSlot), slotWatermark: GetSlotWatermark());
}
@@ -864,7 +866,7 @@ private void VisitPattern(BoundExpression expression, TypeSymbolWithAnnotations
// PROTOTYPE(NullableReferenceTypes): We should only report such
// diagnostics for locals that are set or checked explicitly within this method.
- if (expressionResultType?.IsNullable == false && isNull == true)
+ if (!expressionResultType.IsNull && expressionResultType.IsNullable == false && isNull == true)
{
ReportStaticNullCheckingDiagnostics(ErrorCode.HDN_NullCheckIsProbablyAlwaysFalse, pattern.Syntax);
}
@@ -908,7 +910,7 @@ protected override BoundNode VisitReturnStatementNoAdjust(BoundReturnStatement n
TypeSymbolWithAnnotations resultType = ApplyConversion(expr, expr, conversion, returnType.TypeSymbol, result, checkConversion: true, fromExplicitCast: false, out bool canConvertNestedNullability);
if (!canConvertNestedNullability)
{
- ReportStaticNullCheckingDiagnostics(ErrorCode.WRN_NullabilityMismatchInAssignment, expr.Syntax, GetTypeAsDiagnosticArgument(result?.TypeSymbol), returnType.TypeSymbol);
+ ReportStaticNullCheckingDiagnostics(ErrorCode.WRN_NullabilityMismatchInAssignment, expr.Syntax, GetTypeAsDiagnosticArgument(result.TypeSymbol), returnType.TypeSymbol);
}
bool returnTypeIsNonNullable = IsNonNullable(returnType);
@@ -935,12 +937,12 @@ private TypeSymbolWithAnnotations GetReturnType()
private static bool IsNullable(TypeSymbolWithAnnotations typeOpt)
{
- return typeOpt?.IsNullable == true;
+ return !typeOpt.IsNull && typeOpt.IsNullable == true;
}
private static bool IsNonNullable(TypeSymbolWithAnnotations typeOpt)
{
- return typeOpt?.IsNullable == false && typeOpt.IsReferenceType;
+ return !typeOpt.IsNull && typeOpt.IsNullable == false && typeOpt.IsReferenceType;
}
private static bool IsUnconstrainedTypeParameter(TypeSymbol typeOpt)
@@ -989,7 +991,7 @@ public override BoundNode VisitLocalDeclaration(BoundLocalDeclaration node)
if (node.DeclaredType.InferredType)
{
Debug.Assert(conversion.IsIdentity);
- if (valueType is null)
+ if (valueType.IsNull)
{
Debug.Assert(type.IsErrorType());
valueType = type;
@@ -1005,7 +1007,7 @@ public override BoundNode VisitLocalDeclaration(BoundLocalDeclaration node)
ReportNullReferenceAssignmentIfNecessary(initializer, type, valueType, useLegacyWarnings: true);
if (!canConvertNestedNullability)
{
- ReportStaticNullCheckingDiagnostics(ErrorCode.WRN_NullabilityMismatchInAssignment, initializer.Syntax, GetTypeAsDiagnosticArgument(unconvertedType?.TypeSymbol), type.TypeSymbol);
+ ReportStaticNullCheckingDiagnostics(ErrorCode.WRN_NullabilityMismatchInAssignment, initializer.Syntax, GetTypeAsDiagnosticArgument(unconvertedType.TypeSymbol), type.TypeSymbol);
}
}
@@ -1021,8 +1023,8 @@ protected override BoundExpression VisitExpressionWithoutStackGuard(BoundExpress
#if DEBUG
// Verify Visit method set _result.
TypeSymbolWithAnnotations resultType = _resultType;
- Debug.Assert((object)resultType != _invalidType);
- Debug.Assert(AreCloseEnough(resultType?.TypeSymbol, node.Type));
+ Debug.Assert((object)resultType.TypeSymbol != _invalidType.TypeSymbol);
+ Debug.Assert(AreCloseEnough(resultType.TypeSymbol, node.Type));
#endif
if (_callbackOpt != null)
{
@@ -1291,19 +1293,22 @@ private ArrayTypeSymbol VisitArrayInitializer(BoundArrayCreation node)
// Should do the same here.
HashSet useSiteDiagnostics = null;
// If there are error types, use the first error type. (Matches InferBestType(ImmutableArray, ...).)
- var bestType = resultTypes.FirstOrDefault(t => t?.IsErrorType() == true) ??
- BestTypeInferrer.InferBestType(resultTypes, _conversions, useSiteDiagnostics: ref useSiteDiagnostics);
+ var bestType = resultTypes.FirstOrDefault(t => !t.IsNull && t.IsErrorType());
+ if (bestType.IsNull)
+ {
+ bestType = BestTypeInferrer.InferBestType(resultTypes, _conversions, useSiteDiagnostics: ref useSiteDiagnostics);
+ }
// PROTOTYPE(NullableReferenceTypes): Report a special ErrorCode.WRN_NoBestNullabilityArrayElements
// when InferBestType fails, and avoid reporting conversion warnings for each element in those cases.
// (See similar code for conditional expressions: ErrorCode.WRN_NoBestNullabilityConditionalExpression.)
- if ((object)bestType != null)
+ if (!bestType.IsNull)
{
elementType = bestType;
}
arrayType = arrayType.WithElementType(elementType);
}
- if ((object)elementType != null)
+ if (!elementType.IsNull)
{
bool elementTypeIsReferenceType = elementType.IsReferenceType == true;
for (int i = 0; i < n; i++)
@@ -1311,7 +1316,7 @@ private ArrayTypeSymbol VisitArrayInitializer(BoundArrayCreation node)
var conversion = conversionBuilder[i];
var element = elementBuilder[i];
var resultType = resultBuilder[i];
- var sourceType = resultType?.TypeSymbol;
+ var sourceType = resultType.TypeSymbol;
if (elementTypeIsReferenceType)
{
resultType = ApplyConversion(element, element, conversion, elementType.TypeSymbol, resultType, checkConversion: true, fromExplicitCast: false, out bool canConvertNestedNullability);
@@ -1356,14 +1361,14 @@ public override BoundNode VisitArrayAccess(BoundArrayAccess node)
Debug.Assert(!node.Expression.Type.IsValueType);
CheckPossibleNullReceiver(node.Expression, checkType: false);
- var type = _resultType?.TypeSymbol as ArrayTypeSymbol;
+ var type = _resultType.TypeSymbol as ArrayTypeSymbol;
foreach (var i in node.Indices)
{
VisitRvalue(i);
}
- _resultType = type?.ElementType;
+ _resultType = type?.ElementType ?? default;
return null;
}
@@ -1394,8 +1399,8 @@ private TypeSymbolWithAnnotations InferResultNullability(BinaryOperatorKind oper
{
case BinaryOperatorKind.DelegateCombination:
{
- bool? leftIsNullable = leftType?.IsNullable;
- bool? rightIsNullable = rightType?.IsNullable;
+ bool? leftIsNullable = leftType.IsNullable;
+ bool? rightIsNullable = rightType.IsNullable;
if (leftIsNullable == false || rightIsNullable == false)
{
isNullable = false;
@@ -1453,7 +1458,7 @@ protected override void AfterLeftChildHasBeenVisited(BoundBinaryOperator binary)
if (op == BinaryOperatorKind.Equal || op == BinaryOperatorKind.NotEqual)
{
BoundExpression operandComparedToNull = null;
- TypeSymbolWithAnnotations operandComparedToNullType = null;
+ TypeSymbolWithAnnotations operandComparedToNullType = default;
if (binary.Right.ConstantValue?.IsNull == true)
{
@@ -1471,7 +1476,7 @@ protected override void AfterLeftChildHasBeenVisited(BoundBinaryOperator binary)
// PROTOTYPE(NullableReferenceTypes): This check is incorrect since it compares declared
// nullability rather than tracked nullability. Moreover, we should only report such
// diagnostics for locals that are set or checked explicitly within this method.
- if (operandComparedToNullType?.IsNullable == false)
+ if (!operandComparedToNullType.IsNull && operandComparedToNullType.IsNullable == false)
{
ReportStaticNullCheckingDiagnostics(op == BinaryOperatorKind.Equal ?
ErrorCode.HDN_NullCheckIsProbablyAlwaysFalse :
@@ -1628,7 +1633,7 @@ public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperato
}
var leftState = this.State.Clone();
- if (leftResult?.IsNullable == false)
+ if (leftResult.IsNullable == false)
{
ReportStaticNullCheckingDiagnostics(ErrorCode.HDN_ExpressionIsProbablyNeverNull, leftOperand.Syntax);
}
@@ -1644,8 +1649,8 @@ public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperato
rightResult = VisitRvalueWithResult(rightOperand);
IntersectWith(ref this.State, ref leftState);
TypeSymbol resultType;
- var leftResultType = leftResult?.TypeSymbol;
- var rightResultType = rightResult?.TypeSymbol;
+ var leftResultType = leftResult.TypeSymbol;
+ var rightResultType = rightResult.TypeSymbol;
switch (node.OperatorResultKind)
{
case BoundNullCoalescingOperatorResultKind.NoCommonType:
@@ -1674,7 +1679,7 @@ public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperato
_resultType = TypeSymbolWithAnnotations.Create(resultType, resultIsNullable);
return null;
- bool? getIsNullable(BoundExpression e, TypeSymbolWithAnnotations t) => (t is null) ? e.IsNullable() : t.IsNullable;
+ bool? getIsNullable(BoundExpression e, TypeSymbolWithAnnotations t) => t.IsNull ? e.IsNullable() : t.IsNullable;
TypeSymbol getLeftResultType(TypeSymbol leftType, TypeSymbol rightType)
{
// If there was an identity conversion between the two operands (in short, if there
@@ -1708,7 +1713,7 @@ public override BoundNode VisitConditionalAccess(BoundConditionalAccess node)
if (receiver.Type != null && !receiver.Type.IsValueType)
{
- if (receiverType?.IsNullable == false)
+ if (receiverType.IsNullable == false)
{
ReportStaticNullCheckingDiagnostics(ErrorCode.HDN_ExpressionIsProbablyNeverNull, receiver.Syntax);
}
@@ -1731,7 +1736,7 @@ public override BoundNode VisitConditionalAccess(BoundConditionalAccess node)
// PROTOTYPE(NullableReferenceTypes): Use flow analysis type rather than node.Type
// so that nested nullability is inferred from flow analysis. See VisitConditionalOperator.
- _resultType = TypeSymbolWithAnnotations.Create(node.Type, isNullableIfReferenceType: receiverType?.IsNullable | _resultType?.IsNullable);
+ _resultType = TypeSymbolWithAnnotations.Create(node.Type, isNullableIfReferenceType: receiverType.IsNullable | _resultType.IsNullable);
// PROTOTYPE(NullableReferenceTypes): Report conversion warnings.
return null;
}
@@ -1775,7 +1780,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
TypeSymbolWithAnnotations resultType;
if (node.HasErrors)
{
- resultType = null;
+ resultType = default;
}
else
{
@@ -1794,23 +1799,23 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
_conversions,
out _,
ref useSiteDiagnostics);
- if (resultType is null)
+ if (resultType.IsNull)
{
ReportStaticNullCheckingDiagnostics(
ErrorCode.WRN_NoBestNullabilityConditionalExpression,
node.Syntax,
- GetTypeAsDiagnosticArgument(consequenceResult?.TypeSymbol),
- GetTypeAsDiagnosticArgument(alternativeResult?.TypeSymbol));
+ GetTypeAsDiagnosticArgument(consequenceResult.TypeSymbol),
+ GetTypeAsDiagnosticArgument(alternativeResult.TypeSymbol));
}
}
- resultType = TypeSymbolWithAnnotations.Create(resultType?.TypeSymbol ?? node.Type.SetUnknownNullabilityForReferenceTypes(), isNullableIfReferenceType);
+ resultType = TypeSymbolWithAnnotations.Create(resultType.TypeSymbol ?? node.Type.SetUnknownNullabilityForReferenceTypes(), isNullableIfReferenceType);
_resultType = resultType;
return null;
bool? getIsNullableIfReferenceType(BoundExpression expr, TypeSymbolWithAnnotations type)
{
- if ((object)type != null)
+ if (!type.IsNull)
{
return type.IsNullable;
}
@@ -1823,7 +1828,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
BoundExpression createPlaceholderIfNecessary(BoundExpression expr, TypeSymbolWithAnnotations type)
{
- return type is null ?
+ return type.IsNull ?
expr :
new BoundValuePlaceholder(expr.Syntax, type.IsNullable, type.TypeSymbol);
}
@@ -2053,10 +2058,18 @@ private MethodSymbol VisitArguments(
// We do a first pass to work through the arguments without making any assumptions
ImmutableArray results = VisitArgumentsEvaluate(arguments, refKindsOpt);
- if ((object)method != null && method.IsGenericMethod && HasImplicitTypeArguments(node))
+ if ((object)method != null && method.IsGenericMethod)
{
- method = InferMethodTypeArguments((BoundCall)node, method, GetArgumentsForMethodTypeInference(arguments, results));
- parameters = method.Parameters;
+ if (HasImplicitTypeArguments(node))
+ {
+ method = InferMethodTypeArguments((BoundCall)node, method, GetArgumentsForMethodTypeInference(arguments, results));
+ parameters = method.Parameters;
+ }
+ if (!method.IsDefinition)
+ {
+ var syntax = node.Syntax;
+ CheckMethodConstraints((syntax as InvocationExpressionSyntax)?.Expression ?? syntax, method);
+ }
}
// PROTOTYPE(NullableReferenceTypes): Can we handle some error cases?
@@ -2277,7 +2290,7 @@ private void VisitArgumentConversion(
TypeSymbolWithAnnotations parameterType,
TypeSymbolWithAnnotations resultType)
{
- var argumentType = resultType?.TypeSymbol;
+ var argumentType = resultType.TypeSymbol;
switch (refKind)
{
case RefKind.None:
@@ -2404,7 +2417,7 @@ private static (ParameterSymbol Parameter, TypeSymbolWithAnnotations Type) GetCo
{
if (parameters.IsDefault)
{
- return (null, null);
+ return (default, default);
}
int n = parameters.Length;
@@ -2443,7 +2456,7 @@ private static (ParameterSymbol Parameter, TypeSymbolWithAnnotations Type) GetCo
if (parameter is null)
{
Debug.Assert(!expanded);
- return (null, null);
+ return (default, default);
}
var type = parameter.Type;
@@ -2495,7 +2508,6 @@ private MethodSymbol InferMethodTypeArguments(BoundCall node, MethodSymbol metho
ref useSiteDiagnostics);
if (result.Success)
{
- // PROTOTYPE(NullableReferenceTypes): Check constraints
return definition.Construct(result.InferredTypeArguments);
}
return method;
@@ -2525,7 +2537,7 @@ BoundExpression getArgumentForMethodTypeInference(BoundExpression argument, Type
// to re-bind lambdas in MethodTypeInferrer.
return GetUnboundLambda((BoundLambda)argument, GetVariableState());
}
- if (argumentType is null)
+ if (argumentType.IsNull)
{
return argument;
}
@@ -2538,6 +2550,27 @@ BoundExpression getArgumentForMethodTypeInference(BoundExpression argument, Type
}
}
+ private void CheckMethodConstraints(SyntaxNode syntax, MethodSymbol method)
+ {
+ var diagnosticsBuilder = ArrayBuilder.GetInstance();
+ var warningsBuilder = ArrayBuilder.GetInstance();
+ ArrayBuilder useSiteDiagnosticsBuilder = null;
+ ConstraintsHelper.CheckMethodConstraints(
+ method,
+ _conversions,
+ compilation,
+ diagnosticsBuilder,
+ warningsBuilder,
+ ref useSiteDiagnosticsBuilder);
+ foreach (var pair in warningsBuilder)
+ {
+ Diagnostics.Add(pair.DiagnosticInfo, syntax.Location);
+ }
+ useSiteDiagnosticsBuilder?.Free();
+ warningsBuilder.Free();
+ diagnosticsBuilder.Free();
+ }
+
private void ReplayReadsAndWrites(LocalFunctionSymbol localFunc,
SyntaxNode syntax,
bool writes)
@@ -2658,7 +2691,7 @@ private TypeSymbolWithAnnotations GetAdjustedResult(TypeSymbolWithAnnotations ty
private Symbol AsMemberOfResultType(Symbol symbol)
{
- var containingType = _resultType?.TypeSymbol as NamedTypeSymbol;
+ var containingType = _resultType.TypeSymbol as NamedTypeSymbol;
if ((object)containingType == null || containingType.IsErrorType())
{
return symbol;
@@ -2745,19 +2778,19 @@ public override BoundNode VisitConversion(BoundConversion node)
Visit(operand);
TypeSymbolWithAnnotations operandType = _resultType;
TypeSymbolWithAnnotations explicitType = GetAdjustedType(node.ConversionGroupOpt?.ExplicitType);
- bool fromExplicitCast = (object)explicitType != null;
- TypeSymbolWithAnnotations resultType = ApplyConversion(node, operand, conversion, explicitType?.TypeSymbol ?? node.Type, operandType, checkConversion: !fromExplicitCast, fromExplicitCast: fromExplicitCast, out bool _);
+ bool fromExplicitCast = !explicitType.IsNull;
+ TypeSymbolWithAnnotations resultType = ApplyConversion(node, operand, conversion, explicitType.TypeSymbol ?? node.Type, operandType, checkConversion: !fromExplicitCast, fromExplicitCast: fromExplicitCast, out bool _);
if (fromExplicitCast && explicitType.IsNullable == false)
{
TypeSymbol targetType = explicitType.TypeSymbol;
bool reportNullable = false;
- if (targetType.IsReferenceType && IsUnconstrainedTypeParameter(resultType?.TypeSymbol))
+ if (targetType.IsReferenceType && IsUnconstrainedTypeParameter(resultType.TypeSymbol))
{
reportNullable = true;
}
else if ((targetType.IsReferenceType || IsUnconstrainedTypeParameter(targetType)) &&
- resultType?.IsNullable == true)
+ resultType.IsNullable == true)
{
reportNullable = true;
}
@@ -2789,7 +2822,7 @@ private void VisitTupleExpression(BoundTupleExpression node)
ImmutableArray elementTypes = arguments.SelectAsArray((a, w) => w.VisitRvalueWithResult(a), this);
var tupleOpt = (TupleTypeSymbol)node.Type;
_resultType = (tupleOpt is null) ?
- null :
+ default :
TypeSymbolWithAnnotations.Create(tupleOpt.WithElementTypes(elementTypes));
}
@@ -2918,7 +2951,7 @@ private TypeSymbolWithAnnotations ApplyConversion(
out bool canConvertNestedNullability)
{
Debug.Assert(node != null);
- Debug.Assert(operandOpt != null || (object)operandType != null);
+ Debug.Assert(operandOpt != null || !operandType.IsNull);
Debug.Assert((object)targetType != null);
bool? isNullableIfReferenceType = null;
@@ -3005,7 +3038,7 @@ private TypeSymbolWithAnnotations ApplyConversion(
case ConversionKind.ExplicitDynamic:
case ConversionKind.ImplicitDynamic:
- isNullableIfReferenceType = operandType?.IsNullable;
+ isNullableIfReferenceType = operandType.IsNull ? null : operandType.IsNullable;
break;
case ConversionKind.Unboxing:
@@ -3013,19 +3046,20 @@ private TypeSymbolWithAnnotations ApplyConversion(
break;
case ConversionKind.Boxing:
- if (operandType?.IsValueType == true)
+ if (!operandType.IsNull && operandType.IsValueType)
{
// PROTOTYPE(NullableReferenceTypes): Should we worry about a pathological case of boxing nullable value known to be not null?
// For example, new int?(0)
isNullableIfReferenceType = operandType.IsNullableType();
}
- else if (IsUnconstrainedTypeParameter(operandType?.TypeSymbol))
+ else if (!operandType.IsNull && IsUnconstrainedTypeParameter(operandType.TypeSymbol))
{
isNullableIfReferenceType = operandType.IsNullable;
}
else
{
- Debug.Assert(operandType?.IsReferenceType != true ||
+ Debug.Assert(operandType.IsNull ||
+ !operandType.IsReferenceType ||
operandType.SpecialType == SpecialType.System_ValueType ||
operandType.TypeKind == TypeKind.Interface ||
operandType.TypeKind == TypeKind.Dynamic);
@@ -3040,7 +3074,7 @@ private TypeSymbolWithAnnotations ApplyConversion(
case ConversionKind.Identity:
case ConversionKind.ImplicitReference:
case ConversionKind.ExplicitReference:
- if (operandType is null && operandOpt.IsLiteralNullOrDefault())
+ if (operandType.IsNull && operandOpt.IsLiteralNullOrDefault())
{
isNullableIfReferenceType = true;
}
@@ -3055,10 +3089,10 @@ private TypeSymbolWithAnnotations ApplyConversion(
if (checkConversion)
{
// PROTOTYPE(NullableReferenceTypes): Assert conversion is similar to original.
- conversion = GenerateConversion(_conversions, operandOpt, operandType?.TypeSymbol, targetType, fromExplicitCast);
+ conversion = GenerateConversion(_conversions, operandOpt, operandType.TypeSymbol, targetType, fromExplicitCast);
canConvertNestedNullability = conversion.Exists;
}
- isNullableIfReferenceType = operandType?.IsNullable;
+ isNullableIfReferenceType = operandType.IsNull ? null : operandType.IsNullable;
}
break;
@@ -3119,7 +3153,7 @@ public override BoundNode VisitMethodGroup(BoundMethodGroup node)
//if (this.State.Reachable) // PROTOTYPE(NullableReferenceTypes): Consider reachability?
{
- _resultType = null;
+ _resultType = default;
}
return null;
@@ -3208,7 +3242,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
ReportNullReferenceAssignmentIfNecessary(right, leftType, rightType, UseLegacyWarnings(left));
if (!canConvertNestedNullability)
{
- ReportStaticNullCheckingDiagnostics(ErrorCode.WRN_NullabilityMismatchInAssignment, right.Syntax, GetTypeAsDiagnosticArgument(rightResult?.TypeSymbol), leftType.TypeSymbol);
+ ReportStaticNullCheckingDiagnostics(ErrorCode.WRN_NullabilityMismatchInAssignment, right.Syntax, GetTypeAsDiagnosticArgument(rightResult.TypeSymbol), leftType.TypeSymbol);
}
TrackNullableStateForAssignment(right, leftType, MakeSlot(left), rightType, MakeSlot(right));
// PROTOTYPE(NullableReferenceTypes): Check node.Type.IsErrorType() instead?
@@ -3339,7 +3373,7 @@ public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmen
}
else
{
- leftOnRightType = null;
+ leftOnRightType = default;
}
VisitRvalue(node.Right);
@@ -3402,7 +3436,7 @@ public override BoundNode VisitAddressOfOperator(BoundAddressOfOperator node)
///
private bool ReportNullReferenceArgumentIfNecessary(BoundExpression argument, TypeSymbolWithAnnotations argumentType, ParameterSymbol parameter, TypeSymbolWithAnnotations paramType)
{
- if (argumentType?.IsNullable == true)
+ if (argumentType.IsNullable == true)
{
if (paramType.IsReferenceType && paramType.IsNullable == false)
{
@@ -3424,7 +3458,7 @@ private void ReportArgumentWarnings(BoundExpression argument, TypeSymbolWithAnno
ReportNullReferenceArgumentIfNecessary(argument, argumentType, parameter, paramType);
- if ((object)argumentType != null && IsNullabilityMismatch(paramType.TypeSymbol, argumentType.TypeSymbol))
+ if (!argumentType.IsNull && IsNullabilityMismatch(paramType.TypeSymbol, argumentType.TypeSymbol))
{
ReportNullabilityMismatchInArgument(argument, argumentType.TypeSymbol, parameter, paramType.TypeSymbol);
}
@@ -3537,9 +3571,9 @@ public override void VisitForEachIterationVariables(BoundForEachStatement node)
foreach (var iterationVariable in node.IterationVariables)
{
int slot = GetOrCreateSlot(iterationVariable);
- TypeSymbolWithAnnotations sourceType = node.EnumeratorInfoOpt?.ElementType;
+ TypeSymbolWithAnnotations sourceType = node.EnumeratorInfoOpt?.ElementType ?? default;
bool? isNullableIfReferenceType = null;
- if ((object)sourceType != null)
+ if (!sourceType.IsNull)
{
TypeSymbolWithAnnotations destinationType = iterationVariable.Type;
HashSet useSiteDiagnostics = null;
@@ -3593,7 +3627,7 @@ public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
Debug.Assert(!IsConditionalState);
var result = base.VisitUnaryOperator(node);
- TypeSymbolWithAnnotations resultType = null;
+ TypeSymbolWithAnnotations resultType = default;
// PROTOTYPE(NullableReferenceTypes): Update method based on inferred operand type.
if (node.OperatorKind.IsUserDefined())
@@ -3609,7 +3643,7 @@ public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
}
}
- _resultType = resultType ?? TypeSymbolWithAnnotations.Create(node.Type, isNullableIfReferenceType: null);
+ _resultType = resultType.IsNull ? TypeSymbolWithAnnotations.Create(node.Type, isNullableIfReferenceType: null) : resultType;
return null;
}
@@ -3662,7 +3696,7 @@ private TypeSymbolWithAnnotations InferResultNullability(BoundUserDefinedConditi
}
else
{
- return null;
+ return default;
}
}
@@ -3778,9 +3812,7 @@ public override BoundNode VisitFieldInfo(BoundFieldInfo node)
public override BoundNode VisitDefaultExpression(BoundDefaultExpression node)
{
var result = base.VisitDefaultExpression(node);
- _resultType = (object)node.Type == null ?
- null :
- TypeSymbolWithAnnotations.Create(node.Type, isNullableIfReferenceType: true, treatUnconstrainedTypeParameterAsNullable: true);
+ _resultType = TypeSymbolWithAnnotations.Create(node.Type, isNullableIfReferenceType: true, treatUnconstrainedTypeParameterAsNullable: true);
return result;
}
@@ -3827,7 +3859,7 @@ public override BoundNode VisitAsOperator(BoundAsOperator node)
case ConversionKind.Identity:
case ConversionKind.ImplicitReference:
// Inherit nullability from the operand
- isNullable = _resultType?.IsNullable;
+ isNullable = _resultType.IsNullable;
break;
case ConversionKind.Boxing:
@@ -3868,7 +3900,7 @@ public override BoundNode VisitSuppressNullableWarningExpression(BoundSuppressNu
//if (this.State.Reachable) // PROTOTYPE(NullableReferenceTypes): Consider reachability?
{
- _resultType = _resultType?.WithTopLevelNonNullabilityForReferenceTypes();
+ _resultType = _resultType.IsNull ? default : _resultType.WithTopLevelNonNullabilityForReferenceTypes();
}
return null;
@@ -4062,7 +4094,7 @@ public override BoundNode VisitArrayInitialization(BoundArrayInitialization node
private void SetUnknownResultNullability()
{
- _resultType = null;
+ _resultType = default;
}
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation node)
@@ -4095,12 +4127,12 @@ private void CheckPossibleNullReceiver(BoundExpression receiverOpt, bool checkTy
if (receiverOpt != null && this.State.Reachable)
{
#if DEBUG
- Debug.Assert(receiverOpt.Type is null || _resultType?.TypeSymbol is null || AreCloseEnough(receiverOpt.Type, _resultType.TypeSymbol));
+ Debug.Assert(receiverOpt.Type is null || _resultType.TypeSymbol is null || AreCloseEnough(receiverOpt.Type, _resultType.TypeSymbol));
#endif
- TypeSymbol receiverType = receiverOpt.Type ?? _resultType?.TypeSymbol;
+ TypeSymbol receiverType = receiverOpt.Type ?? _resultType.TypeSymbol;
if ((object)receiverType != null &&
(!checkType || !receiverType.IsValueType) &&
- _resultType?.IsNullable == true)
+ _resultType.IsNullable == true)
{
ReportStaticNullCheckingDiagnostics(ErrorCode.WRN_NullReferenceReceiver, receiverOpt.Syntax);
}
diff --git a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs
index bfe7d45b8616c..38e943285e590 100644
--- a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs
+++ b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs
@@ -203,6 +203,7 @@ public static bool IsWarning(ErrorCode code)
case ErrorCode.WRN_NullAsNonNullable:
case ErrorCode.WRN_NoBestNullabilityConditionalExpression:
case ErrorCode.WRN_MissingNonNullTypesContext:
+ case ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint:
return true;
default:
return false;
diff --git a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaCapturedVariable.cs b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaCapturedVariable.cs
index d179dbe24fc3d..352e0e99c31c0 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaCapturedVariable.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaCapturedVariable.cs
@@ -23,7 +23,7 @@ private LambdaCapturedVariable(SynthesizedContainer frame, TypeSymbolWithAnnotat
isReadOnly: false,
isStatic: false)
{
- Debug.Assert((object)type != null);
+ Debug.Assert(!type.IsNull);
// lifted fields do not need to have the CompilerGeneratedAttribute attached to it, the closure is already
// marked as being compiler generated.
diff --git a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs
index cddb6fa757c06..18e6a8418e752 100644
--- a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs
@@ -213,7 +213,7 @@ private Conversion RewriteConversion(Conversion conversion)
public sealed override TypeSymbol VisitType(TypeSymbol type)
{
- return TypeMap.SubstituteType(type)?.TypeSymbol;
+ return TypeMap.SubstituteType(type).TypeSymbol;
}
public override BoundNode VisitMethodInfo(BoundMethodInfo node)
diff --git a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs
index ff50a2fe17d1b..c562598996509 100644
--- a/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/SynthesizedMethodBaseSymbol.cs
@@ -165,7 +165,7 @@ internal override TypeSymbol IteratorElementType
{
if (_iteratorElementType == null)
{
- _iteratorElementType = TypeMap.SubstituteType(BaseMethod.IteratorElementType)?.TypeSymbol;
+ _iteratorElementType = TypeMap.SubstituteType(BaseMethod.IteratorElementType).TypeSymbol;
}
return _iteratorElementType;
}
diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs
index 509df4f7c2b44..ed31a774b8309 100644
--- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs
+++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs
@@ -29,7 +29,7 @@ private void VisitTypeSymbolWithAnnotations(TypeSymbolWithAnnotations type, Abst
public override void VisitArrayType(IArrayTypeSymbol symbol)
{
- VisitArrayType(symbol, typeOpt: null);
+ VisitArrayType(symbol, typeOpt: default);
}
private void VisitArrayType(IArrayTypeSymbol symbol, TypeSymbolWithAnnotations typeOpt)
@@ -57,15 +57,15 @@ private void VisitArrayType(IArrayTypeSymbol symbol, TypeSymbolWithAnnotations t
return;
}
- TypeSymbolWithAnnotations underlyingNonArrayTypeWithAnnotations = (symbol as ArrayTypeSymbol)?.ElementType;
+ TypeSymbolWithAnnotations underlyingNonArrayTypeWithAnnotations = (symbol as ArrayTypeSymbol)?.ElementType ?? default;
var underlyingNonArrayType = symbol.ElementType;
while (underlyingNonArrayType.Kind == SymbolKind.ArrayType)
{
- underlyingNonArrayTypeWithAnnotations = (underlyingNonArrayType as ArrayTypeSymbol)?.ElementType;
+ underlyingNonArrayTypeWithAnnotations = (underlyingNonArrayType as ArrayTypeSymbol)?.ElementType ?? default;
underlyingNonArrayType = ((IArrayTypeSymbol)underlyingNonArrayType).ElementType;
}
- if ((object)underlyingNonArrayTypeWithAnnotations != null)
+ if (!underlyingNonArrayTypeWithAnnotations.IsNull)
{
VisitTypeSymbolWithAnnotations(underlyingNonArrayTypeWithAnnotations);
}
@@ -85,14 +85,14 @@ private void VisitArrayType(IArrayTypeSymbol symbol, TypeSymbolWithAnnotations t
AddArrayRank(arrayType);
AddNullableAnnotations(typeOpt);
- typeOpt = (arrayType as ArrayTypeSymbol)?.ElementType;
+ typeOpt = (arrayType as ArrayTypeSymbol)?.ElementType ?? default;
arrayType = arrayType.ElementType as IArrayTypeSymbol;
}
}
private void AddNullableAnnotations(TypeSymbolWithAnnotations typeOpt)
{
- if (ReferenceEquals(typeOpt, null))
+ if (typeOpt.IsNull)
{
return;
}
@@ -731,7 +731,7 @@ private void AddTypeArguments(ISymbol owner, ImmutableArray new AnonymousTypeField(f.Name, Location.None, (TypeSymbolWithAnnotations)null));
+ var fields = key.Fields.SelectAsArray(f => new AnonymousTypeField(f.Name, Location.None, default));
var typeDescr = new AnonymousTypeDescriptor(fields, Location.None);
return new AnonymousTypeTemplateSymbol(this, typeDescr);
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/ArrayTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ArrayTypeSymbol.cs
index 79823ace8eb4a..e9e5275f0ba59 100644
--- a/src/Compilers/CSharp/Portable/Symbols/ArrayTypeSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/ArrayTypeSymbol.cs
@@ -22,7 +22,7 @@ private ArrayTypeSymbol(
TypeSymbolWithAnnotations elementType,
NamedTypeSymbol array)
{
- Debug.Assert((object)elementType != null);
+ Debug.Assert(!elementType.IsNull);
Debug.Assert((object)array != null);
_elementType = elementType;
@@ -390,7 +390,7 @@ internal override bool ApplyNullableTransforms(ImmutableArray transforms,
return false;
}
- if ((object)oldElementType == newElementType)
+ if (oldElementType.IsSameAs(newElementType))
{
result = this;
}
@@ -409,7 +409,7 @@ internal override TypeSymbol SetUnknownNullabilityForReferenceTypes()
TypeSymbolWithAnnotations oldElementType = ElementType;
TypeSymbolWithAnnotations newElementType = oldElementType.SetUnknownNullabilityForReferenceTypes();
- if ((object)oldElementType == newElementType)
+ if (oldElementType.IsSameAs(newElementType))
{
return this;
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs
index a11fad4ac1412..fa33cb6ca1245 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs
@@ -454,7 +454,7 @@ private static bool PermissionSetAttributeTypeHasRequiredProperty(NamedTypeSymbo
if (members.Length == 1 && members[0].Kind == SymbolKind.Property)
{
var property = (PropertySymbol)members[0];
- if ((object)property.Type != null && property.Type.SpecialType == SpecialType.System_String &&
+ if (!property.Type.IsNull && property.Type.SpecialType == SpecialType.System_String &&
property.DeclaredAccessibility == Accessibility.Public && property.GetMemberArity() == 0 &&
(object)property.SetMethod != null && property.SetMethod.DeclaredAccessibility == Accessibility.Public)
{
diff --git a/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs b/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs
index 2bc415c511030..501ba01cc92d1 100644
--- a/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs
@@ -702,7 +702,7 @@ public static bool CheckConstraints(
var diagnosticsBuilder = ArrayBuilder.GetInstance();
ArrayBuilder useSiteDiagnosticsBuilder = null;
- var result = CheckMethodConstraints(method, conversions, currentCompilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder);
+ var result = CheckMethodConstraints(method, conversions, currentCompilation, diagnosticsBuilder, warningsBuilderOpt: null, ref useSiteDiagnosticsBuilder);
if (useSiteDiagnosticsBuilder != null)
{
@@ -733,7 +733,7 @@ public static bool CheckConstraints(
var diagnosticsBuilder = ArrayBuilder.GetInstance();
ArrayBuilder useSiteDiagnosticsBuilder = null;
- var result = CheckMethodConstraints(method, conversions, currentCompilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder);
+ var result = CheckMethodConstraints(method, conversions, currentCompilation, diagnosticsBuilder, warningsBuilderOpt: null, ref useSiteDiagnosticsBuilder);
if (useSiteDiagnosticsBuilder != null)
{
@@ -764,6 +764,7 @@ private static bool CheckTypeConstraints(
type.TypeArgumentsNoUseSiteDiagnostics,
currentCompilation,
diagnosticsBuilder,
+ warningsBuilderOpt: conversions.IncludeNullability ? diagnosticsBuilder : null,
ref useSiteDiagnosticsBuilder);
}
@@ -772,6 +773,7 @@ public static bool CheckMethodConstraints(
ConversionsBase conversions,
Compilation currentCompilation,
ArrayBuilder diagnosticsBuilder,
+ ArrayBuilder warningsBuilderOpt,
ref ArrayBuilder useSiteDiagnosticsBuilder,
BitVector skipParameters = default(BitVector))
{
@@ -783,6 +785,7 @@ public static bool CheckMethodConstraints(
method.TypeArguments,
currentCompilation,
diagnosticsBuilder,
+ warningsBuilderOpt,
ref useSiteDiagnosticsBuilder,
skipParameters);
}
@@ -797,6 +800,7 @@ public static bool CheckMethodConstraints(
/// Containing symbol type arguments.
/// Improves error message detail.
/// Diagnostics.
+ /// Nullability warnings.
/// Parameters to skip.
///
/// If an original form of a type constraint
@@ -810,12 +814,14 @@ public static bool CheckConstraints(
ImmutableArray typeArguments,
Compilation currentCompilation,
ArrayBuilder diagnosticsBuilder,
+ ArrayBuilder warningsBuilderOpt,
ref ArrayBuilder useSiteDiagnosticsBuilder,
BitVector skipParameters = default(BitVector),
HashSet ignoreTypeConstraintsDependentOnTypeParametersOpt = null)
{
Debug.Assert(typeParameters.Length == typeArguments.Length);
Debug.Assert(typeParameters.Length > 0);
+ Debug.Assert(warningsBuilderOpt == null || conversions.IncludeNullability);
int n = typeParameters.Length;
bool succeeded = true;
@@ -830,7 +836,7 @@ public static bool CheckConstraints(
var typeArgument = typeArguments[i];
var typeParameter = typeParameters[i];
- if (!CheckConstraints(containingSymbol, conversions, substitution, typeParameter, typeArgument, currentCompilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder,
+ if (!CheckConstraints(containingSymbol, conversions, substitution, typeParameter, typeArgument, currentCompilation, diagnosticsBuilder, warningsBuilderOpt, ref useSiteDiagnosticsBuilder,
ignoreTypeConstraintsDependentOnTypeParametersOpt))
{
succeeded = false;
@@ -849,6 +855,7 @@ private static bool CheckConstraints(
TypeSymbolWithAnnotations typeArgument,
Compilation currentCompilation,
ArrayBuilder diagnosticsBuilder,
+ ArrayBuilder warningsBuilderOpt,
ref ArrayBuilder useSiteDiagnosticsBuilder,
HashSet ignoreTypeConstraintsDependentOnTypeParametersOpt)
{
@@ -911,8 +918,17 @@ private static bool CheckConstraints(
foreach (var constraintType in constraintTypes)
{
- if (SatisfiesConstraintType(conversions, typeArgument, constraintType, ref useSiteDiagnostics))
+ if (SatisfiesConstraintType(conversions.WithNullability(false), typeArgument, constraintType, ref useSiteDiagnostics))
{
+ if (warningsBuilderOpt != null)
+ {
+ Debug.Assert(conversions.IncludeNullability);
+ if (!SatisfiesConstraintType(conversions, typeArgument, constraintType, ref useSiteDiagnostics))
+ {
+ var diagnostic = new CSDiagnosticInfo(ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint, containingSymbol.ConstructedFrom(), constraintType, typeParameter, typeArgument);
+ warningsBuilderOpt.Add(new TypeParameterDiagnosticInfo(typeParameter, diagnostic));
+ }
+ }
continue;
}
@@ -1003,7 +1019,10 @@ private static bool SatisfiesConstraintType(
// "An identity conversion (6.1.1).
// An implicit reference conversion (6.1.6). ..."
- if (conversions.HasIdentityOrImplicitReferenceConversion(typeArgument.TypeSymbol, constraintType.TypeSymbol, ref useSiteDiagnostics))
+
+ // When nullability is considered, top-level nullability must be implicitly convertible.
+ if ((!conversions.IncludeNullability || ConversionsBase.HasTopLevelNullabilityImplicitConversion(typeArgument, constraintType)) &&
+ conversions.HasIdentityOrImplicitReferenceConversion(typeArgument.TypeSymbol, constraintType.TypeSymbol, ref useSiteDiagnostics))
{
return true;
}
@@ -1126,6 +1145,9 @@ private static bool IsEncompassedBy(ConversionsBase conversions, TypeSymbol a, T
Debug.Assert(IsValidEncompassedByArgument(a));
Debug.Assert(IsValidEncompassedByArgument(b));
+ // IncludeNullability should not be used when calculating EffectiveBaseType or EffectiveInterfaceSet.
+ Debug.Assert(!conversions.IncludeNullability);
+
return conversions.HasIdentityOrImplicitReferenceConversion(a, b, ref useSiteDiagnostics) || conversions.HasBoxingConversion(a, b, ref useSiteDiagnostics);
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs b/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs
index 0391bb7e43fb7..50e90ba61f576 100644
--- a/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs
@@ -514,7 +514,9 @@ public int GetHashCode(Symbol member)
if (_considerReturnType && member.GetMemberArity() == 0 &&
(_typeComparison & TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) == 0) // If it is generic, then type argument might be in return type.
{
- hash = Hash.Combine(member.GetTypeOrReturnType(), hash);
+ // PROTOTYPE(NullableReferenceTypes): TypeSymbolWithAnnotations.GetHashCode()
+ // throws ExceptionUtilities.Unreachable.
+ hash = Hash.Combine(member.GetTypeOrReturnType().GetHashCode(), hash);
}
// CONSIDER: modify hash for constraints?
diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/NullableTypeDecoder.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/NullableTypeDecoder.cs
index 64d85825c5c8f..123289750b876 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/NullableTypeDecoder.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/NullableTypeDecoder.cs
@@ -18,7 +18,7 @@ internal static TypeSymbolWithAnnotations TransformType(
EntityHandle targetSymbolToken,
PEModuleSymbol containingModule)
{
- Debug.Assert((object)metadataType != null);
+ Debug.Assert(!metadataType.IsNull);
ImmutableArray nullableTransformFlags;
containingModule.Module.HasNullableAttribute(targetSymbolToken, out nullableTransformFlags);
diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEEventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEEventSymbol.cs
index 71c134ae95eb5..6c4431b9f63f9 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEEventSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEEventSymbol.cs
@@ -88,8 +88,8 @@ internal PEEventSymbol(
}
}
- TypeSymbol originalEventType = _eventType?.TypeSymbol;
- if ((object)_eventType == null)
+ TypeSymbol originalEventType = _eventType.TypeSymbol;
+ if (_eventType.IsNull)
{
var metadataDecoder = new MetadataDecoder(moduleSymbol, containingType);
originalEventType = metadataDecoder.GetTypeOfToken(eventType);
diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs
index 26bd2f6fe1b8f..167ebc3775b0e 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs
@@ -33,7 +33,7 @@ internal sealed class PEFieldSymbol : FieldSymbol
private ObsoleteAttributeData _lazyObsoleteAttributeData = ObsoleteAttributeData.Uninitialized;
- private TypeSymbolWithAnnotations _lazyType;
+ private TypeSymbolWithAnnotations.Builder _lazyType;
private int _lazyFixedSize;
private NamedTypeSymbol _lazyFixedImplementationType;
private PEEventSymbol _associatedEventOpt;
@@ -203,7 +203,7 @@ internal void SetAssociatedEvent(PEEventSymbol eventSymbol)
private void EnsureSignatureIsLoaded()
{
- if ((object)_lazyType == null)
+ if (_lazyType.IsNull)
{
var moduleSymbol = _containingType.ContainingPEModule;
bool isVolatile;
@@ -234,7 +234,7 @@ private void EnsureSignatureIsLoaded()
type = TypeSymbolWithAnnotations.Create(new PointerTypeSymbol(TypeSymbolWithAnnotations.Create(fixedElementType)));
}
- Interlocked.CompareExchange(ref _lazyType, type, null);
+ _lazyType.InterlockedInitialize(type);
}
}
@@ -272,7 +272,7 @@ private PEModuleSymbol ContainingPEModule
internal override TypeSymbolWithAnnotations GetFieldType(ConsList fieldsBeingBound)
{
EnsureSignatureIsLoaded();
- return _lazyType;
+ return _lazyType.ToType();
}
public override bool IsFixed
diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs
index 929fa6d679d4b..ecfded1dc8be4 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs
@@ -199,7 +199,7 @@ private PEParameterSymbol(
Debug.Assert((object)moduleSymbol != null);
Debug.Assert((object)containingSymbol != null);
Debug.Assert(ordinal >= 0);
- Debug.Assert((object)type != null);
+ Debug.Assert(!type.IsNull);
isBad = false;
_moduleSymbol = moduleSymbol;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/TupleTypeDecoder.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/TupleTypeDecoder.cs
index 369540f312f75..f6f3855cc78a2 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/TupleTypeDecoder.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/TupleTypeDecoder.cs
@@ -261,7 +261,7 @@ private ImmutableArray DecodeTypeArguments(ImmutableA
{
TypeSymbolWithAnnotations typeArg = typeArgs[i];
TypeSymbolWithAnnotations decoded = DecodeTypeInternal(typeArg);
- anyDecoded |= !ReferenceEquals(decoded, typeArg);
+ anyDecoded |= !decoded.IsSameAs(typeArg);
decodedArgs.Add(decoded);
}
@@ -279,7 +279,7 @@ private ArrayTypeSymbol DecodeArrayType(ArrayTypeSymbol type)
{
TypeSymbolWithAnnotations elementType = type.ElementType;
TypeSymbolWithAnnotations decodedElementType = DecodeTypeInternal(elementType);
- return ReferenceEquals(decodedElementType, elementType)
+ return decodedElementType.IsSameAs(elementType)
? type
: type.WithElementType(decodedElementType);
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs
index b12f33199836f..bdfdee88a4216 100644
--- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs
@@ -756,7 +756,7 @@ public MethodSymbol Construct(params TypeSymbol[] typeArguments)
///
public MethodSymbol Construct(ImmutableArray typeArguments)
{
- return Construct(typeArguments.SelectAsArray(a => (object)a == null ? null : TypeSymbolWithAnnotations.Create(a)));
+ return Construct(typeArguments.SelectAsArray(a => TypeSymbolWithAnnotations.Create(a)));
}
internal MethodSymbol Construct(ImmutableArray typeArguments)
diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs
index 3f36d3a337269..5fcdab7b5123d 100644
--- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs
@@ -81,10 +81,10 @@ public static MethodSymbol InferExtensionMethodTypeArguments(this MethodSymbol m
// This prevents constraint checking from failing for corresponding type parameters.
var notInferredTypeParameters = PooledHashSet.GetInstance();
var typeParams = method.TypeParameters;
- var typeArgsForConstraintsCheck = typeArgs.SelectAsArray(a => (object)a == null ? null : TypeSymbolWithAnnotations.Create(a));
+ var typeArgsForConstraintsCheck = typeArgs.SelectAsArray(a => TypeSymbolWithAnnotations.Create(a));
for (int i = 0; i < typeArgsForConstraintsCheck.Length; i++)
{
- if ((object)typeArgsForConstraintsCheck[i] == null)
+ if (typeArgsForConstraintsCheck[i].IsNull)
{
firstNullInTypeArgs = i;
var builder = ArrayBuilder.GetInstance();
@@ -93,7 +93,7 @@ public static MethodSymbol InferExtensionMethodTypeArguments(this MethodSymbol m
for (; i < typeArgsForConstraintsCheck.Length; i++)
{
var typeArg = typeArgsForConstraintsCheck[i];
- if ((object)typeArg == null)
+ if (typeArg.IsNull)
{
notInferredTypeParameters.Add(typeParams[i]);
builder.Add(TypeSymbolWithAnnotations.Create(ErrorTypeSymbol.UnknownResultType));
@@ -113,7 +113,7 @@ public static MethodSymbol InferExtensionMethodTypeArguments(this MethodSymbol m
var diagnosticsBuilder = ArrayBuilder.GetInstance();
var substitution = new TypeMap(typeParams, typeArgsForConstraintsCheck);
ArrayBuilder useSiteDiagnosticsBuilder = null;
- var success = method.CheckConstraints(conversions, substitution, typeParams, typeArgsForConstraintsCheck, compilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder,
+ var success = method.CheckConstraints(conversions, substitution, typeParams, typeArgsForConstraintsCheck, compilation, diagnosticsBuilder, warningsBuilderOpt: null, ref useSiteDiagnosticsBuilder,
ignoreTypeConstraintsDependentOnTypeParametersOpt: notInferredTypeParameters.Count > 0 ? notInferredTypeParameters : null);
diagnosticsBuilder.Free();
notInferredTypeParameters.Free();
diff --git a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs
index 8272d3c175c4d..ff2a1bacf02d5 100644
--- a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs
@@ -777,7 +777,7 @@ internal override bool ApplyNullableTransforms(ImmutableArray transforms,
result = this;
return false;
}
- else if ((object)oldTypeArgument != newTypeArgument)
+ else if (!oldTypeArgument.IsSameAs(newTypeArgument))
{
allTypeArguments[i] = newTypeArgument;
haveChanges = true;
@@ -815,7 +815,7 @@ internal override TypeSymbol SetUnknownNullabilityForReferenceTypes()
{
TypeSymbolWithAnnotations oldTypeArgument = allTypeArguments[i];
TypeSymbolWithAnnotations newTypeArgument = oldTypeArgument.SetUnknownNullabilityForReferenceTypes();
- if ((object)oldTypeArgument != newTypeArgument)
+ if (!oldTypeArgument.IsSameAs(newTypeArgument))
{
allTypeArguments[i] = newTypeArgument;
haveChanges = true;
@@ -901,9 +901,9 @@ internal NamedTypeSymbol GetUnboundGenericTypeOrSelf()
///
internal abstract bool HasCodeAnalysisEmbeddedAttribute { get; }
- internal static readonly Func TypeSymbolIsNullFunction = type => (object)type == null;
+ internal static readonly Func TypeSymbolIsNullFunction = type => type.IsNull;
- internal static readonly Func TypeSymbolIsErrorType = type => (object)type != null && type.IsErrorType();
+ internal static readonly Func TypeSymbolIsErrorType = type => !type.IsNull && type.IsErrorType();
private NamedTypeSymbol ConstructWithoutModifiers(ImmutableArray typeArguments, bool unbound, INonNullTypesContext nonNullTypesContext)
{
@@ -913,19 +913,9 @@ private NamedTypeSymbol ConstructWithoutModifiers(ImmutableArray typ
{
modifiedArguments = default(ImmutableArray);
}
- else if (typeArguments.IsEmpty)
- {
- modifiedArguments = ImmutableArray.Empty;
- }
else
{
- var builder = ArrayBuilder.GetInstance(typeArguments.Length);
- foreach (TypeSymbol t in typeArguments)
- {
- builder.Add((object)t == null ? null : TypeSymbolWithAnnotations.Create(nonNullTypesContext, t));
- }
-
- modifiedArguments = builder.ToImmutableAndFree();
+ modifiedArguments = typeArguments.SelectAsArray((t, c) => t == null ? default : TypeSymbolWithAnnotations.Create(c, t), nonNullTypesContext);
}
return Construct(modifiedArguments, unbound);
diff --git a/src/Compilers/CSharp/Portable/Symbols/PointerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PointerTypeSymbol.cs
index de9b448dabdfb..9aec5c21f75b9 100644
--- a/src/Compilers/CSharp/Portable/Symbols/PointerTypeSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/PointerTypeSymbol.cs
@@ -23,7 +23,7 @@ internal sealed partial class PointerTypeSymbol : TypeSymbol, IPointerTypeSymbol
/// The type being pointed at.
internal PointerTypeSymbol(TypeSymbolWithAnnotations pointedAtType)
{
- Debug.Assert((object)pointedAtType != null);
+ Debug.Assert(!pointedAtType.IsNull);
_pointedAtType = pointedAtType;
}
@@ -265,7 +265,7 @@ internal override bool ApplyNullableTransforms(ImmutableArray transforms,
return false;
}
- if ((object)oldPointedAtType == newPointedAtType)
+ if (oldPointedAtType.IsSameAs(newPointedAtType))
{
result = this;
}
@@ -282,7 +282,7 @@ internal override TypeSymbol SetUnknownNullabilityForReferenceTypes()
TypeSymbolWithAnnotations oldPointedAtType = PointedAtType;
TypeSymbolWithAnnotations newPointedAtType = oldPointedAtType.SetUnknownNullabilityForReferenceTypes();
- if ((object)oldPointedAtType == newPointedAtType)
+ if (oldPointedAtType.IsSameAs(newPointedAtType))
{
return this;
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingMethodSymbol.cs
index 5cd4043ee893e..2e9c525cd47ec 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingMethodSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingMethodSymbol.cs
@@ -130,7 +130,7 @@ public override TypeSymbolWithAnnotations ReturnType
{
get
{
- if ((object)_lazyReturnType == null)
+ if (_lazyReturnType.IsNull)
{
_lazyReturnType = this.RetargetingTranslator.Retarget(_underlyingMethod.ReturnType, RetargetOptions.RetargetPrimitiveTypesByTypeCode, this.ContainingType);
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingPropertySymbol.cs
index ba73a70ba93fa..eb3a315e95b4c 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingPropertySymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingPropertySymbol.cs
@@ -59,7 +59,7 @@ public override TypeSymbolWithAnnotations Type
{
get
{
- if ((object)_lazyType == null)
+ if (_lazyType.IsNull)
{
var type = this.RetargetingTranslator.Retarget(_underlyingProperty.Type, RetargetOptions.RetargetPrimitiveTypesByTypeCode);
if (type.TypeSymbol.TryAsDynamicIfNoPia(this.ContainingType, out TypeSymbol asDynamic))
diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingSymbolTranslator.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingSymbolTranslator.cs
index 9841883404f93..e6c3669a118f8 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingSymbolTranslator.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingSymbolTranslator.cs
@@ -515,7 +515,7 @@ public NamedTypeSymbol Retarget(NamedTypeSymbol type, RetargetOptions options)
{
var newArg = Retarget(arg, RetargetOptions.RetargetPrimitiveTypesByTypeCode); // generic instantiation is a signature
- if (!anythingRetargeted && ((object)newArg != arg))
+ if (!anythingRetargeted && !newArg.IsSameAs(arg))
{
anythingRetargeted = true;
}
@@ -680,7 +680,7 @@ public ArrayTypeSymbol Retarget(ArrayTypeSymbol type)
TypeSymbolWithAnnotations oldElement = type.ElementType;
TypeSymbolWithAnnotations newElement = Retarget(oldElement, RetargetOptions.RetargetPrimitiveTypesByTypeCode);
- if ((object)oldElement == newElement)
+ if (oldElement.IsSameAs(newElement))
{
return type;
}
@@ -730,7 +730,7 @@ public PointerTypeSymbol Retarget(PointerTypeSymbol type)
TypeSymbolWithAnnotations oldPointed = type.PointedAtType;
TypeSymbolWithAnnotations newPointed = Retarget(oldPointed, RetargetOptions.RetargetPrimitiveTypesByTypeCode);
- if ((object)oldPointed == newPointed)
+ if (oldPointed.IsSameAs(newPointed))
{
return type;
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/GlobalExpressionVariable.cs b/src/Compilers/CSharp/Portable/Symbols/Source/GlobalExpressionVariable.cs
index 7b1ab4809801a..0742ba96a199b 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/GlobalExpressionVariable.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/GlobalExpressionVariable.cs
@@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
///
internal class GlobalExpressionVariable : SourceMemberFieldSymbol
{
- private TypeSymbolWithAnnotations _lazyType;
+ private TypeSymbolWithAnnotations.Builder _lazyType;
private SyntaxReference _typeSyntax;
internal GlobalExpressionVariable(
@@ -62,9 +62,9 @@ internal override TypeSymbolWithAnnotations GetFieldType(ConsList f
{
Debug.Assert(fieldsBeingBound != null);
- if ((object)_lazyType != null)
+ if (!_lazyType.IsNull)
{
- return _lazyType;
+ return _lazyType.ToType();
}
var typeSyntax = TypeSyntax;
@@ -79,12 +79,12 @@ internal override TypeSymbolWithAnnotations GetFieldType(ConsList f
bool isVar;
TypeSymbolWithAnnotations type = binder.BindTypeOrVarKeyword(typeSyntax, diagnostics, out isVar);
- Debug.Assert((object)type != null || isVar);
+ Debug.Assert(!type.IsNull || isVar);
if (isVar && !fieldsBeingBound.ContainsReference(this))
{
InferFieldType(fieldsBeingBound, binder);
- Debug.Assert((object)_lazyType != null);
+ Debug.Assert(!_lazyType.IsNull);
}
else
{
@@ -98,7 +98,7 @@ internal override TypeSymbolWithAnnotations GetFieldType(ConsList f
}
diagnostics.Free();
- return _lazyType;
+ return _lazyType.ToType();
}
///
@@ -107,23 +107,23 @@ internal override TypeSymbolWithAnnotations GetFieldType(ConsList f
///
private TypeSymbolWithAnnotations SetType(CSharpCompilation compilation, DiagnosticBag diagnostics, TypeSymbolWithAnnotations type)
{
- var originalType = _lazyType;
+ var originalType = _lazyType.DefaultType;
// In the event that we race to set the type of a field, we should
// always deduce the same type, unless the cached type is an error.
Debug.Assert((object)originalType == null ||
originalType.IsErrorType() ||
- originalType.TypeSymbol == type.TypeSymbol);
+ originalType == type.TypeSymbol);
- if ((object)Interlocked.CompareExchange(ref _lazyType, type, null) == null)
+ if (_lazyType.InterlockedInitialize(type))
{
TypeChecks(type.TypeSymbol, diagnostics);
compilation.DeclarationDiagnostics.AddRange(diagnostics);
state.NotePartComplete(CompletionPart.Type);
}
- return _lazyType;
+ return _lazyType.ToType();
}
///
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs
index 2ce22a2525960..49621d6f1d5c3 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs
@@ -24,12 +24,12 @@ internal sealed class LambdaSymbol : SourceMethodSymbol
/// This symbol is used as the return type of a LambdaSymbol when we are interpreting
/// lambda's body in order to infer its return type.
///
- internal static readonly TypeSymbolWithAnnotations ReturnTypeIsBeingInferred = TypeSymbolWithAnnotations.Create(new UnsupportedMetadataTypeSymbol());
+ internal static readonly TypeSymbol ReturnTypeIsBeingInferred = new UnsupportedMetadataTypeSymbol();
///
/// This symbol is used as the return type of a LambdaSymbol when we failed to infer its return type.
///
- internal static readonly TypeSymbolWithAnnotations InferenceFailureReturnType = TypeSymbolWithAnnotations.Create(new UnsupportedMetadataTypeSymbol());
+ internal static readonly TypeSymbol InferenceFailureReturnType = new UnsupportedMetadataTypeSymbol();
private static readonly TypeSymbolWithAnnotations UnknownReturnType = TypeSymbolWithAnnotations.Create(ErrorTypeSymbol.UnknownResultType);
@@ -47,7 +47,7 @@ public LambdaSymbol(
_messageID = unboundLambda.Data.MessageID;
_syntax = unboundLambda.Syntax;
_refKind = refKind;
- _returnType = returnType ?? ReturnTypeIsBeingInferred;
+ _returnType = returnType.IsNull ? TypeSymbolWithAnnotations.CreateUnannotated(NonNullTypesUnusedContext.Instance, ReturnTypeIsBeingInferred) : returnType;
_isSynthesized = unboundLambda.WasCompilerGenerated;
_isAsync = unboundLambda.IsAsync;
// No point in making this lazy. We are always going to need these soon after creation of the symbol.
@@ -166,7 +166,7 @@ internal override ImmutableArray GetAppliedConditionalSymbols()
public override bool ReturnsVoid
{
- get { return (object)this.ReturnType != null && this.ReturnType.SpecialType == SpecialType.System_Void; }
+ get { return !this.ReturnType.IsNull && this.ReturnType.SpecialType == SpecialType.System_Void; }
}
public override RefKind RefKind
@@ -185,8 +185,8 @@ public override TypeSymbolWithAnnotations ReturnType
// IDE might inspect the symbol and want to know the return type.
internal void SetInferredReturnType(RefKind refKind, TypeSymbolWithAnnotations inferredReturnType)
{
- Debug.Assert((object)inferredReturnType != null);
- Debug.Assert((object)_returnType == ReturnTypeIsBeingInferred);
+ Debug.Assert(!inferredReturnType.IsNull);
+ Debug.Assert((object)_returnType.TypeSymbol == ReturnTypeIsBeingInferred);
_refKind = refKind;
_returnType = inferredReturnType;
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs
index e669a47caf452..a695f5ea256ef 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs
@@ -208,7 +208,7 @@ public override TypeSymbolWithAnnotations ReturnType
internal void ComputeReturnType()
{
- if ((object)_lazyReturnType != null)
+ if (!_lazyReturnType.IsNull)
{
return;
}
@@ -243,7 +243,7 @@ internal void ComputeReturnType()
lock (_declarationDiagnostics)
{
- if ((object)_lazyReturnType != null)
+ if (!_lazyReturnType.IsNull)
{
diagnostics.Free();
return;
@@ -254,7 +254,7 @@ internal void ComputeReturnType()
}
}
- public override bool ReturnsVoid => ReturnType?.SpecialType == SpecialType.System_Void;
+ public override bool ReturnsVoid => ReturnType.SpecialType == SpecialType.System_Void;
public override int Arity => TypeParameters.Length;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs
index 297469682a79a..15276ea5cec98 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventAccessorSymbol.cs
@@ -40,14 +40,14 @@ public sealed override Symbol AssociatedSymbol
protected sealed override void MethodChecks(DiagnosticBag diagnostics)
{
- Debug.Assert(_lazyParameters.IsDefault == ((object)_lazyReturnType == null));
+ Debug.Assert(_lazyParameters.IsDefault == _lazyReturnType.IsNull);
// CONSIDER: currently, we're copying the custom modifiers of the event overridden
// by this method's associated event (by using the associated event's type, which is
// copied from the overridden event). It would be more correct to copy them from
// the specific accessor that this method is overriding (as in SourceMemberMethodSymbol).
- if ((object)_lazyReturnType == null)
+ if (_lazyReturnType.IsNull)
{
CSharpCompilation compilation = this.DeclaringCompilation;
Debug.Assert(compilation != null);
@@ -105,7 +105,7 @@ public sealed override bool ReturnsVoid
get
{
LazyMethodChecks();
- Debug.Assert((object)_lazyReturnType != null);
+ Debug.Assert(!_lazyReturnType.IsNull);
return base.ReturnsVoid;
}
}
@@ -120,7 +120,7 @@ public sealed override TypeSymbolWithAnnotations ReturnType
get
{
LazyMethodChecks();
- Debug.Assert((object)_lazyReturnType != null);
+ Debug.Assert(!_lazyReturnType.IsNull);
return _lazyReturnType;
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
index 370d9a240ac5f..14a7e70b7cc3e 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
@@ -27,7 +27,7 @@ internal class SourceLocalSymbol : LocalSymbol
private readonly RefKind _refKind;
private readonly TypeSyntax _typeSyntax;
private readonly LocalDeclarationKind _declarationKind;
- private TypeSymbolWithAnnotations _type;
+ private TypeSymbolWithAnnotations.Builder _type;
///
/// Scope to which the local can "escape" via aliasing/ref assignment.
@@ -100,7 +100,7 @@ internal Binder TypeSyntaxBinder
// don't let the debugger force inference.
internal new string GetDebuggerDisplay()
{
- return ((object)_type != null)
+ return !_type.IsNull
? base.GetDebuggerDisplay()
: $"{this.Kind} ${this.Name}";
}
@@ -285,7 +285,7 @@ public override TypeSymbolWithAnnotations Type
{
get
{
- if ((object)_type == null)
+ if (_type.IsNull)
{
#if DEBUG
concurrentTypeResolutions++;
@@ -295,7 +295,7 @@ public override TypeSymbolWithAnnotations Type
SetType(localType);
}
- return _type;
+ return _type.ToType();
}
}
@@ -336,7 +336,7 @@ private TypeSymbolWithAnnotations GetTypeSymbol()
// If we got a valid result that was not void then use the inferred type
// else create an error type.
- if ((object)inferredType != null &&
+ if (!inferredType.IsNull &&
inferredType.SpecialType != SpecialType.System_Void)
{
declType = inferredType;
@@ -347,7 +347,7 @@ private TypeSymbolWithAnnotations GetTypeSymbol()
}
}
- Debug.Assert((object)declType != null);
+ Debug.Assert(!declType.IsNull);
//
// Note that we drop the diagnostics on the floor! That is because this code is invoked mainly in
@@ -366,23 +366,23 @@ protected virtual TypeSymbolWithAnnotations InferTypeOfVarVariable(DiagnosticBag
// TODO: this method must be overridden for pattern variables to bind the
// expression or statement that is the nearest enclosing to the pattern variable's
// declaration. That will cause the type of the pattern variable to be set as a side-effect.
- return _type;
+ return _type.ToType();
}
internal void SetType(TypeSymbolWithAnnotations newType)
{
- TypeSymbolWithAnnotations originalType = _type;
+ TypeSymbol originalType = _type.DefaultType;
// In the event that we race to set the type of a local, we should
// always deduce the same type, or deduce that the type is an error.
Debug.Assert((object)originalType == null ||
originalType.IsErrorType() && newType.IsErrorType() ||
- originalType.TypeSymbol == newType.TypeSymbol);
+ originalType == newType.TypeSymbol);
if ((object)originalType == null)
{
- Interlocked.CompareExchange(ref _type, newType, null);
+ _type.InterlockedInitialize(newType);
}
}
@@ -522,7 +522,9 @@ public LocalWithInitializer(
protected override TypeSymbolWithAnnotations InferTypeOfVarVariable(DiagnosticBag diagnostics)
{
var initializerOpt = this._initializerBinder.BindInferredVariableInitializer(diagnostics, RefKind, _initializer, _initializer);
- return initializerOpt?.GetTypeAndNullability(_initializer.IsFeatureStaticNullCheckingEnabled());
+ return initializerOpt == null ?
+ default :
+ initializerOpt.GetTypeAndNullability(_initializer.IsFeatureStaticNullCheckingEnabled());
}
internal override SyntaxNode ForbiddenZone => _initializer;
@@ -675,8 +677,8 @@ protected override TypeSymbolWithAnnotations InferTypeOfVarVariable(DiagnosticBa
throw ExceptionUtilities.UnexpectedValue(_deconstruction.Kind());
}
- Debug.Assert((object)this._type != null);
- return this._type;
+ Debug.Assert(!this._type.IsNull);
+ return _type.ToType();
}
internal override SyntaxNode ForbiddenZone
@@ -763,13 +765,13 @@ protected override TypeSymbolWithAnnotations InferTypeOfVarVariable(DiagnosticBa
break;
}
- if ((object)this._type == null)
+ if (this._type.IsNull)
{
Debug.Assert(this.DeclarationKind == LocalDeclarationKind.DeclarationExpressionVariable);
SetType(TypeSymbolWithAnnotations.Create(_nodeBinder.CreateErrorType("var")));
}
- return this._type;
+ return _type.ToType();
}
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs
index 0d14a14c3155c..a366f760971a0 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs
@@ -276,7 +276,7 @@ internal class SourceMemberFieldSymbolFromDeclarator : SourceMemberFieldSymbol
{
private readonly bool _hasInitializer;
- private TypeSymbolWithAnnotations _lazyType;
+ private TypeSymbolWithAnnotations.Builder _lazyType;
// Non-zero if the type of the field has been inferred from the type of its initializer expression
// and the errors of binding the initializer have been or are being reported to compilation diagnostics.
@@ -351,12 +351,12 @@ internal override bool HasPointerType
{
get
{
- if ((object)_lazyType != null)
+ if (!_lazyType.IsNull)
{
- Debug.Assert(_lazyType.TypeSymbol.IsPointerType() ==
+ Debug.Assert(_lazyType.DefaultType.IsPointerType() ==
IsPointerFieldSyntactically());
- return _lazyType.TypeSymbol.IsPointerType();
+ return _lazyType.DefaultType.IsPointerType();
}
return IsPointerFieldSyntactically();
@@ -389,9 +389,9 @@ internal sealed override TypeSymbolWithAnnotations GetFieldType(ConsList 1)
{
@@ -460,7 +460,7 @@ internal sealed override TypeSymbolWithAnnotations GetFieldType(ConsList fieldsBeingBound)
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs
index 157e44a7c60fc..0f0c9f79285ae 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs
@@ -37,7 +37,7 @@ internal sealed class SourcePropertySymbol : PropertySymbol, IAttributeTargetSym
private SymbolCompletionState _state;
private ImmutableArray _lazyParameters;
- private TypeSymbolWithAnnotations _lazyType;
+ private TypeSymbolWithAnnotations.Builder _lazyType;
///
/// Set in constructor, might be changed while decoding .
@@ -238,7 +238,8 @@ private SourcePropertySymbol(
// lazily since the property name depends on the metadata name of the base property,
// and the property name is required to add the property to the containing type, and
// the type and parameters are required to determine the override or implementation.
- _lazyType = this.ComputeType(bodyBinder, syntax, diagnostics);
+ var type = this.ComputeType(bodyBinder, syntax, diagnostics);
+ _lazyType.InterlockedInitialize(type);
_lazyParameters = this.ComputeParameters(bodyBinder, syntax, diagnostics);
bool isOverride = false;
@@ -270,11 +271,13 @@ private SourcePropertySymbol(
// We do an extra check before copying the type to handle the case where the overriding
// property (incorrectly) has a different type than the overridden property. In such cases,
// we want to retain the original (incorrect) type to avoid hiding the type given in source.
- if (_lazyType.TypeSymbol.Equals(overriddenPropertyType.TypeSymbol, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds | TypeCompareKind.IgnoreDynamic))
+ if (type.TypeSymbol.Equals(overriddenPropertyType.TypeSymbol, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds | TypeCompareKind.IgnoreDynamic))
{
- _lazyType = _lazyType.WithTypeAndModifiers(
- CustomModifierUtils.CopyTypeCustomModifiers(overriddenPropertyType.TypeSymbol, _lazyType.TypeSymbol, this.ContainingAssembly, nonNullTypesContext: this),
+ type = type.WithTypeAndModifiers(
+ CustomModifierUtils.CopyTypeCustomModifiers(overriddenPropertyType.TypeSymbol, type.TypeSymbol, this.ContainingAssembly, nonNullTypesContext: this),
overriddenPropertyType.CustomModifiers);
+ _lazyType = default;
+ _lazyType.InterlockedInitialize(type);
}
_lazyParameters = CustomModifierUtils.CopyParameterCustomModifiers(overriddenOrImplementedProperty.Parameters, _lazyParameters, alsoCopyParamsModifier: isOverride);
@@ -471,20 +474,20 @@ public override TypeSymbolWithAnnotations Type
{
get
{
- if ((object)_lazyType == null)
+ if (_lazyType.IsNull)
{
var diagnostics = DiagnosticBag.GetInstance();
var binder = this.CreateBinderForTypeAndParameters();
var syntax = (BasePropertyDeclarationSyntax)_syntaxRef.GetSyntax();
var result = this.ComputeType(binder, syntax, diagnostics);
- if ((object)Interlocked.CompareExchange(ref _lazyType, result, null) == null)
+ if (_lazyType.InterlockedInitialize(result))
{
this.AddDeclarationDiagnostics(diagnostics);
}
diagnostics.Free();
}
- return _lazyType;
+ return _lazyType.ToType();
}
}
@@ -492,9 +495,9 @@ internal bool HasPointerType
{
get
{
- if ((object)_lazyType != null)
+ if (!_lazyType.IsNull)
{
- return _lazyType.IsPointerType();
+ return _lazyType.DefaultType.IsPointerType();
}
var syntax = (BasePropertyDeclarationSyntax)_syntaxRef.GetSyntax();
diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedEventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedEventSymbol.cs
index d53ab8ac1f503..49e1c69d08f08 100644
--- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedEventSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedEventSymbol.cs
@@ -10,7 +10,7 @@ internal sealed class SubstitutedEventSymbol : WrappedEventSymbol
{
private readonly SubstitutedNamedTypeSymbol _containingType;
- private TypeSymbolWithAnnotations _lazyType;
+ private TypeSymbolWithAnnotations.Builder _lazyType;
internal SubstitutedEventSymbol(SubstitutedNamedTypeSymbol containingType, EventSymbol originalDefinition)
: base(originalDefinition)
@@ -23,12 +23,12 @@ public override TypeSymbolWithAnnotations Type
{
get
{
- if ((object)_lazyType == null)
+ if (_lazyType.IsNull)
{
- Interlocked.CompareExchange(ref _lazyType, _containingType.TypeSubstitution.SubstituteTypeWithTupleUnification(OriginalDefinition.Type), null);
+ _lazyType.InterlockedInitialize(_containingType.TypeSubstitution.SubstituteTypeWithTupleUnification(OriginalDefinition.Type));
}
- return _lazyType;
+ return _lazyType.ToType();
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedFieldSymbol.cs
index 2e326df40649e..c4d77bb3b83c7 100644
--- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedFieldSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedFieldSymbol.cs
@@ -12,7 +12,7 @@ internal sealed class SubstitutedFieldSymbol : WrappedFieldSymbol
{
private readonly SubstitutedNamedTypeSymbol _containingType;
- private TypeSymbolWithAnnotations _lazyType;
+ private TypeSymbolWithAnnotations.Builder _lazyType;
internal SubstitutedFieldSymbol(SubstitutedNamedTypeSymbol containingType, FieldSymbol substitutedFrom)
: base((FieldSymbol)substitutedFrom.OriginalDefinition)
@@ -22,12 +22,12 @@ internal SubstitutedFieldSymbol(SubstitutedNamedTypeSymbol containingType, Field
internal override TypeSymbolWithAnnotations GetFieldType(ConsList fieldsBeingBound)
{
- if ((object)_lazyType == null)
+ if (_lazyType.IsNull)
{
- Interlocked.CompareExchange(ref _lazyType, _containingType.TypeSubstitution.SubstituteTypeWithTupleUnification(OriginalDefinition.GetFieldType(fieldsBeingBound)), null);
+ _lazyType.InterlockedInitialize(_containingType.TypeSubstitution.SubstituteTypeWithTupleUnification(OriginalDefinition.GetFieldType(fieldsBeingBound)));
}
- return _lazyType;
+ return _lazyType.ToType();
}
public override Symbol ContainingSymbol
diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedMethodSymbol.cs
index d3edf4e4ceb8e..0ed75eea49e4c 100644
--- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedMethodSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedMethodSymbol.cs
@@ -22,7 +22,7 @@ internal class SubstitutedMethodSymbol : WrappedMethodSymbol
private readonly TypeMap _inputMap;
private readonly MethodSymbol _constructedFrom;
- private TypeSymbolWithAnnotations _lazyReturnType;
+ private TypeSymbolWithAnnotations.Builder _lazyReturnType;
private ImmutableArray _lazyParameters;
private TypeMap _lazyMap;
private ImmutableArray _lazyTypeParameters;
@@ -230,14 +230,12 @@ public sealed override TypeSymbolWithAnnotations ReturnType
{
get
{
- var returnType = _lazyReturnType;
- if ((object)returnType != null)
+ if (_lazyReturnType.IsNull)
{
- return returnType;
+ var returnType = Map.SubstituteTypeWithTupleUnification(OriginalDefinition.ReturnType);
+ _lazyReturnType.InterlockedInitialize(returnType);
}
-
- returnType = Map.SubstituteTypeWithTupleUnification(OriginalDefinition.ReturnType);
- return Interlocked.CompareExchange(ref _lazyReturnType, returnType, null) ?? returnType;
+ return _lazyReturnType.ToType();
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedParameterSymbol.cs
index aae49022367e7..b45361afc7619 100644
--- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedParameterSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedParameterSymbol.cs
@@ -45,24 +45,21 @@ public override TypeSymbolWithAnnotations Type
get
{
var mapOrType = _mapOrType;
- var type = mapOrType as TypeSymbolWithAnnotations;
- if ((object)type != null)
+ if (mapOrType is TypeSymbolWithAnnotations type)
{
return type;
}
TypeSymbolWithAnnotations substituted = ((TypeMap)mapOrType).SubstituteTypeWithTupleUnification(this._underlyingParameter.Type);
- type = substituted;
-
if (substituted.CustomModifiers.IsEmpty &&
this._underlyingParameter.Type.CustomModifiers.IsEmpty &&
this._underlyingParameter.RefCustomModifiers.IsEmpty)
{
- _mapOrType = type;
+ _mapOrType = substituted;
}
- return type;
+ return substituted;
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedPropertySymbol.cs
index 2ccb90dbb0e5e..2cff86934f85e 100644
--- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedPropertySymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedPropertySymbol.cs
@@ -10,7 +10,7 @@ internal sealed class SubstitutedPropertySymbol : WrappedPropertySymbol
{
private readonly SubstitutedNamedTypeSymbol _containingType;
- private TypeSymbolWithAnnotations _lazyType;
+ private TypeSymbolWithAnnotations.Builder _lazyType;
private ImmutableArray _lazyParameters;
internal SubstitutedPropertySymbol(SubstitutedNamedTypeSymbol containingType, PropertySymbol originalDefinition)
@@ -23,12 +23,12 @@ public override TypeSymbolWithAnnotations Type
{
get
{
- if ((object)_lazyType == null)
+ if (_lazyType.IsNull)
{
- Interlocked.CompareExchange(ref _lazyType, _containingType.TypeSubstitution.SubstituteTypeWithTupleUnification(OriginalDefinition.Type), null);
+ _lazyType.InterlockedInitialize(_containingType.TypeSubstitution.SubstituteTypeWithTupleUnification(OriginalDefinition.Type));
}
- return _lazyType;
+ return _lazyType.ToType();
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs
index dba525a50b5c4..12cbe27892aff 100644
--- a/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs
@@ -58,7 +58,7 @@ public static bool Any(this ImmutableArray array, Sym
for (int i = 0, n = array.Length; i < n; i++)
{
var item = array[i];
- if ((object)item != null && item.Kind == kind)
+ if (!item.IsNull && item.Kind == kind)
{
return true;
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/SymbolWithAnnotations.cs b/src/Compilers/CSharp/Portable/Symbols/SymbolWithAnnotations.cs
index ce56d2ad1cd7b..23b8b7950e3be 100644
--- a/src/Compilers/CSharp/Portable/Symbols/SymbolWithAnnotations.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/SymbolWithAnnotations.cs
@@ -15,9 +15,103 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
/// A simple class that combines a single type symbol with annotations
///
[DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
- internal abstract class TypeSymbolWithAnnotations : IFormattable
+ internal readonly struct TypeSymbolWithAnnotations : IFormattable
{
- public sealed override string ToString() => TypeSymbol.ToString();
+ ///
+ /// A builder for lazy instances of TypeSymbolWithAnnotations.
+ ///
+ [DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
+ internal struct Builder
+ {
+ private TypeSymbol _defaultType;
+ private INonNullTypesContext _nonNullTypesContext;
+ private bool _isAnnotated;
+ private Extensions _extensions;
+
+ ///
+ /// The underlying type, unless overridden by _extensions.
+ ///
+ internal TypeSymbol DefaultType => _defaultType;
+
+ ///
+ /// True if the fields of the builder are unset.
+ ///
+ internal bool IsNull => _defaultType is null;
+
+ ///
+ /// Set the fields of the builder.
+ ///
+ ///
+ /// This method guarantees: fields will be set once; exactly one caller is
+ /// returned true; and IsNull will return true until all fields are initialized.
+ /// This method does not guarantee that all fields will be set by the same
+ /// caller. Instead, the expectation is that all callers will attempt to initialize
+ /// the builder with equivalent TypeSymbolWithAnnotations instances where
+ /// different fields of the builder may be assigned from different instances.
+ ///
+ internal bool InterlockedInitialize(TypeSymbolWithAnnotations type)
+ {
+ if ((object)_defaultType != null)
+ {
+ return false;
+ }
+ _isAnnotated = type.IsAnnotated;
+ Interlocked.CompareExchange(ref _nonNullTypesContext, type.NonNullTypesContext, null);
+ Interlocked.CompareExchange(ref _extensions, type._extensions, null);
+ return (object)Interlocked.CompareExchange(ref _defaultType, type._defaultType, null) == null;
+ }
+
+ ///
+ /// Create immutable TypeSymbolWithAnnotations instance.
+ ///
+ internal TypeSymbolWithAnnotations ToType()
+ {
+ return (object)_defaultType == null ?
+ default :
+ new TypeSymbolWithAnnotations(_defaultType, _nonNullTypesContext, _isAnnotated, _extensions);
+ }
+
+ internal string GetDebuggerDisplay() => ToType().GetDebuggerDisplay();
+ }
+
+ ///
+ /// The underlying type, unless overridden by _extensions.
+ ///
+ private readonly TypeSymbol _defaultType;
+
+ ///
+ /// Additional data or behavior. Such cases should be
+ /// uncommon to minimize allocations.
+ ///
+ private readonly Extensions _extensions;
+
+ ///
+ /// Returns:
+ /// false for string, int, T;
+ /// true for string?, T? where T : class; and
+ /// true for int?, T? where T : struct.
+ ///
+ public readonly bool IsAnnotated;
+
+ ///
+ /// [NonNullTypes] context used for determining whether unannotated types are not nullable.
+ /// Allows us to get the information without eagerly pulling on the NonNullTypes property (which causes cycles).
+ ///
+ public readonly INonNullTypesContext NonNullTypesContext;
+
+ private TypeSymbolWithAnnotations(TypeSymbol defaultType, INonNullTypesContext nonNullTypesContext, bool isAnnotated, Extensions extensions)
+ {
+ Debug.Assert((object)defaultType != null);
+ Debug.Assert(!defaultType.IsNullableType() || isAnnotated);
+ Debug.Assert(nonNullTypesContext != null);
+ Debug.Assert(extensions != null);
+ _defaultType = defaultType;
+ IsAnnotated = isAnnotated;
+ NonNullTypesContext = nonNullTypesContext;
+ _extensions = extensions;
+ }
+
+ public override string ToString() => TypeSymbol.ToString();
public string Name => TypeSymbol.Name;
public SymbolKind Kind => TypeSymbol.Kind;
@@ -64,10 +158,20 @@ public static TypeSymbolWithAnnotations Create(TypeSymbol typeSymbol, ImmutableA
{
if (typeSymbol is null)
{
- return null;
+ return default;
}
- return Create(typeSymbol, typeSymbol.IsNullableType(), treatUnconstrainedTypeParameterAsNullable: false, customModifiers);
+ return CreateNonLazyType(typeSymbol, NonNullTypesTrueContext.Instance, isAnnotated: typeSymbol.IsNullableType(), customModifiers);
+ }
+
+ internal static TypeSymbolWithAnnotations CreateNonLazyType(TypeSymbol typeSymbol, INonNullTypesContext nonNullTypesContext, bool isAnnotated, ImmutableArray customModifiers)
+ {
+ return new TypeSymbolWithAnnotations(typeSymbol, nonNullTypesContext, isAnnotated, Extensions.Create(customModifiers));
+ }
+
+ internal static TypeSymbolWithAnnotations CreateLazyNullableType(CSharpCompilation compilation, TypeSymbolWithAnnotations underlying)
+ {
+ return new TypeSymbolWithAnnotations(defaultType: underlying._defaultType, nonNullTypesContext: underlying.NonNullTypesContext, isAnnotated: true, Extensions.CreateLazy(compilation, underlying));
}
// PROTOTYPE(NullableReferenceTypes): [Obsolete("Use explicit NonNullTypes context")]
@@ -94,7 +198,7 @@ public static TypeSymbolWithAnnotations Create(TypeSymbol typeSymbol, INonNullTy
if (typeSymbol is null)
{
- return null;
+ return default;
}
// PROTOTYPE(NullableReferenceTypes): See if the if/else can be simplified to:
@@ -118,9 +222,14 @@ public static TypeSymbolWithAnnotations Create(TypeSymbol typeSymbol, INonNullTy
isAnnotated = typeSymbol.IsNullableType() || (treatUnconstrainedTypeParameterAsNullable && typeSymbol.IsUnconstrainedTypeParameter());
}
- return new NonLazyType(typeSymbol, nonNullTypesContext, isAnnotated, customModifiers);
+ return CreateNonLazyType(typeSymbol, nonNullTypesContext, isAnnotated: isAnnotated, customModifiers);
}
+ ///
+ /// True if the fields are unset.
+ ///
+ internal bool IsNull => _defaultType is null;
+
public TypeSymbolWithAnnotations SetIsAnnotated(CSharpCompilation compilation)
{
Debug.Assert(compilation.IsFeatureEnabled(MessageID.IDS_FeatureStaticNullChecking));
@@ -134,7 +243,7 @@ public TypeSymbolWithAnnotations SetIsAnnotated(CSharpCompilation compilation)
{
if (!typeSymbol.IsValueType)
{
- return new NonLazyType(typeSymbol, NonNullTypesContext, isAnnotated: true, this.CustomModifiers);
+ return CreateNonLazyType(typeSymbol, NonNullTypesContext, isAnnotated: true, this.CustomModifiers);
}
else
{
@@ -142,22 +251,28 @@ public TypeSymbolWithAnnotations SetIsAnnotated(CSharpCompilation compilation)
}
}
- return new LazyNullableTypeParameter(compilation, this);
+ return CreateLazyNullableType(compilation, this);
}
///
/// Adjust types in signatures coming from metadata.
///
- public abstract TypeSymbolWithAnnotations AsNullableReferenceType();
- public abstract TypeSymbolWithAnnotations AsNotNullableReferenceType();
+ public TypeSymbolWithAnnotations AsNullableReferenceType() => _extensions.AsNullableReferenceType(this);
+ public TypeSymbolWithAnnotations AsNotNullableReferenceType() => _extensions.AsNotNullableReferenceType(this);
+
+ public TypeSymbolWithAnnotations WithModifiers(ImmutableArray customModifiers) =>
+ _extensions.WithModifiers(this, customModifiers);
+ public TypeSymbolWithAnnotations WithNonNullTypesContext(INonNullTypesContext nonNullTypesContext) =>
+ _extensions.WithNonNullTypesContext(this, nonNullTypesContext);
- public abstract TypeSymbolWithAnnotations WithModifiers(ImmutableArray customModifiers);
- public abstract TypeSymbolWithAnnotations WithNonNullTypesContext(INonNullTypesContext nonNullTypesContext);
+ public TypeSymbol TypeSymbol => _extensions?.GetResolvedType(_defaultType);
+ public TypeSymbol NullableUnderlyingTypeOrSelf => _extensions.GetNullableUnderlyingTypeOrSelf(_defaultType);
- public abstract TypeSymbol TypeSymbol { get; }
- public virtual TypeSymbol NullableUnderlyingTypeOrSelf => TypeSymbol.StrippedType();
+ // PROTOTYPE(NullableReferenceTypes): IsNullable depends on IsValueType which
+ // can lead to cycles when IsNullable is queried early. Replace this property with
+ // the Annotation property that depends on IsAnnotated and NonNullTypes only.
+ // Should review all the usages of IsNullable outside of NullableWalker.
- // PROTOTYPE(NullableReferenceTypes): Should review all the usages of IsNullable outside of NullableWalker.
///
/// Returns:
/// true if this is a nullable reference or value type;
@@ -169,21 +284,29 @@ public TypeSymbolWithAnnotations SetIsAnnotated(CSharpCompilation compilation)
/// If this is a nullable reference type,
/// simply returns a symbol for the reference type.
///
- public abstract bool? IsNullable { get; }
-
- ///
- /// Returns:
- /// false for string, int, T;
- /// true for string?, T? where T : class; and
- /// true for int?, T? where T : struct.
- ///
- public abstract bool IsAnnotated { get; }
-
- ///
- /// [NonNullTypes] context used for determining whether unannotated types are not nullable.
- /// Allows us to get the information without eagerly pulling on the NonNullTypes property (which causes cycles).
- ///
- public abstract INonNullTypesContext NonNullTypesContext { get; }
+ public bool? IsNullable
+ {
+ get
+ {
+ if (_defaultType is null)
+ {
+ return null;
+ }
+ if (IsAnnotated)
+ {
+ return true;
+ }
+ if (NonNullTypesContext.NonNullTypes == true)
+ {
+ return false;
+ }
+ if (TypeSymbol.IsValueType)
+ {
+ return false;
+ }
+ return null;
+ }
+ }
///
/// Returns:
@@ -200,13 +323,20 @@ internal bool? IsAnnotatedWithNonNullTypesContext
{
get
{
+ if (_defaultType is null)
+ {
+ return null;
+ }
if (IsAnnotated)
{
return true;
}
-
// A null NonNullTypes (ie. no attribute) means the same as NonNullTypes(false).
- return NonNullTypesContext.NonNullTypes == true ? false : (bool?)null;
+ if (NonNullTypesContext.NonNullTypes == true)
+ {
+ return false;
+ }
+ return null;
}
}
@@ -218,30 +348,34 @@ internal bool? IsAnnotatedWithNonNullTypesContext
///
/// The list of custom modifiers, if any, associated with the .
///
- public abstract ImmutableArray CustomModifiers { get; }
+ public ImmutableArray CustomModifiers => _extensions.CustomModifiers;
public bool IsReferenceType => TypeSymbol.IsReferenceType;
public bool IsValueType => TypeSymbol.IsValueType;
public TypeKind TypeKind => TypeSymbol.TypeKind;
- public virtual SpecialType SpecialType => TypeSymbol.SpecialType;
+ public SpecialType SpecialType => _extensions.GetSpecialType(_defaultType);
public bool IsManagedType => TypeSymbol.IsManagedType;
public Cci.PrimitiveTypeCode PrimitiveTypeCode => TypeSymbol.PrimitiveTypeCode;
public bool IsEnumType() => TypeSymbol.IsEnumType();
public bool IsDynamic() => TypeSymbol.IsDynamic();
public bool IsObjectType() => TypeSymbol.IsObjectType();
public bool IsArray() => TypeSymbol.IsArray();
- public virtual bool IsRestrictedType(bool ignoreSpanLikeTypes = false) => TypeSymbol.IsRestrictedType(ignoreSpanLikeTypes);
+ public bool IsRestrictedType(bool ignoreSpanLikeTypes = false) =>
+ _extensions.IsRestrictedType(_defaultType, ignoreSpanLikeTypes);
public bool IsPointerType() => TypeSymbol.IsPointerType();
public bool IsErrorType() => TypeSymbol.IsErrorType();
public bool IsUnsafe() => TypeSymbol.IsUnsafe();
- public virtual bool IsStatic => TypeSymbol.IsStatic;
+ public bool IsStatic => _extensions.IsStatic(_defaultType);
public bool IsNullableTypeOrTypeParameter() => TypeSymbol.IsNullableTypeOrTypeParameter();
- public virtual bool IsVoid => TypeSymbol.SpecialType == SpecialType.System_Void;
- public virtual bool IsSZArray() => TypeSymbol.IsSZArray();
- public TypeSymbolWithAnnotations GetNullableUnderlyingType() => TypeSymbol.GetNullableUnderlyingTypeWithAnnotations();
+ public bool IsVoid => _extensions.IsVoid(_defaultType);
+ public bool IsSZArray() => _extensions.IsSZArray(_defaultType);
+ public TypeSymbolWithAnnotations GetNullableUnderlyingType() =>
+ TypeSymbol.GetNullableUnderlyingTypeWithAnnotations();
- internal abstract bool GetIsReferenceType(ConsList inProgress);
- internal abstract bool GetIsValueType(ConsList inProgress);
+ internal bool GetIsReferenceType(ConsList inProgress) =>
+ _extensions.GetIsReferenceType(_defaultType, inProgress);
+ internal bool GetIsValueType(ConsList inProgress) =>
+ _extensions.GetIsValueType(_defaultType, inProgress);
public string ToDisplayString(SymbolDisplayFormat format = null)
{
@@ -267,7 +401,7 @@ public string ToDisplayString(SymbolDisplayFormat format = null)
return str;
}
- internal string GetDebuggerDisplay() => ToDisplayString(DebuggerDisplayFormat);
+ internal string GetDebuggerDisplay() => _defaultType is null ? "null" : ToDisplayString(DebuggerDisplayFormat);
// PROTOTYPE(NullableReferenceTypes): Remove IFormattable implementation
// if instances should not be used as Diagnostic arguments.
@@ -278,12 +412,12 @@ string IFormattable.ToString(string format, IFormatProvider formatProvider)
public bool Equals(TypeSymbolWithAnnotations other, TypeCompareKind comparison)
{
- if (ReferenceEquals(this, other))
+ if (this.IsSameAs(other))
{
return true;
}
- if ((object)other == null || !TypeSymbolEquals(other, comparison))
+ if (other.IsNull || !TypeSymbolEquals(other, comparison))
{
return false;
}
@@ -322,7 +456,7 @@ private EqualsComparer()
public override int GetHashCode(TypeSymbolWithAnnotations obj)
{
- if (obj is null)
+ if (obj.IsNull)
{
return 0;
}
@@ -331,18 +465,16 @@ public override int GetHashCode(TypeSymbolWithAnnotations obj)
public override bool Equals(TypeSymbolWithAnnotations x, TypeSymbolWithAnnotations y)
{
- if (x is null)
+ if (x.IsNull)
{
- return y is null;
+ return y.IsNull;
}
return x.Equals(y, TypeCompareKind.CompareNullableModifiersForReferenceTypes);
}
}
- protected virtual bool TypeSymbolEquals(TypeSymbolWithAnnotations other, TypeCompareKind comparison)
- {
- return this.TypeSymbol.Equals(other.TypeSymbol, comparison);
- }
+ internal bool TypeSymbolEquals(TypeSymbolWithAnnotations other, TypeCompareKind comparison) =>
+ _extensions.TypeSymbolEquals(this, other, comparison);
public bool GetUnificationUseSiteDiagnosticRecursive(ref DiagnosticInfo result, Symbol owner, ref HashSet checkedTypes)
{
@@ -361,24 +493,19 @@ public bool IsAtLeastAsVisibleAs(Symbol sym, ref HashSet useSite
return NullableUnderlyingTypeOrSelf.IsAtLeastAsVisibleAs(sym, ref useSiteDiagnostics);
}
- public TypeSymbolWithAnnotations SubstituteType(AbstractTypeMap typeMap)
- {
- return SubstituteType(typeMap, withTupleUnification: false);
- }
-
- public TypeSymbolWithAnnotations SubstituteTypeWithTupleUnification(AbstractTypeMap typeMap)
- {
- return SubstituteType(typeMap, withTupleUnification: true);
- }
+ public TypeSymbolWithAnnotations SubstituteType(AbstractTypeMap typeMap) =>
+ _extensions.SubstituteType(this, typeMap, withTupleUnification: false);
+ public TypeSymbolWithAnnotations SubstituteTypeWithTupleUnification(AbstractTypeMap typeMap) =>
+ _extensions.SubstituteType(this, typeMap, withTupleUnification: true);
- protected virtual TypeSymbolWithAnnotations SubstituteType(AbstractTypeMap typeMap, bool withTupleUnification)
+ internal TypeSymbolWithAnnotations SubstituteTypeCore(AbstractTypeMap typeMap, bool withTupleUnification)
{
var newCustomModifiers = typeMap.SubstituteCustomModifiers(this.CustomModifiers);
var newTypeWithModifiers = typeMap.SubstituteType(this.TypeSymbol, withTupleUnification);
bool newIsAnnotated = this.IsAnnotated || newTypeWithModifiers.IsAnnotated;
// PROTOTYPE(NullableReferenceTypes): Can we use Equals instead?
- if (TypeSymbolEquals(newTypeWithModifiers, TypeCompareKind.CompareNullableModifiersForReferenceTypes) &&
+ if (this.TypeSymbolEquals(newTypeWithModifiers, TypeCompareKind.CompareNullableModifiersForReferenceTypes) &&
newTypeWithModifiers.CustomModifiers.IsEmpty &&
newIsAnnotated == this.IsAnnotated &&
newCustomModifiers == this.CustomModifiers)
@@ -400,14 +527,22 @@ protected virtual TypeSymbolWithAnnotations SubstituteType(AbstractTypeMap typeM
{
return newTypeWithModifiers;
}
- return new NonLazyType(
+ return TypeSymbolWithAnnotations.CreateNonLazyType(
newTypeWithModifiers.TypeSymbol,
newTypeWithModifiers.NonNullTypesContext,
isAnnotated: newIsAnnotated,
newCustomModifiers.Concat(newTypeWithModifiers.CustomModifiers));
}
- public virtual void ReportDiagnosticsIfObsolete(Binder binder, SyntaxNode syntax, DiagnosticBag diagnostics)
+ public void ReportDiagnosticsIfObsolete(Binder binder, SyntaxNode syntax, DiagnosticBag diagnostics) =>
+ _extensions.ReportDiagnosticsIfObsolete(this, binder, syntax, diagnostics);
+
+ internal bool TypeSymbolEqualsCore(TypeSymbolWithAnnotations other, TypeCompareKind comparison)
+ {
+ return TypeSymbol.Equals(other.TypeSymbol, comparison);
+ }
+
+ internal void ReportDiagnosticsIfObsoleteCore(Binder binder, SyntaxNode syntax, DiagnosticBag diagnostics)
{
binder.ReportDiagnosticsIfObsolete(diagnostics, TypeSymbol, syntax, hasBaseReceiver: false);
}
@@ -416,24 +551,15 @@ public virtual void ReportDiagnosticsIfObsolete(Binder binder, SyntaxNode syntax
/// Extract type under assumption that there should be no custom modifiers or annotations.
/// The method asserts otherwise.
///
- public abstract TypeSymbol AsTypeSymbolOnly();
+ public TypeSymbol AsTypeSymbolOnly() => _extensions.AsTypeSymbolOnly(_defaultType);
///
/// Is this the given type parameter?
///
- public abstract bool Is(TypeParameterSymbol other);
+ public bool Is(TypeParameterSymbol other) => _extensions.Is(_defaultType, other);
- public TypeSymbolWithAnnotations WithTypeAndModifiers(TypeSymbol typeSymbol, ImmutableArray customModifiers)
- {
- // PROTOTYPE(NullableReferenceTypes): This method can cause cycles, since it pulls on NonNullTypes
- // Once TypeSymbolWithAnnotations is a struct, we can probably skip this optimization altogether
- //if (CustomModifiers != customModifiers || !TypeSymbol.Equals(typeSymbol, TypeCompareKind.AllAspects))
- //{
- // return DoUpdate(typeSymbol, customModifiers);
- //}
-
- return new NonLazyType(typeSymbol, NonNullTypesContext, isAnnotated: IsAnnotated, customModifiers);
- }
+ public TypeSymbolWithAnnotations WithTypeAndModifiers(TypeSymbol typeSymbol, ImmutableArray customModifiers) =>
+ _extensions.WithTypeAndModifiers(this, typeSymbol, customModifiers);
public bool ContainsNullableReferenceTypes()
{
@@ -552,7 +678,7 @@ public TypeSymbolWithAnnotations WithTopLevelNonNullabilityForReferenceTypes()
return this;
}
- return new NonLazyType(typeSymbol, NonNullTypesTrueContext.Instance, isAnnotated: false, CustomModifiers);
+ return CreateNonLazyType(typeSymbol, NonNullTypesTrueContext.Instance, isAnnotated: false, CustomModifiers);
}
public TypeSymbolWithAnnotations SetUnknownNullabilityForReferenceTypes()
@@ -564,7 +690,7 @@ public TypeSymbolWithAnnotations SetUnknownNullabilityForReferenceTypes()
if (!typeSymbol.IsValueType)
{
typeSymbol = typeSymbol.SetUnknownNullabilityForReferenceTypes();
- return new NonLazyType(typeSymbol, NonNullTypesFalseContext.Instance, isAnnotated: false, CustomModifiers);
+ return CreateNonLazyType(typeSymbol, NonNullTypesFalseContext.Instance, isAnnotated: false, CustomModifiers);
}
}
@@ -580,7 +706,7 @@ public TypeSymbolWithAnnotations SetUnknownNullabilityForReferenceTypes()
#pragma warning disable CS0809
[Obsolete("Unsupported", error: true)]
- public sealed override bool Equals(object other)
+ public override bool Equals(object other)
#pragma warning restore CS0809
{
throw ExceptionUtilities.Unreachable;
@@ -588,146 +714,175 @@ public sealed override bool Equals(object other)
#pragma warning disable CS0809
[Obsolete("Unsupported", error: true)]
- public sealed override int GetHashCode()
+ public override int GetHashCode()
#pragma warning restore CS0809
{
throw ExceptionUtilities.Unreachable;
}
+#pragma warning disable CS0809
[Obsolete("Unsupported", error: true)]
- public static bool operator ==(TypeSymbolWithAnnotations x, TypeSymbolWithAnnotations y)
+ public static bool operator ==(TypeSymbolWithAnnotations? x, TypeSymbolWithAnnotations? y)
+#pragma warning restore CS0809
{
throw ExceptionUtilities.Unreachable;
}
+#pragma warning disable CS0809
[Obsolete("Unsupported", error: true)]
- public static bool operator !=(TypeSymbolWithAnnotations x, TypeSymbolWithAnnotations y)
+ public static bool operator !=(TypeSymbolWithAnnotations? x, TypeSymbolWithAnnotations? y)
+#pragma warning restore CS0809
{
throw ExceptionUtilities.Unreachable;
}
- [Obsolete("Unsupported", error: true)]
- public static bool operator ==(Symbol x, TypeSymbolWithAnnotations y)
+ // Field-wise ReferenceEquals.
+ internal bool IsSameAs(TypeSymbolWithAnnotations other)
{
- throw ExceptionUtilities.Unreachable;
+ return ReferenceEquals(_defaultType, other._defaultType) &&
+ ReferenceEquals(NonNullTypesContext, other.NonNullTypesContext) &&
+ IsAnnotated == other.IsAnnotated &&
+ ReferenceEquals(_extensions, other._extensions);
}
- [Obsolete("Unsupported", error: true)]
- public static bool operator !=(Symbol x, TypeSymbolWithAnnotations y)
+ ///
+ /// Additional data or behavior beyond the core TypeSymbolWithAnnotations.
+ ///
+ private abstract class Extensions
{
- throw ExceptionUtilities.Unreachable;
- }
+ internal static readonly Extensions Default = new NonLazyType(ImmutableArray.Empty);
- [Obsolete("Unsupported", error: true)]
- public static bool operator ==(TypeSymbolWithAnnotations x, Symbol y)
- {
- throw ExceptionUtilities.Unreachable;
- }
+ internal static Extensions Create(ImmutableArray customModifiers)
+ {
+ if (customModifiers.IsEmpty)
+ {
+ return Default;
+ }
+ return new NonLazyType(customModifiers);
+ }
- [Obsolete("Unsupported", error: true)]
- public static bool operator !=(TypeSymbolWithAnnotations x, Symbol y)
- {
- throw ExceptionUtilities.Unreachable;
+ internal static Extensions CreateLazy(CSharpCompilation compilation, TypeSymbolWithAnnotations underlying)
+ {
+ return new LazyNullableTypeParameter(compilation, underlying);
+ }
+
+ internal abstract TypeSymbol GetResolvedType(TypeSymbol defaultType);
+ internal abstract ImmutableArray CustomModifiers { get; }
+
+ internal abstract TypeSymbolWithAnnotations AsNullableReferenceType(TypeSymbolWithAnnotations type);
+ internal abstract TypeSymbolWithAnnotations AsNotNullableReferenceType(TypeSymbolWithAnnotations type);
+
+ internal abstract TypeSymbolWithAnnotations WithModifiers(TypeSymbolWithAnnotations type, ImmutableArray customModifiers);
+ internal abstract TypeSymbolWithAnnotations WithNonNullTypesContext(TypeSymbolWithAnnotations type, INonNullTypesContext nonNullTypesContext);
+
+ internal abstract TypeSymbol GetNullableUnderlyingTypeOrSelf(TypeSymbol typeSymbol);
+
+ internal abstract bool GetIsReferenceType(TypeSymbol typeSymbol, ConsList inProgress);
+ internal abstract bool GetIsValueType(TypeSymbol typeSymbol, ConsList inProgress);
+
+ internal abstract TypeSymbol AsTypeSymbolOnly(TypeSymbol typeSymbol);
+
+ internal abstract SpecialType GetSpecialType(TypeSymbol typeSymbol);
+ internal abstract bool IsRestrictedType(TypeSymbol typeSymbol, bool ignoreSpanLikeTypes);
+ internal abstract bool IsStatic(TypeSymbol typeSymbol);
+ internal abstract bool IsVoid(TypeSymbol typeSymbol);
+ internal abstract bool IsSZArray(TypeSymbol typeSymbol);
+
+ internal abstract bool Is(TypeSymbol typeSymbol, TypeParameterSymbol other);
+
+ internal abstract TypeSymbolWithAnnotations WithTypeAndModifiers(TypeSymbolWithAnnotations type, TypeSymbol typeSymbol, ImmutableArray customModifiers);
+
+ internal abstract bool TypeSymbolEquals(TypeSymbolWithAnnotations type, TypeSymbolWithAnnotations other, TypeCompareKind comparison);
+ internal abstract TypeSymbolWithAnnotations SubstituteType(TypeSymbolWithAnnotations type, AbstractTypeMap typeMap, bool withTupleUnification);
+ internal abstract void ReportDiagnosticsIfObsolete(TypeSymbolWithAnnotations type, Binder binder, SyntaxNode syntax, DiagnosticBag diagnostics);
}
- private sealed class NonLazyType : TypeSymbolWithAnnotations
+ private sealed class NonLazyType : Extensions
{
- private readonly TypeSymbol _typeSymbol;
- private readonly bool _isAnnotated;
private readonly ImmutableArray _customModifiers;
- private readonly INonNullTypesContext _nonNullTypesContext;
- public NonLazyType(TypeSymbol typeSymbol, INonNullTypesContext nonNullTypesContext, bool isAnnotated, ImmutableArray customModifiers)
+ public NonLazyType(ImmutableArray customModifiers)
{
- Debug.Assert((object)typeSymbol != null);
Debug.Assert(!customModifiers.IsDefault);
- Debug.Assert(!typeSymbol.IsNullableType() || isAnnotated);
- Debug.Assert(nonNullTypesContext != null);
-
- _typeSymbol = typeSymbol;
- _nonNullTypesContext = nonNullTypesContext;
- _isAnnotated = isAnnotated;
_customModifiers = customModifiers;
}
- public override TypeSymbol TypeSymbol => _typeSymbol;
+ internal override TypeSymbol GetResolvedType(TypeSymbol defaultType) => defaultType;
+ internal override ImmutableArray CustomModifiers => _customModifiers;
- // PROTOTYPE(NullableReferenceTypes): IsNullable depends on IsValueType which
- // can lead to cycles when IsNullable is queried early. Replace this property with
- // the Annotation property that depends on IsAnnotated and NonNullTypes only.
- public override bool? IsNullable
- {
- get
- {
- if (_isAnnotated)
- {
- return true;
- }
- if (NonNullTypesContext.NonNullTypes == true)
- {
- return false;
- }
- if (_typeSymbol.IsValueType)
- {
- return false;
- }
- return null;
- }
- }
+ internal override SpecialType GetSpecialType(TypeSymbol typeSymbol) => typeSymbol.SpecialType;
+ internal override bool IsRestrictedType(TypeSymbol typeSymbol, bool ignoreSpanLikeTypes) => typeSymbol.IsRestrictedType(ignoreSpanLikeTypes);
+ internal override bool IsStatic(TypeSymbol typeSymbol) => typeSymbol.IsStatic;
+ internal override bool IsVoid(TypeSymbol typeSymbol) => typeSymbol.SpecialType == SpecialType.System_Void;
+ internal override bool IsSZArray(TypeSymbol typeSymbol) => typeSymbol.IsSZArray();
- public override bool IsAnnotated => _isAnnotated;
- public override ImmutableArray CustomModifiers => _customModifiers;
- public override INonNullTypesContext NonNullTypesContext => _nonNullTypesContext;
+ internal override TypeSymbol GetNullableUnderlyingTypeOrSelf(TypeSymbol typeSymbol) => typeSymbol.StrippedType();
- internal override bool GetIsReferenceType(ConsList inProgress)
+ internal override bool GetIsReferenceType(TypeSymbol typeSymbol, ConsList inProgress)
{
- if (_typeSymbol.TypeKind == TypeKind.TypeParameter)
+ if (typeSymbol.TypeKind == TypeKind.TypeParameter)
{
- return ((TypeParameterSymbol)_typeSymbol).GetIsReferenceType(inProgress);
+ return ((TypeParameterSymbol)typeSymbol).GetIsReferenceType(inProgress);
}
- return _typeSymbol.IsReferenceType;
+ return typeSymbol.IsReferenceType;
}
- internal override bool GetIsValueType(ConsList inProgress)
+ internal override bool GetIsValueType(TypeSymbol typeSymbol, ConsList inProgress)
{
- if (_typeSymbol.TypeKind == TypeKind.TypeParameter)
+ if (typeSymbol.TypeKind == TypeKind.TypeParameter)
{
- return ((TypeParameterSymbol)_typeSymbol).GetIsValueType(inProgress);
+ return ((TypeParameterSymbol)typeSymbol).GetIsValueType(inProgress);
}
- return _typeSymbol.IsValueType;
+ return typeSymbol.IsValueType;
}
- public override TypeSymbolWithAnnotations WithModifiers(ImmutableArray customModifiers)
+ internal override TypeSymbolWithAnnotations WithModifiers(TypeSymbolWithAnnotations type, ImmutableArray customModifiers)
{
- return new NonLazyType(_typeSymbol, NonNullTypesContext, _isAnnotated, customModifiers);
+ return TypeSymbolWithAnnotations.CreateNonLazyType(type._defaultType, type.NonNullTypesContext, type.IsAnnotated, customModifiers);
}
- public override TypeSymbolWithAnnotations WithNonNullTypesContext(INonNullTypesContext nonNullTypesContext)
+ internal override TypeSymbolWithAnnotations WithNonNullTypesContext(TypeSymbolWithAnnotations type, INonNullTypesContext nonNullTypesContext)
{
Debug.Assert(nonNullTypesContext != null);
- return NonNullTypesContext == nonNullTypesContext ?
- this :
- new NonLazyType(_typeSymbol, nonNullTypesContext, _isAnnotated, _customModifiers);
+ return TypeSymbolWithAnnotations.CreateNonLazyType(type._defaultType, nonNullTypesContext, type.IsAnnotated, _customModifiers);
}
- public override TypeSymbol AsTypeSymbolOnly() => _typeSymbol;
+ internal override TypeSymbol AsTypeSymbolOnly(TypeSymbol typeSymbol) => typeSymbol;
// PROTOTYPE(NullableReferenceTypes): Use WithCustomModifiers.Is() => false
// and set IsNullable=null always for GetTypeParametersAsTypeArguments.
- public override bool Is(TypeParameterSymbol other) => _typeSymbol.Equals(other, TypeCompareKind.CompareNullableModifiersForReferenceTypes) && _customModifiers.IsEmpty;
+ internal override bool Is(TypeSymbol typeSymbol, TypeParameterSymbol other) =>
+ typeSymbol.Equals(other, TypeCompareKind.CompareNullableModifiersForReferenceTypes) && _customModifiers.IsEmpty;
+
+ internal override TypeSymbolWithAnnotations WithTypeAndModifiers(TypeSymbolWithAnnotations type, TypeSymbol typeSymbol, ImmutableArray customModifiers)
+ {
+ return TypeSymbolWithAnnotations.CreateNonLazyType(typeSymbol, type.NonNullTypesContext, type.IsAnnotated, customModifiers);
+ }
+
+ internal override TypeSymbolWithAnnotations AsNullableReferenceType(TypeSymbolWithAnnotations type)
+ {
+ return TypeSymbolWithAnnotations.CreateNonLazyType(type._defaultType, type.NonNullTypesContext, isAnnotated: true, _customModifiers);
+ }
+
+ internal override TypeSymbolWithAnnotations AsNotNullableReferenceType(TypeSymbolWithAnnotations type)
+ {
+ var defaultType = type._defaultType;
+ return TypeSymbolWithAnnotations.CreateNonLazyType(defaultType, type.NonNullTypesContext, isAnnotated: defaultType.IsNullableType(), _customModifiers);
+ }
+
+ internal override bool TypeSymbolEquals(TypeSymbolWithAnnotations type, TypeSymbolWithAnnotations other, TypeCompareKind comparison)
+ {
+ return type.TypeSymbolEqualsCore(other, comparison);
+ }
- public override TypeSymbolWithAnnotations AsNullableReferenceType()
+ internal override TypeSymbolWithAnnotations SubstituteType(TypeSymbolWithAnnotations type, AbstractTypeMap typeMap, bool withTupleUnification)
{
- return _isAnnotated ?
- this :
- new NonLazyType(_typeSymbol, NonNullTypesContext, isAnnotated: true, _customModifiers);
+ return type.SubstituteTypeCore(typeMap, withTupleUnification);
}
- public override TypeSymbolWithAnnotations AsNotNullableReferenceType()
+ internal override void ReportDiagnosticsIfObsolete(TypeSymbolWithAnnotations type, Binder binder, SyntaxNode syntax, DiagnosticBag diagnostics)
{
- return !_isAnnotated || _typeSymbol.IsNullableType() ?
- this :
- new NonLazyType(_typeSymbol, NonNullTypesContext, isAnnotated: false, _customModifiers);
+ type.ReportDiagnosticsIfObsoleteCore(binder, syntax, diagnostics);
}
}
@@ -735,7 +890,7 @@ public override TypeSymbolWithAnnotations AsNotNullableReferenceType()
/// Nullable type parameter. The underlying TypeSymbol is resolved
/// lazily to avoid cycles when binding declarations.
///
- private sealed class LazyNullableTypeParameter : TypeSymbolWithAnnotations
+ private sealed class LazyNullableTypeParameter : Extensions
{
private readonly CSharpCompilation _compilation;
private readonly TypeSymbolWithAnnotations _underlying;
@@ -751,154 +906,164 @@ public LazyNullableTypeParameter(CSharpCompilation compilation, TypeSymbolWithAn
_underlying = underlying;
}
- public override bool? IsNullable => true;
- public override bool IsAnnotated => true;
- public override INonNullTypesContext NonNullTypesContext => _underlying.NonNullTypesContext;
- public override bool IsVoid => false;
- public override bool IsSZArray() => false;
- public override bool IsStatic => false;
+ internal override bool IsVoid(TypeSymbol typeSymbol) => false;
+ internal override bool IsSZArray(TypeSymbol typeSymbol) => false;
+ internal override bool IsStatic(TypeSymbol typeSymbol) => false;
- public override TypeSymbol TypeSymbol
+ private TypeSymbol GetResolvedType()
{
- get
+ if ((object)_resolved == null)
{
- if ((object)_resolved == null)
+ if (!_underlying.IsValueType)
{
- if (!_underlying.IsValueType)
- {
- _resolved = _underlying.TypeSymbol;
- }
- else
- {
- Interlocked.CompareExchange(ref _resolved,
- _compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(ImmutableArray.Create(_underlying)),
- null);
- }
+ _resolved = _underlying.TypeSymbol;
+ }
+ else
+ {
+ Interlocked.CompareExchange(ref _resolved,
+ _compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(ImmutableArray.Create(_underlying)),
+ null);
}
-
- return _resolved;
}
+
+ return _resolved;
}
- internal override bool GetIsReferenceType(ConsList inProgress)
+ internal override bool GetIsReferenceType(TypeSymbol typeSymbol, ConsList inProgress)
{
return _underlying.GetIsReferenceType(inProgress);
}
- internal override bool GetIsValueType(ConsList inProgress)
+ internal override bool GetIsValueType(TypeSymbol typeSymbol, ConsList inProgress)
{
return _underlying.GetIsValueType(inProgress);
}
- public override TypeSymbol NullableUnderlyingTypeOrSelf => _underlying.TypeSymbol;
+ internal override TypeSymbol GetNullableUnderlyingTypeOrSelf(TypeSymbol typeSymbol) => _underlying.TypeSymbol;
- public override SpecialType SpecialType => SpecialType.None;
+ internal override SpecialType GetSpecialType(TypeSymbol typeSymbol)
+ {
+ var specialType = _underlying.SpecialType;
+ return specialType.IsValueType() ? SpecialType.None : specialType;
+ }
- public override bool IsRestrictedType(bool ignoreSpanLikeTypes) => false;
+ internal override bool IsRestrictedType(TypeSymbol typeSymbol, bool ignoreSpanLikeTypes) => _underlying.IsRestrictedType(ignoreSpanLikeTypes);
- public override TypeSymbol AsTypeSymbolOnly()
+ internal override TypeSymbol AsTypeSymbolOnly(TypeSymbol typeSymbol)
{
- Debug.Assert(TypeSymbol.IsNullableType() && CustomModifiers.IsEmpty);
- return TypeSymbol;
+ var resolvedType = GetResolvedType();
+ Debug.Assert(resolvedType.IsNullableType() && CustomModifiers.IsEmpty);
+ return resolvedType;
}
// PROTOTYPE(NullableReferenceTypes): This implementation looks
// incorrect since a type parameter cannot be Nullable.
- public override bool Is(TypeParameterSymbol other)
+ internal override bool Is(TypeSymbol typeSymbol, TypeParameterSymbol other)
{
if (!other.IsNullableType())
{
return false;
}
- return TypeSymbol.Equals(other, TypeCompareKind.CompareNullableModifiersForReferenceTypes);
+ var resolvedType = GetResolvedType();
+ return resolvedType.Equals(other, TypeCompareKind.CompareNullableModifiersForReferenceTypes);
}
- public override ImmutableArray CustomModifiers => ImmutableArray.Empty;
+ internal override TypeSymbol GetResolvedType(TypeSymbol defaultType) => GetResolvedType();
+ internal override ImmutableArray CustomModifiers => ImmutableArray.Empty;
- public override TypeSymbolWithAnnotations WithModifiers(ImmutableArray customModifiers)
+ internal override TypeSymbolWithAnnotations WithModifiers(TypeSymbolWithAnnotations type, ImmutableArray customModifiers)
{
- if (customModifiers.IsDefaultOrEmpty)
+ if (customModifiers.IsEmpty)
{
- return this;
+ return type;
}
- // It should be safe to force resolution
- var typeSymbol = TypeSymbol;
+ var resolvedType = GetResolvedType();
+ if (resolvedType.IsNullableType())
+ {
+ return TypeSymbolWithAnnotations.Create(resolvedType, customModifiers);
+ }
+
+ return TypeSymbolWithAnnotations.CreateNonLazyType(resolvedType, type.NonNullTypesContext, isAnnotated: true, customModifiers);
+ }
+
+ internal override TypeSymbolWithAnnotations WithNonNullTypesContext(TypeSymbolWithAnnotations type, INonNullTypesContext nonNullTypesContext)
+ {
+ return TypeSymbolWithAnnotations.CreateLazyNullableType(_compilation, _underlying.WithNonNullTypesContext(nonNullTypesContext));
+ }
+
+ internal override TypeSymbolWithAnnotations WithTypeAndModifiers(TypeSymbolWithAnnotations type, TypeSymbol typeSymbol, ImmutableArray customModifiers)
+ {
if (typeSymbol.IsNullableType())
{
return TypeSymbolWithAnnotations.Create(typeSymbol, customModifiers);
}
- return new NonLazyType(typeSymbol, NonNullTypesContext, isAnnotated: IsAnnotated, customModifiers);
+ return TypeSymbolWithAnnotations.CreateNonLazyType(typeSymbol, type.NonNullTypesContext, isAnnotated: true, customModifiers);
}
- public override TypeSymbolWithAnnotations WithNonNullTypesContext(INonNullTypesContext nonNullTypesContext)
+ internal override TypeSymbolWithAnnotations AsNullableReferenceType(TypeSymbolWithAnnotations type)
{
- return _underlying.NonNullTypesContext == nonNullTypesContext ?
- this :
- new LazyNullableTypeParameter(_compilation, _underlying.WithNonNullTypesContext(nonNullTypesContext));
+ return type;
}
- public override TypeSymbolWithAnnotations AsNullableReferenceType() => this;
-
- public override TypeSymbolWithAnnotations AsNotNullableReferenceType()
+ internal override TypeSymbolWithAnnotations AsNotNullableReferenceType(TypeSymbolWithAnnotations type)
{
if (!_underlying.TypeSymbol.IsValueType)
{
return _underlying;
}
-
- return this;
+ return type;
}
- protected override TypeSymbolWithAnnotations SubstituteType(AbstractTypeMap typeMap, bool withTupleUnification)
+ internal override TypeSymbolWithAnnotations SubstituteType(TypeSymbolWithAnnotations type, AbstractTypeMap typeMap, bool withTupleUnification)
{
if ((object)_resolved != null)
{
- return base.SubstituteType(typeMap, withTupleUnification);
+ return type.SubstituteTypeCore(typeMap, withTupleUnification);
}
- var newUnderlying = _underlying.SubstituteType(typeMap, withTupleUnification);
- if ((object)newUnderlying != this._underlying)
+ var newUnderlying = _underlying.SubstituteTypeCore(typeMap, withTupleUnification);
+ if (!newUnderlying.IsSameAs(this._underlying))
{
- if ((newUnderlying.TypeSymbol.Equals(this._underlying.TypeSymbol, TypeCompareKind.AllAspects) ||
+ if ((newUnderlying.TypeSymbol.Equals(this._underlying.TypeSymbol, TypeCompareKind.AllAspects) ||
newUnderlying.TypeSymbol is IndexedTypeParameterSymbolForOverriding) &&
newUnderlying.CustomModifiers.IsEmpty)
{
- return new LazyNullableTypeParameter(_compilation, newUnderlying);
+ return TypeSymbolWithAnnotations.CreateLazyNullableType(_compilation, newUnderlying);
}
- return base.SubstituteType(typeMap, withTupleUnification);
+ return type.SubstituteTypeCore(typeMap, withTupleUnification);
}
else
{
- return this; // substitution had no effect on the type or modifiers
+ return type; // substitution had no effect on the type or modifiers
}
}
- public override void ReportDiagnosticsIfObsolete(Binder binder, SyntaxNode syntax, DiagnosticBag diagnostics)
+ internal override void ReportDiagnosticsIfObsolete(TypeSymbolWithAnnotations type, Binder binder, SyntaxNode syntax, DiagnosticBag diagnostics)
{
if ((object)_resolved != null)
{
- base.ReportDiagnosticsIfObsolete(binder, syntax, diagnostics);
+ type.ReportDiagnosticsIfObsoleteCore(binder, syntax, diagnostics);
}
else
{
- diagnostics.Add(new LazyObsoleteDiagnosticInfo(this, binder.ContainingMemberOrLambda, binder.Flags), syntax.GetLocation());
+ diagnostics.Add(new LazyObsoleteDiagnosticInfo(type, binder.ContainingMemberOrLambda, binder.Flags), syntax.GetLocation());
}
}
- protected override bool TypeSymbolEquals(TypeSymbolWithAnnotations other, TypeCompareKind comparison)
+ internal override bool TypeSymbolEquals(TypeSymbolWithAnnotations type, TypeSymbolWithAnnotations other, TypeCompareKind comparison)
{
- var otherLazy = other as LazyNullableTypeParameter;
+ var otherLazy = other._extensions as LazyNullableTypeParameter;
if ((object)otherLazy != null)
{
return _underlying.TypeSymbolEquals(otherLazy._underlying, comparison);
}
- return base.TypeSymbolEquals(other, comparison);
+ return type.TypeSymbolEqualsCore(other, comparison);
}
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs
index c56cf61408e24..4d46e41d581f0 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedParameterSymbol.cs
@@ -28,7 +28,7 @@ public SynthesizedParameterSymbolBase(
RefKind refKind,
string name = "")
{
- Debug.Assert((object)type != null);
+ Debug.Assert(!type.IsNull);
Debug.Assert(name != null);
Debug.Assert(ordinal >= 0);
diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/TypeSubstitutedLocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/TypeSubstitutedLocalSymbol.cs
index f2305b14b17ef..ab8f8ee69d259 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/TypeSubstitutedLocalSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/TypeSubstitutedLocalSymbol.cs
@@ -15,7 +15,7 @@ internal sealed class TypeSubstitutedLocalSymbol : LocalSymbol
public TypeSubstitutedLocalSymbol(LocalSymbol originalVariable, TypeSymbolWithAnnotations type, Symbol containingSymbol)
{
Debug.Assert(originalVariable != null);
- Debug.Assert((object)type != null);
+ Debug.Assert(!type.IsNull);
Debug.Assert(containingSymbol != null);
_originalVariable = originalVariable;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs
index 1db89d1d926a7..c8709b9a42495 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs
@@ -219,7 +219,7 @@ internal TupleTypeSymbol WithUnderlyingType(NamedTypeSymbol newUnderlyingType)
internal TupleTypeSymbol WithElementTypes(ImmutableArray newElementTypes)
{
Debug.Assert(_elementTypes.Length == newElementTypes.Length);
- Debug.Assert(newElementTypes.All(t => (object)t != null));
+ Debug.Assert(newElementTypes.All(t => !t.IsNull));
NamedTypeSymbol firstTupleType;
NamedTypeSymbol chainedTupleType;
diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs
index d46dfafa4bd91..03d3804b1d9fa 100644
--- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs
@@ -624,12 +624,12 @@ public virtual NamedTypeSymbol TupleUnderlyingType
internal bool ContainsNullableReferenceTypes()
{
- return TypeSymbolWithAnnotations.ContainsNullableReferenceTypes(typeWithAnnotationsOpt: null, typeOpt: this);
+ return TypeSymbolWithAnnotations.ContainsNullableReferenceTypes(typeWithAnnotationsOpt: default, typeOpt: this);
}
internal bool ContainsAnnotatedUnconstrainedTypeParameter()
{
- return TypeSymbolWithAnnotations.ContainsAnnotatedUnconstrainedTypeParameter(typeWithAnnotationsOpt: null, typeOpt: this);
+ return TypeSymbolWithAnnotations.ContainsAnnotatedUnconstrainedTypeParameter(typeWithAnnotationsOpt: default, typeOpt: this);
}
internal abstract void AddNullableTransforms(ArrayBuilder transforms);
diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs
index 6b9e8273c4010..f52f25dbf05eb 100644
--- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs
@@ -545,7 +545,7 @@ public static TypeSymbol VisitType(
bool canDigThroughNullable = false)
{
return VisitType(
- typeWithAnnotationsOpt: null,
+ typeWithAnnotationsOpt: default,
typeOpt: type,
typeWithAnnotationsPredicateOpt: null,
typePredicateOpt: predicate,
@@ -572,7 +572,7 @@ public static TypeSymbol VisitType(
T arg,
bool canDigThroughNullable = false)
{
- Debug.Assert((typeWithAnnotationsOpt is null) != (typeOpt is null));
+ Debug.Assert(typeWithAnnotationsOpt.IsNull != (typeOpt is null));
// In order to handle extremely "deep" types like "int[][][][][][][][][]...[]"
// or int*****************...* we implement manual tail recursion rather than
@@ -580,7 +580,7 @@ public static TypeSymbol VisitType(
while (true)
{
- TypeSymbol current = typeOpt ?? typeWithAnnotationsOpt?.TypeSymbol;
+ TypeSymbol current = typeOpt ?? typeWithAnnotationsOpt.TypeSymbol;
bool isNestedNamedType = false;
// Visit containing types from outer-most to inner-most.
@@ -596,7 +596,7 @@ public static TypeSymbol VisitType(
if ((object)containingType != null)
{
isNestedNamedType = true;
- var result = VisitType(null, containingType, typeWithAnnotationsPredicateOpt, typePredicateOpt, arg, canDigThroughNullable);
+ var result = VisitType(default, containingType, typeWithAnnotationsPredicateOpt, typePredicateOpt, arg, canDigThroughNullable);
if ((object)result != null)
{
return result;
@@ -610,7 +610,7 @@ public static TypeSymbol VisitType(
break;
}
- if ((object)typeWithAnnotationsOpt != null && typeWithAnnotationsPredicateOpt != null)
+ if (!typeWithAnnotationsOpt.IsNull && typeWithAnnotationsPredicateOpt != null)
{
if (typeWithAnnotationsPredicateOpt(typeWithAnnotationsOpt, arg, isNestedNamedType))
{
@@ -650,7 +650,7 @@ public static TypeSymbol VisitType(
{
// Let's try to avoid early resolution of nullable types
var result = VisitType(
- typeWithAnnotationsOpt: canDigThroughNullable ? null : typeArg,
+ typeWithAnnotationsOpt: canDigThroughNullable ? default : typeArg,
typeOpt: canDigThroughNullable ? typeArg.NullableUnderlyingTypeOrSelf : null,
typeWithAnnotationsPredicateOpt,
typePredicateOpt,
@@ -676,7 +676,7 @@ public static TypeSymbol VisitType(
}
// Let's try to avoid early resolution of nullable types
- typeWithAnnotationsOpt = canDigThroughNullable ? null : next;
+ typeWithAnnotationsOpt = canDigThroughNullable ? default : next;
typeOpt = canDigThroughNullable ? next.NullableUnderlyingTypeOrSelf : null;
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeUnification.cs b/src/Compilers/CSharp/Portable/Symbols/TypeUnification.cs
index 0a6201bd65198..9249b1ae70e5f 100644
--- a/src/Compilers/CSharp/Portable/Symbols/TypeUnification.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/TypeUnification.cs
@@ -21,8 +21,8 @@ public static bool CanUnify(TypeSymbol t1, TypeSymbol t2)
}
MutableTypeMap substitution = null;
- bool result = CanUnifyHelper((object)t1 == null ? null : TypeSymbolWithAnnotations.Create(t1),
- (object)t2 == null ? null : TypeSymbolWithAnnotations.Create(t2),
+ bool result = CanUnifyHelper(TypeSymbolWithAnnotations.Create(t1),
+ TypeSymbolWithAnnotations.Create(t2),
ref substitution);
#if DEBUG
if (result && ((object)t1 != null && (object)t2 != null))
@@ -47,7 +47,7 @@ private static TypeSymbolWithAnnotations SubstituteAllTypeParameters(AbstractTyp
{
previous = type;
type = type.SubstituteType(substitution);
- } while ((object)type != previous);
+ } while (!type.IsSameAs(previous));
}
return type;
@@ -73,9 +73,9 @@ private static TypeSymbolWithAnnotations SubstituteAllTypeParameters(AbstractTyp
///
private static bool CanUnifyHelper(TypeSymbolWithAnnotations t1, TypeSymbolWithAnnotations t2, ref MutableTypeMap substitution)
{
- if ((object)t1 == null || (object)t2 == null)
+ if (t1.IsNull || t2.IsNull)
{
- return (object)t1 == t2;
+ return t1.IsSameAs(t2);
}
if (t1.TypeSymbol == t2.TypeSymbol && t1.CustomModifiers.SequenceEqual(t2.CustomModifiers))
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
index 4390fde73555f..991b8899b1784 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
@@ -9050,6 +9050,16 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference
Converting null literal or possible null value to non-nullable type.
+
+
+ The type '{3}' cannot be used as type parameter '{2}' in the generic type or method '{0}'. Nullability of type argument '{3}' doesn't match constraint type '{1}'.
+
+
+
+
+ The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match constraint type.
+
+