diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs index f785cbbbdb51..f63813d3bbf0 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs @@ -1497,14 +1497,14 @@ internal SynthesizedAttributeData SynthesizeNullableAttribute(Symbol symbol, Typ type.AddNullableTransforms(flagsBuilder); Debug.Assert(flagsBuilder.Any()); - Debug.Assert(flagsBuilder.Contains((byte)NullableAnnotation.NotAnnotated) || flagsBuilder.Contains((byte)NullableAnnotation.Annotated)); + Debug.Assert(flagsBuilder.Contains(NullableAnnotationExtensions.NotAnnotatedAttributeValue) || flagsBuilder.Contains(NullableAnnotationExtensions.AnnotatedAttributeValue)); WellKnownMember constructor; ImmutableArray arguments; NamedTypeSymbol byteType = Compilation.GetSpecialType(SpecialType.System_Byte); Debug.Assert((object)byteType != null); - if (flagsBuilder.All(flag => flag == (byte)NullableAnnotation.NotAnnotated) || flagsBuilder.All(flag => flag == (byte)NullableAnnotation.Annotated)) + if (flagsBuilder.All(flag => flag == NullableAnnotationExtensions.NotAnnotatedAttributeValue) || flagsBuilder.All(flag => flag == NullableAnnotationExtensions.AnnotatedAttributeValue)) { constructor = WellKnownMember.System_Runtime_CompilerServices_NullableAttribute__ctorByte; arguments = ImmutableArray.Create(new TypedConstant(byteType, TypedConstantKind.Primitive, flagsBuilder[0])); @@ -1515,7 +1515,7 @@ internal SynthesizedAttributeData SynthesizeNullableAttribute(Symbol symbol, Typ foreach (byte flag in flagsBuilder) { - Debug.Assert(flag == (byte)NullableAnnotation.Oblivious || flag == (byte)NullableAnnotation.NotAnnotated || flag == (byte)NullableAnnotation.Annotated); + Debug.Assert(flag == NullableAnnotationExtensions.ObliviousAttributeValue || flag == NullableAnnotationExtensions.NotAnnotatedAttributeValue || flag == NullableAnnotationExtensions.AnnotatedAttributeValue); constantsBuilder.Add(new TypedConstant(byteType, TypedConstantKind.Primitive, flag)); } diff --git a/src/Compilers/CSharp/Portable/Symbols/ExtraAnnotations.cs b/src/Compilers/CSharp/Portable/Symbols/ExtraAnnotations.cs index b968c6da5585..8a035e42efcc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ExtraAnnotations.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ExtraAnnotations.cs @@ -129,7 +129,7 @@ private static ImmutableArray Array(params FlowAnalysis private static ImmutableArray Nullable(bool isNullable) { - return ImmutableArray.Create((byte)(isNullable ? NullableAnnotation.Annotated : NullableAnnotation.NotAnnotated)); + return ImmutableArray.Create(isNullable ? NullableAnnotationExtensions.AnnotatedAttributeValue : NullableAnnotationExtensions.NotAnnotatedAttributeValue); } internal static ImmutableArray> GetExtraAnnotations(string key) diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs index 0c85c553adbf..c144b14c9871 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs @@ -288,11 +288,11 @@ internal override bool? ReferenceTypeConstraintIsNullable if (((PEModuleSymbol)this.ContainingModule).Module.HasNullableAttribute(_handle, out byte transformFlag, out _)) { - switch ((NullableAnnotation)transformFlag) + switch (transformFlag) { - case NullableAnnotation.Annotated: + case NullableAnnotationExtensions.AnnotatedAttributeValue: return true; - case NullableAnnotation.NotAnnotated: + case NullableAnnotationExtensions.NotAnnotatedAttributeValue: return false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/NullableAnnotation.cs b/src/Compilers/CSharp/Portable/Symbols/NullableAnnotation.cs index 0f688d77e0f3..47a18494a8a9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NullableAnnotation.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NullableAnnotation.cs @@ -14,15 +14,15 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols internal enum NullableAnnotation : byte { /// - /// The type is not annotated in a context where the nullable feature is not enabled. - /// Used for interoperation with existing pre-nullable code. + /// Type is not annotated - string, int, T (including the case when T is unconstrained). /// - Oblivious, + NotAnnotated, /// - /// Type is not annotated - string, int, T (including the case when T is unconstrained). + /// The type is not annotated in a context where the nullable feature is not enabled. + /// Used for interoperation with existing pre-nullable code. /// - NotAnnotated, + Oblivious, /// /// Type is annotated with '?' - string?, T? where T : class; and for int?, T? where T : struct. diff --git a/src/Compilers/CSharp/Portable/Symbols/NullableAnnotationExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/NullableAnnotationExtensions.cs index f901afdfc517..2372c6295398 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NullableAnnotationExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NullableAnnotationExtensions.cs @@ -2,6 +2,9 @@ using Roslyn.Utilities; +// https://github.com/dotnet/roslyn/issues/34962 IDE005 "Fix formatting" does a poor job with a switch expression as the body of an expression-bodied method +#pragma warning disable IDE0055 + namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal static class NullableAnnotationExtensions @@ -16,49 +19,51 @@ internal static class NullableAnnotationExtensions /// Join nullable annotations from the set of lower bounds for fixing a type parameter. /// This uses the covariant merging rules. /// - public static NullableAnnotation Join(this NullableAnnotation a, NullableAnnotation b) - { - if (a.IsAnnotated() || b.IsAnnotated()) - return NullableAnnotation.Annotated; - return (a < b) ? a : b; - } + public static NullableAnnotation Join(this NullableAnnotation a, NullableAnnotation b) => (a < b) ? b : a; /// /// Meet two nullable annotations for computing the nullable annotation of a type parameter from upper bounds. /// This uses the contravariant merging rules. /// - public static NullableAnnotation Meet(this NullableAnnotation a, NullableAnnotation b) - { - if (a.IsNotAnnotated() || b.IsNotAnnotated()) - return NullableAnnotation.NotAnnotated; - return (a < b) ? a : b; - } + public static NullableAnnotation Meet(this NullableAnnotation a, NullableAnnotation b) => (a < b) ? a : b; /// - /// Check that two nullable annotations are "compatible", which means they could be the same. Return the - /// nullable annotation to be used as a result. This uses the invariant merging rules. + /// Return the nullable annotation to use when two annotations are expected to be "compatible", which means + /// they could be the same. These are the "invariant" merging rules. /// - public static NullableAnnotation EnsureCompatible(this NullableAnnotation a, NullableAnnotation b) - { - if (a.IsOblivious()) - return b; - if (b.IsOblivious()) - return a; - return (a < b) ? a : b; - } + public static NullableAnnotation EnsureCompatible(this NullableAnnotation a, NullableAnnotation b) => + (a, b) switch + { + (NullableAnnotation.Oblivious, _) => b, + (_, NullableAnnotation.Oblivious) => a, + _ => a < b ? a : b, + }; /// /// Merges nullability. /// - public static NullableAnnotation MergeNullableAnnotation(this NullableAnnotation a, NullableAnnotation b, VarianceKind variance) - { - return variance switch + public static NullableAnnotation MergeNullableAnnotation(this NullableAnnotation a, NullableAnnotation b, VarianceKind variance) => + variance switch { VarianceKind.In => a.Meet(b), VarianceKind.Out => a.Join(b), VarianceKind.None => a.EnsureCompatible(b), _ => throw ExceptionUtilities.UnexpectedValue(variance) }; - } + + /// + /// The attribute (metadata) representation of . + /// + public const byte NotAnnotatedAttributeValue = 1; + + /// + /// The attribute (metadata) representation of . + /// + public const byte AnnotatedAttributeValue = 2; + + /// + /// The attribute (metadata) representation of . + /// + public const byte ObliviousAttributeValue = 0; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs index f17bd6406893..3894b1ae4de5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs @@ -370,9 +370,9 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r ref attributes, moduleBuilder.SynthesizeNullableAttribute(WellKnownMember.System_Runtime_CompilerServices_NullableAttribute__ctorByte, ImmutableArray.Create(new TypedConstant(byteType, TypedConstantKind.Primitive, - (byte)(this.ReferenceTypeConstraintIsNullable == true ? - NullableAnnotation.Annotated : - NullableAnnotation.NotAnnotated))))); + (this.ReferenceTypeConstraintIsNullable == true ? + NullableAnnotationExtensions.AnnotatedAttributeValue : + NullableAnnotationExtensions.NotAnnotatedAttributeValue))))); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs b/src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs index 0b18c4b70fd4..05b26849e6fe 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeWithAnnotations.cs @@ -551,15 +551,15 @@ public void AddNullableTransforms(ArrayBuilder transforms) if (NullableAnnotation.IsOblivious() || typeSymbol.IsValueType) { - flag = (byte)NullableAnnotation.Oblivious; + flag = NullableAnnotationExtensions.ObliviousAttributeValue; } else if (NullableAnnotation.IsAnnotated()) { - flag = (byte)NullableAnnotation.Annotated; + flag = NullableAnnotationExtensions.AnnotatedAttributeValue; } else { - flag = (byte)NullableAnnotation.NotAnnotated; + flag = NullableAnnotationExtensions.NotAnnotatedAttributeValue; } transforms.Add(flag); @@ -597,17 +597,17 @@ public bool ApplyNullableTransforms(byte defaultTransformFlag, ImmutableArray. {