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..d4e0a02129e35 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); } 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 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..b6ac63dcfe9a3 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs @@ -2229,7 +2229,7 @@ private bool ExpressionMatchExactly(BoundExpression node, TypeSymbol t, ref Hash // - an inferred return type X exists for E in the context of the parameter list of D(ยง7.5.2.12), and an identity conversion exists from X to Y var x = lambda.GetInferredReturnType(ref useSiteDiagnostics); - if ((object)x != null && Conversions.HasIdentityConversion(x.TypeSymbol, y)) + if (!x.IsNull && Conversions.HasIdentityConversion(x.TypeSymbol, y)) { return true; } @@ -2654,7 +2654,7 @@ private bool CanDowngradeConversionFromLambdaToNeither(BetterResult currentResul } var x = lambda.InferReturnType(d1, ref useSiteDiagnostics); - if ((object)x == null) + if (x.IsNull) { return true; } diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundDiscardExpression.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundDiscardExpression.cs index 229f963525061..50e6826521503 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundDiscardExpression.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundDiscardExpression.cs @@ -9,7 +9,7 @@ internal partial class BoundDiscardExpression { public BoundExpression SetInferredType(TypeSymbolWithAnnotations type) { - Debug.Assert((object)Type == null && (object)type != null); + Debug.Assert((object)Type == null && !type.IsNull); // PROTOTYPE(NullableReferenceTypes): we're dropping the annotation return this.Update(type.TypeSymbol); } diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs index 97a35dc9730da..ef518ab55e0f1 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundExpressionExtensions.cs @@ -214,7 +214,7 @@ internal static TypeSymbolWithAnnotations GetTypeAndNullability(this BoundExpres var type = expr.Type; if ((object)type == null) { - return null; + return default; } // PROTOTYPE(NullableReferenceTypes): Could we track nullability always, // even in C#7, but only report warnings when the feature is enabled? @@ -250,7 +250,7 @@ internal static TypeSymbolWithAnnotations GetTypeAndNullability(this BoundExpres case BoundKind.Call: return ((BoundCall)expr).Method.ReturnType.IsNullable; case BoundKind.Conversion: - return ((BoundConversion)expr).ConversionGroupOpt?.ExplicitType?.IsNullable == true ? (bool?)true : null; + return ((BoundConversion)expr).ConversionGroupOpt?.ExplicitType.IsNullable == true ? (bool?)true : null; case BoundKind.BinaryOperator: return ((BoundBinaryOperator)expr).MethodOpt?.ReturnType.IsNullable; case BoundKind.NullCoalescingOperator: diff --git a/src/Compilers/CSharp/Portable/BoundTree/ConversionGroup.cs b/src/Compilers/CSharp/Portable/BoundTree/ConversionGroup.cs index 63b16d679f2df..aec1e38691576 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/ConversionGroup.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/ConversionGroup.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp [DebuggerDisplay("{GetDebuggerDisplay(), nq}")] internal sealed class ConversionGroup { - internal ConversionGroup(Conversion conversion, TypeSymbolWithAnnotations explicitType = null) + internal ConversionGroup(Conversion conversion, TypeSymbolWithAnnotations explicitType = default) { Conversion = conversion; ExplicitType = explicitType; @@ -22,7 +22,7 @@ internal ConversionGroup(Conversion conversion, TypeSymbolWithAnnotations explic /// /// 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..72d1386000a4b 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -110,7 +110,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/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 3b3e0bdf51173..ac888fbf0b182 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -488,7 +488,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; } @@ -516,7 +516,7 @@ private void ReportAssignmentWarnings(BoundExpression value, TypeSymbolWithAnnot if (this.State.Reachable) { - if (targetType is null || valueType is null) + if (targetType.IsNull || valueType.IsNull) { return; } @@ -536,7 +536,7 @@ private void TrackNullableStateForAssignment(BoundExpression value, TypeSymbolWi if (this.State.Reachable) { - if ((object)targetType == null) + if (targetType.IsNull) { return; } @@ -553,7 +553,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? @@ -571,7 +571,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) { @@ -580,7 +580,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()); } @@ -847,7 +847,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); } @@ -891,7 +891,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); @@ -905,7 +905,7 @@ protected override BoundNode VisitReturnStatementNoAdjust(BoundReturnStatement n if (!reportedNullable) { if (IsNullable(resultType) && (returnTypeIsNonNullable || returnTypeIsUnconstrainedTypeParameter) || - IsUnconstrainedTypeParameter(resultType?.TypeSymbol) && returnTypeIsNonNullable) + IsUnconstrainedTypeParameter(resultType.TypeSymbol) && returnTypeIsNonNullable) { ReportStaticNullCheckingDiagnostics(ErrorCode.WRN_NullReferenceReturn, node.ExpressionOpt.Syntax); } @@ -918,7 +918,7 @@ private TypeSymbolWithAnnotations GetReturnType() { var method = (MethodSymbol)_member; var returnType = (_useMethodSignatureReturnType ? _methodSignatureOpt : method).ReturnType; - Debug.Assert((object)returnType != LambdaSymbol.ReturnTypeIsBeingInferred); + Debug.Assert((object)returnType.TypeSymbol != LambdaSymbol.ReturnTypeIsBeingInferred); return method.IsGenericTaskReturningAsync(compilation) ? ((NamedTypeSymbol)returnType.TypeSymbol).TypeArgumentsNoUseSiteDiagnostics.Single() : returnType; @@ -926,12 +926,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) @@ -980,7 +980,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; @@ -996,7 +996,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); } } @@ -1012,8 +1012,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) { @@ -1282,19 +1282,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++) @@ -1302,7 +1305,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); @@ -1347,14 +1350,14 @@ public override BoundNode VisitArrayAccess(BoundArrayAccess node) Debug.Assert(node.Expression.Type.IsReferenceType); 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; } @@ -1385,8 +1388,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; @@ -1444,7 +1447,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) { @@ -1462,7 +1465,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 : @@ -1619,7 +1622,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); } @@ -1635,8 +1638,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: @@ -1665,7 +1668,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 @@ -1699,7 +1702,7 @@ public override BoundNode VisitConditionalAccess(BoundConditionalAccess node) if (receiver.Type?.IsReferenceType == true) { - if (receiverType?.IsNullable == false) + if (receiverType.IsNullable == false) { ReportStaticNullCheckingDiagnostics(ErrorCode.HDN_ExpressionIsProbablyNeverNull, receiver.Syntax); } @@ -1722,7 +1725,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; } @@ -1766,7 +1769,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node TypeSymbolWithAnnotations resultType; if (node.HasErrors) { - resultType = null; + resultType = default; } else { @@ -1785,23 +1788,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; } @@ -1814,7 +1817,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); } @@ -2268,7 +2271,7 @@ private void VisitArgumentConversion( TypeSymbolWithAnnotations parameterType, TypeSymbolWithAnnotations resultType) { - var argumentType = resultType?.TypeSymbol; + var argumentType = resultType.TypeSymbol; switch (refKind) { case RefKind.None: @@ -2395,7 +2398,7 @@ private static (ParameterSymbol Parameter, TypeSymbolWithAnnotations Type) GetCo { if (parameters.IsDefault) { - return (null, null); + return (default, default); } int n = parameters.Length; @@ -2434,7 +2437,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; @@ -2516,7 +2519,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; } @@ -2649,7 +2652,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; @@ -2735,20 +2738,20 @@ public override BoundNode VisitConversion(BoundConversion node) Visit(operand); TypeSymbolWithAnnotations operandType = _resultType; - TypeSymbolWithAnnotations explicitType = 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 _); + TypeSymbolWithAnnotations explicitType = node.ConversionGroupOpt?.ExplicitType ?? default; + 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; } @@ -2780,7 +2783,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)); } @@ -2909,7 +2912,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; @@ -2996,7 +2999,7 @@ private TypeSymbolWithAnnotations ApplyConversion( case ConversionKind.ExplicitDynamic: case ConversionKind.ImplicitDynamic: - isNullableIfReferenceType = operandType?.IsNullable; + isNullableIfReferenceType = operandType.IsNull ? null : operandType.IsNullable; break; case ConversionKind.Unboxing: @@ -3004,19 +3007,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 = true; } 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); @@ -3031,7 +3035,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; } @@ -3041,10 +3045,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; @@ -3105,7 +3109,7 @@ public override BoundNode VisitMethodGroup(BoundMethodGroup node) //if (this.State.Reachable) // PROTOTYPE(NullableReferenceTypes): Consider reachability? { - _resultType = null; + _resultType = default; } return null; @@ -3194,7 +3198,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? @@ -3325,7 +3329,7 @@ public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmen } else { - leftOnRightType = null; + leftOnRightType = default; } VisitRvalue(node.Right); @@ -3388,7 +3392,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) { @@ -3410,7 +3414,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); } @@ -3523,9 +3527,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; @@ -3579,7 +3583,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()) @@ -3595,7 +3599,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; } @@ -3648,7 +3652,7 @@ private TypeSymbolWithAnnotations InferResultNullability(BoundUserDefinedConditi } else { - return null; + return default; } } @@ -3764,9 +3768,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); + _resultType = TypeSymbolWithAnnotations.Create(node.Type, isNullableIfReferenceType: true); return result; } @@ -3813,7 +3815,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: @@ -3854,7 +3856,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; @@ -4048,7 +4050,7 @@ public override BoundNode VisitArrayInitialization(BoundArrayInitialization node private void SetUnknownResultNullability() { - _resultType = null; + _resultType = default; } public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation node) @@ -4081,12 +4083,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.IsReferenceType || receiverType.IsUnconstrainedTypeParameter()) && - (_resultType?.IsNullable == true || receiverType.IsUnconstrainedTypeParameter())) + (_resultType.IsNullable == true || receiverType.IsUnconstrainedTypeParameter())) { ReportStaticNullCheckingDiagnostics(ErrorCode.WRN_NullReferenceReceiver, receiverOpt.Syntax); } 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/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 d9f6c1b62f1e8..5bf9a5176cabb 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..b118131ad8773 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)); 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 e36cde76036eb..4083fb01c5321 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(), 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(); } - return new NonLazyType(typeSymbol, nonNullTypesContext, isAnnotated: 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/Test/Emit/CodeGen/CodeGenTupleTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs index ad5caf69e9e8b..533821bb99407 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs @@ -23011,7 +23011,7 @@ static void Main() var model = comp.GetSemanticModel(tree); var x = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); Assert.Equal("x", x.Identifier.ToString()); - var xSymbol = (model.GetDeclaredSymbol(x) as LocalSymbol)?.Type; + var xSymbol = ((LocalSymbol)model.GetDeclaredSymbol(x)).Type; Assert.Equal("(System.Int32 a, System.Int32 b)", xSymbol.ToTestDisplayString()); } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs index 0d6659e3003fc..df63ff966b3fd 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs @@ -159,7 +159,7 @@ interface IAsyncResult {} Assert.Equal("System.IAsyncResult", beginInvoke.ReturnType.TypeSymbol.ToTestDisplayString()); for (int i = 0; i < invoke.Parameters.Length; i++) { - Assert.Equal(invoke.Parameters[i].Type, beginInvoke.Parameters[i].Type); + Assert.Equal(invoke.Parameters[i].Type.TypeSymbol, beginInvoke.Parameters[i].Type.TypeSymbol); Assert.Equal(invoke.Parameters[i].RefKind, beginInvoke.Parameters[i].RefKind); } var lastParameterType = beginInvoke.Parameters[invoke.Parameters.Length].Type.TypeSymbol; @@ -168,13 +168,13 @@ interface IAsyncResult {} Assert.Equal("System.Object", beginInvoke.Parameters[invoke.Parameters.Length + 1].Type.TypeSymbol.ToTestDisplayString()); var endInvoke = myDel.GetMembers("EndInvoke").Single() as MethodSymbol; - Assert.Equal(invoke.ReturnType, endInvoke.ReturnType); + Assert.Equal(invoke.ReturnType.TypeSymbol, endInvoke.ReturnType.TypeSymbol); int k = 0; for (int i = 0; i < invoke.Parameters.Length; i++) { if (invoke.Parameters[i].RefKind != RefKind.None) { - Assert.Equal(invoke.Parameters[i].Type, endInvoke.Parameters[k].Type); + Assert.Equal(invoke.Parameters[i].Type.TypeSymbol, endInvoke.Parameters[k].Type.TypeSymbol); Assert.Equal(invoke.Parameters[i].RefKind, endInvoke.Parameters[k++].RefKind); } } diff --git a/src/Compilers/Test/Utilities/CSharp/UsesIsNullableVisitor.cs b/src/Compilers/Test/Utilities/CSharp/UsesIsNullableVisitor.cs index f32edcff56f9f..7a096f8f10e3a 100644 --- a/src/Compilers/Test/Utilities/CSharp/UsesIsNullableVisitor.cs +++ b/src/Compilers/Test/Utilities/CSharp/UsesIsNullableVisitor.cs @@ -122,7 +122,7 @@ private bool AddIfUsesIsNullable(Symbol symbol, TypeSymbolWithAnnotations type) private bool UsesIsNullable(TypeSymbolWithAnnotations type) { - if (type is null) + if (type.IsNull) { return false; } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs index b6c548718d456..b531c44b29216 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs @@ -1305,7 +1305,8 @@ private static void GetDisplayClassVariables( var name = local.Name; if ((name != null) && (GeneratedNames.GetKind(name) == GeneratedNameKind.DisplayClassLocalOrField)) { - if (displayClassTypes.Add(local.Type?.TypeSymbol)) + var localType = local.Type.TypeSymbol; + if ((object)localType != null && displayClassTypes.Add(localType)) { var instance = new DisplayClassInstanceFromLocal((EELocalSymbol)local); displayClassInstances.Add(new DisplayClassInstanceAndFields(instance));