diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 729923528e46b13fb3267e170dc8abccb661353c..ac306a677d1c806c58ec52c9289908c33a1bf299 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -1404,29 +1404,40 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag } else { - if (node.IsKind(SyntaxKind.IdentifierName) && FallBackOnDiscard((IdentifierNameSyntax)node, diagnostics)) + expression = null; + if (node is IdentifierNameSyntax identifier) { - lookupResult.Free(); - return new BoundDiscardExpression(node, type: null); + var type = BindNativeIntegerSymbolIfAny(identifier, diagnostics); + if (type is { }) + { + expression = new BoundTypeExpression(node, null, type); + } + else if (FallBackOnDiscard(identifier, diagnostics)) + { + expression = new BoundDiscardExpression(node, type: null); + } } // Otherwise, the simple-name is undefined and a compile-time error occurs. - expression = BadExpression(node); - if (lookupResult.Error != null) - { - Error(diagnostics, lookupResult.Error, node); - } - else if (IsJoinRangeVariableInLeftKey(node)) - { - Error(diagnostics, ErrorCode.ERR_QueryOuterKey, node, name); - } - else if (IsInJoinRightKey(node)) - { - Error(diagnostics, ErrorCode.ERR_QueryInnerKey, node, name); - } - else + if (expression is null) { - Error(diagnostics, ErrorCode.ERR_NameNotInContext, node, name); + expression = BadExpression(node); + if (lookupResult.Error != null) + { + Error(diagnostics, lookupResult.Error, node); + } + else if (IsJoinRangeVariableInLeftKey(node)) + { + Error(diagnostics, ErrorCode.ERR_QueryOuterKey, node, name); + } + else if (IsInJoinRightKey(node)) + { + Error(diagnostics, ErrorCode.ERR_QueryInnerKey, node, name); + } + else + { + Error(diagnostics, ErrorCode.ERR_NameNotInContext, node, name); + } } } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index d1bcd22c6938193afd5ceb16d42f4ed5aaf526fd..8edf02f829d648b123773fb3d41e153f19fde421 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -819,26 +819,21 @@ private static bool IsViableType(LookupResult result) if ((object)qualifierOpt == null && !IsViableType(result)) { - switch (node.Identifier.ValueText) + if (node.Identifier.ValueText == "dynamic") { - case "dynamic": - if ((node.Parent == null || - node.Parent.Kind() != SyntaxKind.Attribute && // dynamic not allowed as attribute type - SyntaxFacts.IsInTypeOnlyContext(node)) && - Compilation.LanguageVersion >= MessageID.IDS_FeatureDynamic.RequiredVersion()) - { - bindingResult = Compilation.DynamicType; - ReportUseSiteDiagnosticForDynamic(diagnostics, node); - } - break; - case "nint": - bindingResult = getNativeIntType(node, unsigned: false, diagnostics); - break; - case "nuint": - bindingResult = getNativeIntType(node, unsigned: true, diagnostics); - break; - default: - break; + + if ((node.Parent == null || + node.Parent.Kind() != SyntaxKind.Attribute && // dynamic not allowed as attribute type + SyntaxFacts.IsInTypeOnlyContext(node)) && + Compilation.LanguageVersion >= MessageID.IDS_FeatureDynamic.RequiredVersion()) + { + bindingResult = Compilation.DynamicType; + ReportUseSiteDiagnosticForDynamic(diagnostics, node); + } + } + else + { + bindingResult = BindNativeIntegerSymbolIfAny(node, diagnostics); } } @@ -859,12 +854,28 @@ private static bool IsViableType(LookupResult result) result.Free(); return NamespaceOrTypeOrAliasSymbolWithAnnotations.CreateUnannotated(AreNullableAnnotationsEnabled(node.Identifier), bindingResult); + } - NamedTypeSymbol getNativeIntType(SyntaxNode node, bool unsigned, DiagnosticBag diagnostics) + /// + /// If the node is "nint" or "nuint", return the corresponding native integer symbol. + /// Otherwise return null. + /// + private NamedTypeSymbol BindNativeIntegerSymbolIfAny(IdentifierNameSyntax node, DiagnosticBag diagnostics) + { + SpecialType specialType; + switch (node.Identifier.Text) { - CheckFeatureAvailability(node, MessageID.IDS_FeatureNativeInt, diagnostics); - return this.GetSpecialType(unsigned ? SpecialType.System_UIntPtr : SpecialType.System_IntPtr, diagnostics, node).AsNativeInteger(); + case "nint": + specialType = SpecialType.System_IntPtr; + break; + case "nuint": + specialType = SpecialType.System_UIntPtr; + break; + default: + return null; } + CheckFeatureAvailability(node, MessageID.IDS_FeatureNativeInt, diagnostics); + return this.GetSpecialType(specialType, diagnostics, node).AsNativeInteger(); } private void ReportUseSiteDiagnosticForDynamic(DiagnosticBag diagnostics, IdentifierNameSyntax node) diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Patterns.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Patterns.cs index bb47ad1660f396174c6e4c395591649fb144b17f..21204ac7909404d9ae714a27e2b1916f97b481a9 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Patterns.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Patterns.cs @@ -316,6 +316,10 @@ private BoundExpression MakeEqual(BoundExpression loweredLiteral, BoundExpressio return _localRewriter.MakeBinaryOperator(_factory.Syntax, BinaryOperatorKind.UIntEqual, input, loweredLiteral, booleanType, method: null); case SpecialType.System_UInt64: return _localRewriter.MakeBinaryOperator(_factory.Syntax, BinaryOperatorKind.ULongEqual, input, loweredLiteral, booleanType, method: null); + case SpecialType.System_IntPtr when loweredLiteral.Type.IsNativeIntegerType: + return _localRewriter.MakeBinaryOperator(_factory.Syntax, BinaryOperatorKind.NIntEqual, input, loweredLiteral, booleanType, method: null); + case SpecialType.System_UIntPtr when loweredLiteral.Type.IsNativeIntegerType: + return _localRewriter.MakeBinaryOperator(_factory.Syntax, BinaryOperatorKind.NUIntEqual, input, loweredLiteral, booleanType, method: null); default: if (loweredLiteral.Type.IsEnumType()) { diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs index 7a8f7fc19562e5666f4454033d981952f019cdee..6b013a0db48d70007ef11fe136bd96731f53da20 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs @@ -182,7 +182,8 @@ private void VisitNamedTypeWithoutNullability(INamedTypeSymbol symbol) return; } - if (format.MiscellaneousOptions.IncludesOption(SymbolDisplayMiscellaneousOptions.UseSpecialTypes)) + if (format.MiscellaneousOptions.IncludesOption(SymbolDisplayMiscellaneousOptions.UseSpecialTypes) || + (symbol.IsNativeIntegerType && !format.CompilerInternalOptions.IncludesOption(SymbolDisplayCompilerInternalOptions.UseNativeIntegerUnderlyingType))) { if (AddSpecialTypeKeyword(symbol)) { diff --git a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs index 86af68908c98445d7b71bd22e312d8597616f03d..bf08ad2257b87b26cb4a3b332fd0b37f02d1a41b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs @@ -15,13 +15,15 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols // PROTOTYPE: Handle retargeting these types. internal sealed class NativeIntegerTypeSymbol : WrappedNamedTypeSymbol, Cci.IReference { - internal NativeIntegerTypeSymbol(NamedTypeSymbol underlying) : base(underlying, tupleData: null) + private ImmutableArray _lazyInterfaces; + + internal NativeIntegerTypeSymbol(NamedTypeSymbol underlyingType) : base(underlyingType, tupleData: null) { - Debug.Assert(underlying.TupleData is null); - Debug.Assert(!underlying.IsNativeIntegerType); - Debug.Assert(underlying.SpecialType == SpecialType.System_IntPtr || underlying.SpecialType == SpecialType.System_UIntPtr); - Debug.Assert(this.Equals(underlying)); - Debug.Assert(underlying.Equals(this)); + Debug.Assert(underlyingType.TupleData is null); + Debug.Assert(!underlyingType.IsNativeIntegerType); + Debug.Assert(underlyingType.SpecialType == SpecialType.System_IntPtr || underlyingType.SpecialType == SpecialType.System_UIntPtr); + Debug.Assert(this.Equals(underlyingType)); + Debug.Assert(underlyingType.Equals(this)); } public override ImmutableArray TypeParameters => ImmutableArray.Empty; @@ -63,7 +65,7 @@ internal NativeIntegerTypeSymbol(NamedTypeSymbol underlying) : base(underlying, internal override NamedTypeSymbol GetDeclaredBaseType(ConsList basesBeingResolved) => _underlyingType.GetDeclaredBaseType(basesBeingResolved); - internal override ImmutableArray GetDeclaredInterfaces(ConsList basesBeingResolved) => _underlyingType.GetDeclaredInterfaces(basesBeingResolved); + internal override ImmutableArray GetDeclaredInterfaces(ConsList basesBeingResolved) => GetInterfaces(basesBeingResolved); internal override ImmutableArray GetEarlyAttributeDecodingMembers() => throw ExceptionUtilities.Unreachable; @@ -73,9 +75,7 @@ internal NativeIntegerTypeSymbol(NamedTypeSymbol underlying) : base(underlying, internal override ImmutableArray GetInterfacesToEmit() => throw ExceptionUtilities.Unreachable; - // PROTOTYPE: Include certain interfaces defined on the underlying type, with substitution - // of [U]IntPtr (for instance, IEquatable rather than IEquatable). - internal override ImmutableArray InterfacesNoUseSiteDiagnostics(ConsList? basesBeingResolved = null) => ImmutableArray.Empty; + internal override ImmutableArray InterfacesNoUseSiteDiagnostics(ConsList? basesBeingResolved = null) => GetInterfaces(basesBeingResolved); protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) => throw ExceptionUtilities.Unreachable; @@ -101,5 +101,41 @@ void Cci.IReference.Dispatch(Cci.MetadataVisitor visitor) // NativeIntegerTypeSymbol should not be used in emit. throw ExceptionUtilities.Unreachable; } + + private ImmutableArray GetInterfaces(ConsList? basesBeingResolved) + { + if (_lazyInterfaces.IsDefault) + { + ImmutableInterlocked.InterlockedCompareExchange(ref _lazyInterfaces, makeInterfaces(_underlyingType.InterfacesNoUseSiteDiagnostics(basesBeingResolved)), default(ImmutableArray)); + } + return _lazyInterfaces; + + // Return IEquatable if the underlying type implemented IEquatable. + ImmutableArray makeInterfaces(ImmutableArray underlyingInterfaces) + { + Debug.Assert(_underlyingType.SpecialType == SpecialType.System_IntPtr || _underlyingType.SpecialType == SpecialType.System_UIntPtr); + + foreach (var underlyingInterface in underlyingInterfaces) + { + // Is the underlying interface IEquatable? + if (underlyingInterface.Name != "IEquatable") + { + continue; + } + var typeArgs = underlyingInterface.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics; + if (typeArgs.Length == 1 && _underlyingType.SpecialType == typeArgs[0].Type.SpecialType) + { + var def = underlyingInterface.OriginalDefinition; + if (def.ContainingSymbol is NamespaceSymbol { Name: "System", ContainingSymbol: NamespaceSymbol { IsGlobalNamespace: true } }) + { + // Return IEquatable. + return ImmutableArray.Create(def.Construct(ImmutableArray.Create(TypeWithAnnotations.Create(this)))); + } + } + } + + return ImmutableArray.Empty; + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/SpecialTypeExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/SpecialTypeExtensions.cs index ba083a24a14962482b3c866fc5816a128d0947dd..56ebf0979e0d281e96d9bbbcf5e67845498ca3ff 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SpecialTypeExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SpecialTypeExtensions.cs @@ -27,20 +27,6 @@ public static bool IsIntegralType(this SpecialType specialType) } } - public static bool IsSignedIntegralType(this SpecialType specialType) - { - switch (specialType) - { - case SpecialType.System_SByte: - case SpecialType.System_Int16: - case SpecialType.System_Int32: - case SpecialType.System_Int64: - return true; - default: - return false; - } - } - public static bool CanBeConst(this SpecialType specialType) { switch (specialType) @@ -65,34 +51,6 @@ public static bool CanBeConst(this SpecialType specialType) } } - /// - /// The type is one of the simple types defined in Dev10 C#, see "predeftype.h"/simple - /// - public static bool IsIntrinsicType(this SpecialType specialType) - { - switch (specialType) - { - case SpecialType.System_Boolean: - case SpecialType.System_Char: - case SpecialType.System_SByte: - case SpecialType.System_Int16: - case SpecialType.System_Int32: - case SpecialType.System_Int64: - case SpecialType.System_Byte: - case SpecialType.System_UInt16: - case SpecialType.System_UInt32: - case SpecialType.System_UInt64: - case SpecialType.System_Single: - case SpecialType.System_Double: - // NOTE: VB treats System.DateTime as an intrinsic, while C# does not, see "predeftype.h" - //case SpecialType.System_DateTime: - case SpecialType.System_Decimal: - return true; - default: - return false; - } - } - public static bool IsValidVolatileFieldType(this SpecialType specialType) { switch (specialType) diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index e1c57121217d03739b8851d265454aaaf4ed6a09..6a499740e9d85edea1fc2e0f23fb04400e67da2d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1035,7 +1035,29 @@ internal static bool IsValidV6SwitchGoverningType(this TypeSymbol type, bool isT public static bool IsIntrinsicType(this TypeSymbol type) { - return type.SpecialType.IsIntrinsicType(); + switch (type.SpecialType) + { + case SpecialType.System_Boolean: + case SpecialType.System_Char: + case SpecialType.System_SByte: + case SpecialType.System_Int16: + case SpecialType.System_Int32: + case SpecialType.System_Int64: + case SpecialType.System_Byte: + case SpecialType.System_UInt16: + case SpecialType.System_UInt32: + case SpecialType.System_UInt64: + case SpecialType.System_IntPtr when type.IsNativeIntegerType: + case SpecialType.System_UIntPtr when type.IsNativeIntegerType: + case SpecialType.System_Single: + case SpecialType.System_Double: + // NOTE: VB treats System.DateTime as an intrinsic, while C# does not. + //case SpecialType.System_DateTime: + case SpecialType.System_Decimal: + return true; + default: + return false; + } } public static bool IsPartial(this TypeSymbol type) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs index 5a3d2a1c2747c86f486a44bf6751ff8dde161e13..fe3a74ae28f60442fe98a00bff7dfb1be30359e2 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs @@ -8,8 +8,11 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Symbols; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -17,10 +20,6 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics { public class NativeIntegerTests : CSharpTestBase { - // PROTOTYPE: SymbolDisplay should use "nint" and "nuint" always, regardless of SymbolDisplayFormat. - // Remove this SymbolDisplayFormat and use .ToTestDisplayString() instead. - private static readonly SymbolDisplayFormat FormatWithSpecialTypes = SymbolDisplayFormat.TestFormat.WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes); - [Fact] public void LanguageVersion() { @@ -70,12 +69,12 @@ public void TypeDefinitions_FromMetadata() VerifyType(type.GetPublicSymbol(), signed: false, isNativeInt: false); var method = comp.GetMember("I.F1"); - Assert.Equal("void I.F1(System.IntPtr x, nint y)", method.ToDisplayString(FormatWithSpecialTypes)); + Assert.Equal("void I.F1(System.IntPtr x, nint y)", method.ToTestDisplayString()); Assert.Equal("Sub I.F1(x As System.IntPtr, y As System.IntPtr)", VisualBasic.SymbolDisplay.ToDisplayString(method.GetPublicSymbol(), SymbolDisplayFormat.TestFormat)); VerifyTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: true); method = comp.GetMember("I.F2"); - Assert.Equal("void I.F2(System.UIntPtr x, nuint y)", method.ToDisplayString(FormatWithSpecialTypes)); + Assert.Equal("void I.F2(System.UIntPtr x, nuint y)", method.ToTestDisplayString()); Assert.Equal("Sub I.F2(x As System.UIntPtr, y As System.UIntPtr)", VisualBasic.SymbolDisplay.ToDisplayString(method.GetPublicSymbol(), SymbolDisplayFormat.TestFormat)); VerifyTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: false); } @@ -105,17 +104,23 @@ public abstract class ValueType public struct Void { } public struct Boolean { } public struct Int32 { } - public struct IntPtr + public interface IEquatable + { + bool Equals(T other); + } + public struct IntPtr : IEquatable { public override string ToString() => null; public override int GetHashCode() => 0; public override bool Equals(object obj) => false; + bool IEquatable.Equals(IntPtr other) => false; } - public struct UIntPtr + public struct UIntPtr : IEquatable { public override string ToString() => null; public override int GetHashCode() => 0; public override bool Equals(object obj) => false; + bool IEquatable.Equals(UIntPtr other) => false; } }"; var sourceB = @@ -152,11 +157,11 @@ static void verify(CSharpCompilation comp) VerifyType(type.GetPublicSymbol(), signed: false, isNativeInt: false); var method = comp.GetMember("I.F1"); - Assert.Equal("void I.F1(System.IntPtr x, nint y)", method.ToDisplayString(FormatWithSpecialTypes)); + Assert.Equal("void I.F1(System.IntPtr x, nint y)", method.ToTestDisplayString()); VerifyTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: true); method = comp.GetMember("I.F2"); - Assert.Equal("void I.F2(System.UIntPtr x, nuint y)", method.ToDisplayString(FormatWithSpecialTypes)); + Assert.Equal("void I.F2(System.UIntPtr x, nuint y)", method.ToTestDisplayString()); VerifyTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: false); } } @@ -203,8 +208,7 @@ private static void VerifyTypes(INamedTypeSymbol underlyingType, INamedTypeSymbo var baseMembers = members.SelectAsArray(m => ((IMethodSymbol)m).OverriddenMethod); Assert.Empty(baseMembers); - // PROTOTYPE: Include certain interfaces defined on the underlying underlyingType. - Assert.Empty(nativeIntegerType.Interfaces); + verifyInterfaces(underlyingType, underlyingType.Interfaces, nativeIntegerType, nativeIntegerType.Interfaces); Assert.NotSame(underlyingType, nativeIntegerType); Assert.Same(underlyingType, nativeIntegerType.NativeIntegerUnderlyingType); @@ -216,6 +220,33 @@ private static void VerifyTypes(INamedTypeSymbol underlyingType, INamedTypeSymbo Assert.True(underlyingType.Equals(nativeIntegerType, SymbolEqualityComparer.IncludeNullability)); Assert.True(underlyingType.Equals(nativeIntegerType, SymbolEqualityComparer.ConsiderEverything)); Assert.Equal(underlyingType.GetHashCode(), nativeIntegerType.GetHashCode()); + + static void verifyInterfaces(INamedTypeSymbol underlyingType, ImmutableArray underlyingInterfaces, INamedTypeSymbol nativeIntegerType, ImmutableArray nativeIntegerInterfaces) + { + underlyingInterfaces = underlyingInterfaces.WhereAsArray(t => t.Name == "IEquatable" && t.ContainingNamespace.Name == "System"); + + Assert.Equal(underlyingInterfaces.Length, nativeIntegerInterfaces.Length); + + for (int i = 0; i < underlyingInterfaces.Length; i++) + { + verifyInterface(underlyingInterfaces[i], nativeIntegerInterfaces[i]); + } + + void verifyInterface(INamedTypeSymbol underlyingInterface, INamedTypeSymbol nativeIntegerInterface) + { + Assert.Equal(underlyingInterface, nativeIntegerInterface); + + for (int i = 0; i < underlyingInterface.TypeArguments.Length; i++) + { + var underlyingTypeArgument = underlyingInterface.TypeArguments[i]; + var nativeIntegerTypeArgument = nativeIntegerInterface.TypeArguments[i]; + if (underlyingTypeArgument.Equals(underlyingType, TypeCompareKind.AllIgnoreOptions)) + { + Assert.True(nativeIntegerTypeArgument.IsNativeIntegerType); + } + } + } + } } private static void VerifyTypes(NamedTypeSymbol underlyingType, NamedTypeSymbol nativeIntegerType, bool signed) @@ -235,8 +266,8 @@ private static void VerifyTypes(NamedTypeSymbol underlyingType, NamedTypeSymbol var baseMembers = members.SelectAsArray(m => ((MethodSymbol)m).OverriddenMethod); Assert.Empty(baseMembers); - // PROTOTYPE: Include certain interfaces defined on the underlying underlyingType. - Assert.Empty(nativeIntegerType.InterfacesNoUseSiteDiagnostics()); + verifyInterfaces(underlyingType, underlyingType.InterfacesNoUseSiteDiagnostics(), nativeIntegerType, nativeIntegerType.InterfacesNoUseSiteDiagnostics()); + verifyInterfaces(underlyingType, underlyingType.GetDeclaredInterfaces(null), nativeIntegerType, nativeIntegerType.GetDeclaredInterfaces(null)); Assert.Null(underlyingType.NativeIntegerUnderlyingType); Assert.Same(nativeIntegerType, underlyingType.AsNativeInteger()); @@ -256,6 +287,33 @@ static void verifyEqualButDistinct(NamedTypeSymbol underlyingType, NamedTypeSymb Assert.True(nativeIntegerType.Equals(underlyingType, TypeCompareKind.ConsiderEverything)); Assert.Equal(underlyingType.GetHashCode(), nativeIntegerType.GetHashCode()); } + + static void verifyInterfaces(NamedTypeSymbol underlyingType, ImmutableArray underlyingInterfaces, NamedTypeSymbol nativeIntegerType, ImmutableArray nativeIntegerInterfaces) + { + underlyingInterfaces = underlyingInterfaces.WhereAsArray(t => t.Name == "IEquatable" && t.ContainingNamespace.Name == "System"); + + Assert.Equal(underlyingInterfaces.Length, nativeIntegerInterfaces.Length); + + for (int i = 0; i < underlyingInterfaces.Length; i++) + { + verifyInterface(underlyingInterfaces[i], nativeIntegerInterfaces[i]); + } + + void verifyInterface(NamedTypeSymbol underlyingInterface, NamedTypeSymbol nativeIntegerInterface) + { + Assert.Equal(underlyingInterface, nativeIntegerInterface); + + for (int i = 0; i < underlyingInterface.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Length; i++) + { + var underlyingTypeArgument = underlyingInterface.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[i].Type; + var nativeIntegerTypeArgument = nativeIntegerInterface.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[i].Type; + if (underlyingTypeArgument.Equals(underlyingType, TypeCompareKind.AllIgnoreOptions)) + { + Assert.True(nativeIntegerTypeArgument.IsNativeIntegerType); + } + } + } + } } private static void VerifyMembers(NamedTypeSymbol type) @@ -349,11 +407,11 @@ public struct Void { } static void verify(CSharpCompilation comp) { var method = comp.GetMember("I.F1"); - Assert.Equal("void I.F1(System.IntPtr x, nint y)", method.ToDisplayString(FormatWithSpecialTypes)); + Assert.Equal("void I.F1(System.IntPtr x, nint y)", method.ToTestDisplayString()); VerifyErrorTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: true); method = comp.GetMember("I.F2"); - Assert.Equal("void I.F2(System.UIntPtr x, nuint y)", method.ToDisplayString(FormatWithSpecialTypes)); + Assert.Equal("void I.F2(System.UIntPtr x, nuint y)", method.ToTestDisplayString()); VerifyErrorTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: false); } } @@ -398,6 +456,330 @@ private static void VerifyErrorTypes(INamedTypeSymbol underlyingType, INamedType VerifyErrorType(nativeIntegerType.NativeIntegerUnderlyingType, specialType, isNativeInt: false); } + [Fact] + public void Interfaces() + { + var sourceA = +@"namespace System +{ + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public interface ISerializable { } + public interface IEquatable + { + bool Equals(T other); + } + public interface IOther { } + public struct IntPtr : ISerializable, IEquatable, IOther + { + bool IEquatable.Equals(IntPtr other) => false; + } +}"; + var sourceB = +@"using System; +class Program +{ + static void F0(ISerializable i) { } + static object F1(IEquatable i) => default; + static void F2(IEquatable i) { } + static void F3(IOther i) { } + static void Main() + { + nint n = 42; + F0(n); + F1(n); + _ = F2(n); + F3(n); + F3(n); + F3((IntPtr)n); + } +}"; + var comp = CreateEmptyCompilation(new[] { sourceA, sourceB }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (11,12): error CS1503: Argument 1: cannot convert from 'nint' to 'System.ISerializable' + // F0(n); + Diagnostic(ErrorCode.ERR_BadArgType, "n").WithArguments("1", "nint", "System.ISerializable").WithLocation(11, 12), + // (13,9): error CS8209: A value of type 'void' may not be assigned. + // _ = F2(n); + Diagnostic(ErrorCode.ERR_VoidAssignment, "_").WithLocation(13, 9), + // (14,18): error CS1503: Argument 1: cannot convert from 'nint' to 'System.IOther' + // F3(n); + Diagnostic(ErrorCode.ERR_BadArgType, "n").WithArguments("1", "nint", "System.IOther").WithLocation(14, 18), + // (15,20): error CS1503: Argument 1: cannot convert from 'nint' to 'System.IOther' + // F3(n); + Diagnostic(ErrorCode.ERR_BadArgType, "n").WithArguments("1", "nint", "System.IOther").WithLocation(15, 20)); + } + + [Fact] + public void IEquatable() + { + // Minimal definitions. + verifyAll(includesIEquatable: true, +@"namespace System +{ + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public interface IEquatable { } + public struct IntPtr : IEquatable { } + public struct UIntPtr : IEquatable { } +}"); + + // IEquatable in global namespace. + verifyAll(includesIEquatable: false, +@"public interface IEquatable { } +namespace System +{ + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public struct IntPtr : IEquatable { } + public struct UIntPtr : IEquatable { } +}"); + + // IEquatable in other namespace. + verifyAll(includesIEquatable: false, +@"namespace Other +{ + public interface IEquatable { } +} +namespace System +{ + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public struct IntPtr : Other.IEquatable { } + public struct UIntPtr : Other.IEquatable { } +}"); + + // IEquatable nested in "System" type. + verifyAll(includesIEquatable: false, +@"namespace System +{ + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public class System + { + public interface IEquatable { } + } + public struct IntPtr : System.IEquatable { } + public struct UIntPtr : System.IEquatable { } +}"); + + // IEquatable nested in other type. + verifyAll(includesIEquatable: false, +@"namespace System +{ + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public class Other + { + public interface IEquatable { } + } + public struct IntPtr : Other.IEquatable { } + public struct UIntPtr : Other.IEquatable { } +}"); + + // IEquatable. + verifyAll(includesIEquatable: false, +@"namespace System +{ + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public interface IEquatable { } + public struct IntPtr : IEquatable { } + public struct UIntPtr : IEquatable { } +}"); + + // IEquatable. + verifyAll(includesIEquatable: false, +@"namespace System +{ + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public interface IEquatable { } + public struct IntPtr : IEquatable { } + public struct UIntPtr : IEquatable { } +}"); + + // IEquatable and IEquatable + verifyAll(includesIEquatable: false, +@"namespace System +{ + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public interface IEquatable { } + public struct IntPtr : IEquatable { } + public struct UIntPtr : IEquatable { } +}"); + + // IEquatable and IEquatable. + verifyAll(includesIEquatable: false, +@"namespace System +{ + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public interface IEquatable { } + public struct IntPtr : IEquatable { } + public struct UIntPtr : IEquatable { } +}"); + + // IEquatable and IEquatable. + var comp = CreateEmptyCompilation( +@"namespace System +{ + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public struct Enum { } + public class Attribute { } + public class AttributeUsageAttribute : Attribute + { + public AttributeUsageAttribute(AttributeTargets validOn) { } + public bool AllowMultiple { get; set; } + public bool Inherited { get; set; } + } + public enum AttributeTargets { } + public interface IEquatable { } + public struct IntPtr : IEquatable { } + public struct UIntPtr : IEquatable { } +}", + parseOptions: TestOptions.RegularPreview); + verifyReference(comp.EmitToImageReference(EmitOptions.Default.WithRuntimeMetadataVersion("0.0.0.0")), includesIEquatable: true); + + // IEquatable and IEquatable. + comp = CreateEmptyCompilation( +@"namespace System +{ + public class Object { } + public class String { } + public abstract class ValueType { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public struct Enum { } + public class Attribute { } + public class AttributeUsageAttribute : Attribute + { + public AttributeUsageAttribute(AttributeTargets validOn) { } + public bool AllowMultiple { get; set; } + public bool Inherited { get; set; } + } + public enum AttributeTargets { } + public interface IEquatable { } + public struct IntPtr : IEquatable { } + public struct UIntPtr : IEquatable { } +}", + parseOptions: TestOptions.RegularPreview); + verifyReference(comp.EmitToImageReference(EmitOptions.Default.WithRuntimeMetadataVersion("0.0.0.0")), includesIEquatable: false); + + static void verifyAll(bool includesIEquatable, string sourceA) + { + var sourceB = +@"interface I +{ + nint F1(); + nuint F2(); +}"; + var comp = CreateEmptyCompilation(new[] { sourceA, sourceB }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + verifyCompilation(comp, includesIEquatable); + + comp = CreateEmptyCompilation(sourceA); + comp.VerifyDiagnostics(); + var ref1 = comp.ToMetadataReference(); + var ref2 = comp.EmitToImageReference(); + + comp = CreateEmptyCompilation(sourceB, references: new[] { ref1 }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + verifyCompilation(comp, includesIEquatable); + + comp = CreateEmptyCompilation(sourceB, references: new[] { ref2 }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + verifyCompilation(comp, includesIEquatable); + } + + static void verifyReference(MetadataReference reference, bool includesIEquatable) + { + var sourceB = +@"interface I +{ + nint F1(); + nuint F2(); +}"; + var comp = CreateEmptyCompilation(sourceB, references: new[] { reference }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + verifyCompilation(comp, includesIEquatable); + } + + + static void verifyCompilation(CSharpCompilation comp, bool includesIEquatable) + { + verifyInterfaces(comp, (NamedTypeSymbol)comp.GetMember("I.F1").ReturnType, SpecialType.System_IntPtr, includesIEquatable); + verifyInterfaces(comp, (NamedTypeSymbol)comp.GetMember("I.F2").ReturnType, SpecialType.System_UIntPtr, includesIEquatable); + } + + static void verifyInterfaces(CSharpCompilation comp, NamedTypeSymbol type, SpecialType specialType, bool includesIEquatable) + { + Assert.True(type.IsNativeIntegerType); + Assert.Equal(specialType, type.NativeIntegerUnderlyingType.SpecialType); + + var interfaces = type.InterfacesNoUseSiteDiagnostics(null); + Assert.Equal(interfaces, type.GetDeclaredInterfaces(null)); + + Assert.Equal(includesIEquatable ? 1 : 0, interfaces.Length); + + if (includesIEquatable) + { + var @interface = interfaces.Single(); + var def = comp.GetWellKnownType(WellKnownType.System_IEquatable_T); + Assert.NotNull(def); + Assert.Equal(def, @interface.OriginalDefinition); + Assert.Equal(type, @interface.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0].Type); + } + } + } + [Fact] public void CreateNativeIntegerTypeSymbol_FromMetadata() { @@ -498,6 +880,89 @@ static void verifyCreateNativeIntegerTypeSymbol(CSharpCompilation comp) } } + [Fact] + public void ArrayInitialization() + { + var source = +@"class Program +{ + static void Main() + { + Report(new nint[] { int.MinValue, -1, 0, 1, int.MaxValue }); + Report(new nuint[] { 0, 1, 2, int.MaxValue, uint.MaxValue }); + } + static void Report(T[] items) + { + foreach (var item in items) + System.Console.WriteLine($""{item.GetType().FullName}: {item}""); + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview); + var verifier = CompileAndVerify(comp, expectedOutput: +@"System.IntPtr: -2147483648 +System.IntPtr: -1 +System.IntPtr: 0 +System.IntPtr: 1 +System.IntPtr: 2147483647 +System.UIntPtr: 0 +System.UIntPtr: 1 +System.UIntPtr: 2 +System.UIntPtr: 2147483647 +System.UIntPtr: 4294967295"); + verifier.VerifyIL("Program.Main", +@"{ + // Code size 75 (0x4b) + .maxstack 4 + IL_0000: ldc.i4.5 + IL_0001: newarr ""System.IntPtr"" + IL_0006: dup + IL_0007: ldc.i4.0 + IL_0008: ldc.i4 0x80000000 + IL_000d: conv.i + IL_000e: stelem.i + IL_000f: dup + IL_0010: ldc.i4.1 + IL_0011: ldc.i4.m1 + IL_0012: conv.i + IL_0013: stelem.i + IL_0014: dup + IL_0015: ldc.i4.3 + IL_0016: ldc.i4.1 + IL_0017: conv.i + IL_0018: stelem.i + IL_0019: dup + IL_001a: ldc.i4.4 + IL_001b: ldc.i4 0x7fffffff + IL_0020: conv.i + IL_0021: stelem.i + IL_0022: call ""void Program.Report(nint[])"" + IL_0027: ldc.i4.5 + IL_0028: newarr ""System.UIntPtr"" + IL_002d: dup + IL_002e: ldc.i4.1 + IL_002f: ldc.i4.1 + IL_0030: conv.i + IL_0031: stelem.i + IL_0032: dup + IL_0033: ldc.i4.2 + IL_0034: ldc.i4.2 + IL_0035: conv.i + IL_0036: stelem.i + IL_0037: dup + IL_0038: ldc.i4.3 + IL_0039: ldc.i4 0x7fffffff + IL_003e: conv.i + IL_003f: stelem.i + IL_0040: dup + IL_0041: ldc.i4.4 + IL_0042: ldc.i4.m1 + IL_0043: conv.u + IL_0044: stelem.i + IL_0045: call ""void Program.Report(nuint[])"" + IL_004a: ret +}"); + } + [Fact] public void Overrides_01() { @@ -937,11 +1402,8 @@ static void Main() } // PROTOTYPE: Test: - // - @nint - // - Type.nint, Namespace.nint // - BindNonGenericSimpleNamespaceOrTypeOrAliasSymbol has the comment "dynamic not allowed as an attribute type". Does that apply to "nint"? // - BindNonGenericSimpleNamespaceOrTypeOrAliasSymbol checks IsViableType(result) - // - Use-site diagnostics (basically any use-site diagnostics from IntPtr/UIntPtr) // - Type unification of I and I [Fact] @@ -976,7 +1438,7 @@ static void verify(CSharpCompilation comp) Assert.Equal("nint", underlyingType.ToTestDisplayString()); Assert.Equal(SpecialType.None, underlyingType.SpecialType); var method = model.GetDeclaredSymbol(nodes.OfType().Single()); - Assert.Equal("nint I.Add(nint x, System.UIntPtr y)", method.ToTestDisplayString()); + Assert.Equal("nint I.Add(nint x, nuint y)", method.ToTestDisplayString()); var underlyingType0 = method.Parameters[0].Type.GetSymbol(); var underlyingType1 = method.Parameters[1].Type.GetSymbol(); Assert.Equal(SpecialType.None, underlyingType0.SpecialType); @@ -1010,7 +1472,7 @@ interface I static void verify(CSharpCompilation comp) { var method = comp.GetMember("I.Add"); - Assert.Equal("System.Int16 I.Add(System.Int16 x, System.UIntPtr y)", method.ToTestDisplayString()); + Assert.Equal("System.Int16 I.Add(System.Int16 x, nuint y)", method.ToTestDisplayString()); var underlyingType0 = (NamedTypeSymbol)method.Parameters[0].Type; var underlyingType1 = (NamedTypeSymbol)method.Parameters[1].Type; Assert.Equal(SpecialType.System_Int16, underlyingType0.SpecialType); @@ -1020,9 +1482,57 @@ static void verify(CSharpCompilation comp) } } - // PROTOTYPE: nint and nuint should be allowed. [Fact] - public void MemberName() + public void MemberName_01() + { + var source = +@"namespace N +{ + class nint { } + class Program + { + internal static object nuint; + static void Main() + { + _ = new nint(); + _ = new @nint(); + _ = new N.nint(); + @nint i = null; + _ = i; + @nuint = null; + _ = nuint; + _ = @nuint; + _ = Program.nuint; + } + } +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8); + comp.VerifyDiagnostics(); + verify(comp); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + verify(comp); + + static void verify(CSharpCompilation comp) + { + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var nodes = tree.GetRoot().DescendantNodes().OfType().ToArray(); + Assert.Equal(3, nodes.Length); + foreach (var node in nodes) + { + var type = model.GetTypeInfo(node).Type; + Assert.Equal("N.nint", type.ToTestDisplayString()); + Assert.Equal(SpecialType.None, type.SpecialType); + Assert.False(type.IsNativeIntegerType); + } + } + } + + [Fact] + public void MemberName_02() { var source = @"class Program @@ -1036,54 +1546,130 @@ static void Main() var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( - // (5,13): error CS0103: The name 'nint' does not exist in the current context + // (5,13): error CS8652: The feature 'native-sized integers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // _ = nint.Equals(0, 0); - Diagnostic(ErrorCode.ERR_NameNotInContext, "nint").WithArguments("nint").WithLocation(5, 13), - // (6,13): error CS0103: The name 'nuint' does not exist in the current context + Diagnostic(ErrorCode.ERR_FeatureInPreview, "nint").WithArguments("native-sized integers").WithLocation(5, 13), + // (6,13): error CS8652: The feature 'native-sized integers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // _ = nuint.Equals(0, 0); - Diagnostic(ErrorCode.ERR_NameNotInContext, "nuint").WithArguments("nuint").WithLocation(6, 13)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "nuint").WithArguments("native-sized integers").WithLocation(6, 13)); comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + } + + [Fact] + public void NameOf_01() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Console.WriteLine(nameof(nint)); + Console.WriteLine(nameof(nuint)); + } +}"; + + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( - // (5,13): error CS0103: The name 'nint' does not exist in the current context - // _ = nint.Equals(0, 0); - Diagnostic(ErrorCode.ERR_NameNotInContext, "nint").WithArguments("nint").WithLocation(5, 13), - // (6,13): error CS0103: The name 'nuint' does not exist in the current context - // _ = nuint.Equals(0, 0); - Diagnostic(ErrorCode.ERR_NameNotInContext, "nuint").WithArguments("nuint").WithLocation(6, 13)); + // (6,34): error CS8652: The feature 'native-sized integers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Console.WriteLine(nameof(nint)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "nint").WithArguments("native-sized integers").WithLocation(6, 34), + // (7,34): error CS8652: The feature 'native-sized integers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Console.WriteLine(nameof(nuint)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "nuint").WithArguments("native-sized integers").WithLocation(7, 34)); + + comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: +@"nint +nuint"); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var node = tree.GetRoot().DescendantNodes().First(n => n is IdentifierNameSyntax { Identifier: { ValueText: "nint" } }); + var symbol = (ITypeSymbol)model.GetSymbolInfo(node).Symbol; + Assert.Equal("nint", symbol.ToTestDisplayString()); + Assert.True(symbol.IsNativeIntegerType); } - // PROTOTYPE: nint and nuint should be allowed. [Fact] - public void NameOf() + public void NameOf_02() { var source = @"class Program { - static void Main() + static void F(nint nint) { _ = nameof(nint); _ = nameof(nuint); } }"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8); + comp.VerifyDiagnostics( + // (3,19): error CS8652: The feature 'native-sized integers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static void F(nint nint) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "nint").WithArguments("native-sized integers").WithLocation(3, 19), + // (6,20): error CS8652: The feature 'native-sized integers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // _ = nameof(nuint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "nuint").WithArguments("native-sized integers").WithLocation(6, 20)); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + } + + [Fact] + public void NameOf_03() + { + var source = +@"class Program +{ + static void F() + { + _ = nameof(@nint); + _ = nameof(@nuint); + } +}"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (5,20): error CS0103: The name 'nint' does not exist in the current context - // _ = nameof(nint); - Diagnostic(ErrorCode.ERR_NameNotInContext, "nint").WithArguments("nint").WithLocation(5, 20), + // _ = nameof(@nint); + Diagnostic(ErrorCode.ERR_NameNotInContext, "@nint").WithArguments("nint").WithLocation(5, 20), // (6,20): error CS0103: The name 'nuint' does not exist in the current context - // _ = nameof(nuint); - Diagnostic(ErrorCode.ERR_NameNotInContext, "nuint").WithArguments("nuint").WithLocation(6, 20)); + // _ = nameof(@nuint); + Diagnostic(ErrorCode.ERR_NameNotInContext, "@nuint").WithArguments("nuint").WithLocation(6, 20)); comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyDiagnostics( // (5,20): error CS0103: The name 'nint' does not exist in the current context - // _ = nameof(nint); - Diagnostic(ErrorCode.ERR_NameNotInContext, "nint").WithArguments("nint").WithLocation(5, 20), + // _ = nameof(@nint); + Diagnostic(ErrorCode.ERR_NameNotInContext, "@nint").WithArguments("nint").WithLocation(5, 20), // (6,20): error CS0103: The name 'nuint' does not exist in the current context - // _ = nameof(nuint); - Diagnostic(ErrorCode.ERR_NameNotInContext, "nuint").WithArguments("nuint").WithLocation(6, 20)); + // _ = nameof(@nuint); + Diagnostic(ErrorCode.ERR_NameNotInContext, "@nuint").WithArguments("nuint").WithLocation(6, 20)); + } + + [Fact] + public void NameOf_04() + { + var source = +@"class Program +{ + static void F(int @nint, uint @nuint) + { + _ = nameof(@nint); + _ = nameof(@nuint); + } +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8); + comp.VerifyDiagnostics(); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); } /// @@ -2025,6 +2611,512 @@ static void Main() 4294967295"); } + [Fact] + public void ConstantValue_Properties() + { + var source = +@"class Program +{ + const nint A = int.MinValue; + const nint B = 0; + const nint C = int.MaxValue; + const nuint D = 0; + const nuint E = uint.MaxValue; +}"; + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + verify((FieldSymbol)comp.GetMember("Program.A"), int.MinValue, signed: true, negative: true); + verify((FieldSymbol)comp.GetMember("Program.B"), 0, signed: true, negative: false); + verify((FieldSymbol)comp.GetMember("Program.C"), int.MaxValue, signed: true, negative: false); + verify((FieldSymbol)comp.GetMember("Program.D"), 0U, signed: false, negative: false); + verify((FieldSymbol)comp.GetMember("Program.E"), uint.MaxValue, signed: false, negative: false); + + static void verify(FieldSymbol field, object expectedValue, bool signed, bool negative) + { + var value = field.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false); + Assert.Equal(signed ? ConstantValueTypeDiscriminator.NInt : ConstantValueTypeDiscriminator.NUInt, value.Discriminator); + Assert.Equal(expectedValue, value.Value); + Assert.True(value.IsIntegral); + Assert.True(value.IsNumeric); + Assert.Equal(negative, value.IsNegativeNumeric); + Assert.Equal(!signed, value.IsUnsigned); + } + } + + /// + /// Native integers cannot be used as attribute values. + /// + [Fact] + public void AttributeValue_01() + { + var source0 = +@"class A : System.Attribute +{ + public A() { } + public A(object value) { } + public object Value; +} +[A((nint)1)] +[A(new nuint[0])] +[A(Value = (nint)3)] +[A(Value = new[] { (nuint)4 })] +class B +{ +}"; + var comp = CreateCompilation(source0, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (7,4): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [A((nint)1)] + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "(nint)1").WithLocation(7, 4), + // (8,4): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [A(new nuint[0])] + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "new nuint[0]").WithLocation(8, 4), + // (9,12): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [A(Value = (nint)3)] + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "(nint)3").WithLocation(9, 12), + // (10,12): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [A(Value = new[] { (nuint)4 })] + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "new[] { (nuint)4 }").WithLocation(10, 12)); + } + + /// + /// Native integers cannot be used as attribute values. + /// + [Fact] + public void AttributeValue_02() + { + var source0 = +@"class A : System.Attribute +{ + public A() { } + public A(nint value) { } + public nuint[] Value; +} +[A(1)] +[A(Value = default)] +class B +{ +}"; + var comp = CreateCompilation(source0, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (7,2): error CS0181: Attribute constructor parameter 'value' has type 'nint', which is not a valid attribute parameter type + // [A(1)] + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "A").WithArguments("value", "nint").WithLocation(7, 2), + // (8,4): error CS0655: 'Value' is not a valid named attribute argument because it is not a valid attribute parameter type + // [A(Value = default)] + Diagnostic(ErrorCode.ERR_BadNamedAttributeArgumentType, "Value").WithArguments("Value").WithLocation(8, 4)); + } + + [Fact] + public void ParameterDefaultValue_01() + { + var source = +@"using System; +class A +{ + static void F0(IntPtr x = default, UIntPtr y = default) + { + } + static void F1(IntPtr x = (IntPtr)(-1), UIntPtr y = (UIntPtr)2) + { + } + static void F2(IntPtr? x = null, UIntPtr? y = null) + { + } + static void F3(IntPtr? x = (IntPtr)(-3), UIntPtr? y = (UIntPtr)4) + { + } +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,31): error CS1736: Default parameter value for 'x' must be a compile-time constant + // static void F1(IntPtr x = (IntPtr)(-1), UIntPtr y = (UIntPtr)2) + Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "(IntPtr)(-1)").WithArguments("x").WithLocation(7, 31), + // (7,57): error CS1736: Default parameter value for 'y' must be a compile-time constant + // static void F1(IntPtr x = (IntPtr)(-1), UIntPtr y = (UIntPtr)2) + Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "(UIntPtr)2").WithArguments("y").WithLocation(7, 57), + // (13,32): error CS1736: Default parameter value for 'x' must be a compile-time constant + // static void F3(IntPtr? x = (IntPtr)(-3), UIntPtr? y = (UIntPtr)4) + Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "(IntPtr)(-3)").WithArguments("x").WithLocation(13, 32), + // (13,59): error CS1736: Default parameter value for 'y' must be a compile-time constant + // static void F3(IntPtr? x = (IntPtr)(-3), UIntPtr? y = (UIntPtr)4) + Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "(UIntPtr)4").WithArguments("y").WithLocation(13, 59)); + } + + [Fact] + public void ParameterDefaultValue_02() + { + var sourceA = +@"public class A +{ + public static void F0(nint x = default, nuint y = default) + { + Report(x); + Report(y); + } + public static void F1(nint x = -1, nuint y = 2) + { + Report(x); + Report(y); + } + public static void F2(nint? x = null, nuint? y = null) + { + Report(x); + Report(y); + } + public static void F3(nint? x = -3, nuint? y = 4) + { + Report(x); + Report(y); + } + static void Report(object o) + { + System.Console.WriteLine(o ?? ""null""); + } +}"; + var sourceB = +@"class B +{ + static void Main() + { + A.F0(); + A.F1(); + A.F2(); + A.F3(); + } +}"; + var expectedOutput = +@"0 +0 +-1 +2 +null +null +-3 +4"; + + var comp = CreateCompilation(new[] { sourceA, sourceB }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview); + CompileAndVerify(comp, expectedOutput: expectedOutput); + + comp = CreateCompilation(sourceA, parseOptions: TestOptions.RegularPreview); + var ref1 = comp.ToMetadataReference(); + var ref2 = comp.EmitToImageReference(); + + comp = CreateCompilation(sourceB, references: new[] { ref1 }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview); + CompileAndVerify(comp, expectedOutput: expectedOutput); + + comp = CreateCompilation(sourceB, references: new[] { ref2 }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview); + CompileAndVerify(comp, expectedOutput: expectedOutput); + + comp = CreateCompilation(sourceB, references: new[] { ref1 }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular8); + CompileAndVerify(comp, expectedOutput: expectedOutput); + + comp = CreateCompilation(sourceB, references: new[] { ref2 }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular8); + CompileAndVerify(comp, expectedOutput: expectedOutput); + } + + [Fact] + public void SwitchStatement_01() + { + var source = +@"using System; +class Program +{ + static nint M(nint ret) + { + switch (ret) { + case 0: + ret--; // 2 + Report(""case 0: "", ret); + goto case 9999; + case 2: + ret--; // 4 + Report(""case 2: "", ret); + goto case 255; + case 6: // start here + ret--; // 5 + Report(""case 6: "", ret); + goto case 2; + case 9999: + ret--; // 1 + Report(""case 9999: "", ret); + goto default; + case 0xff: + ret--; // 3 + Report(""case 0xff: "", ret); + goto case 0; + default: + ret--; + Report(""default: "", ret); + if (ret > 0) { + goto case -1; + } + break; + case -1: + ret = 999; + Report(""case -1: "", ret); + break; + } + return(ret); + } + static void Report(string prefix, nint value) + { + Console.WriteLine(prefix + value); + } + static void Main() + { + Console.WriteLine(M(6)); + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview); + var verifier = CompileAndVerify(comp, expectedOutput: +@"case 6: 5 +case 2: 4 +case 0xff: 3 +case 0: 2 +case 9999: 1 +default: 0 +0"); + verifier.VerifyIL("Program.M", +@"{ + // Code size 170 (0xaa) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: brfalse.s IL_0026 + IL_0003: ldarg.0 + IL_0004: ldc.i4.2 + IL_0005: conv.i + IL_0006: beq.s IL_0038 + IL_0008: ldarg.0 + IL_0009: ldc.i4.6 + IL_000a: conv.i + IL_000b: beq.s IL_004a + IL_000d: ldarg.0 + IL_000e: ldc.i4 0x270f + IL_0013: conv.i + IL_0014: beq.s IL_005c + IL_0016: ldarg.0 + IL_0017: ldc.i4 0xff + IL_001c: conv.i + IL_001d: beq.s IL_006e + IL_001f: ldarg.0 + IL_0020: ldc.i4.m1 + IL_0021: conv.i + IL_0022: beq.s IL_0095 + IL_0024: br.s IL_0080 + IL_0026: ldarg.0 + IL_0027: ldc.i4.1 + IL_0028: sub + IL_0029: starg.s V_0 + IL_002b: ldstr ""case 0: "" + IL_0030: ldarg.0 + IL_0031: call ""void Program.Report(string, nint)"" + IL_0036: br.s IL_005c + IL_0038: ldarg.0 + IL_0039: ldc.i4.1 + IL_003a: sub + IL_003b: starg.s V_0 + IL_003d: ldstr ""case 2: "" + IL_0042: ldarg.0 + IL_0043: call ""void Program.Report(string, nint)"" + IL_0048: br.s IL_006e + IL_004a: ldarg.0 + IL_004b: ldc.i4.1 + IL_004c: sub + IL_004d: starg.s V_0 + IL_004f: ldstr ""case 6: "" + IL_0054: ldarg.0 + IL_0055: call ""void Program.Report(string, nint)"" + IL_005a: br.s IL_0038 + IL_005c: ldarg.0 + IL_005d: ldc.i4.1 + IL_005e: sub + IL_005f: starg.s V_0 + IL_0061: ldstr ""case 9999: "" + IL_0066: ldarg.0 + IL_0067: call ""void Program.Report(string, nint)"" + IL_006c: br.s IL_0080 + IL_006e: ldarg.0 + IL_006f: ldc.i4.1 + IL_0070: sub + IL_0071: starg.s V_0 + IL_0073: ldstr ""case 0xff: "" + IL_0078: ldarg.0 + IL_0079: call ""void Program.Report(string, nint)"" + IL_007e: br.s IL_0026 + IL_0080: ldarg.0 + IL_0081: ldc.i4.1 + IL_0082: sub + IL_0083: starg.s V_0 + IL_0085: ldstr ""default: "" + IL_008a: ldarg.0 + IL_008b: call ""void Program.Report(string, nint)"" + IL_0090: ldarg.0 + IL_0091: ldc.i4.0 + IL_0092: conv.i + IL_0093: ble.s IL_00a8 + IL_0095: ldc.i4 0x3e7 + IL_009a: conv.i + IL_009b: starg.s V_0 + IL_009d: ldstr ""case -1: "" + IL_00a2: ldarg.0 + IL_00a3: call ""void Program.Report(string, nint)"" + IL_00a8: ldarg.0 + IL_00a9: ret +}"); + } + + [Fact] + public void SwitchStatement_02() + { + var source = +@"using System; +class Program +{ + static nuint M(nuint ret) + { + switch (ret) { + case 0: + ret--; // 2 + Report(""case 0: "", ret); + goto case 9999; + case 2: + ret--; // 4 + Report(""case 2: "", ret); + goto case 255; + case 6: // start here + ret--; // 5 + Report(""case 6: "", ret); + goto case 2; + case 9999: + ret--; // 1 + Report(""case 9999: "", ret); + goto default; + case 0xff: + ret--; // 3 + Report(""case 0xff: "", ret); + goto case 0; + default: + ret--; + Report(""default: "", ret); + if (ret > 0) { + goto case int.MaxValue; + } + break; + case int.MaxValue: + ret = 999; + Report(""case int.MaxValue: "", ret); + break; + } + return(ret); + } + static void Report(string prefix, nuint value) + { + Console.WriteLine(prefix + value); + } + static void Main() + { + Console.WriteLine(M(6)); + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview); + var verifier = CompileAndVerify(comp, expectedOutput: +@"case 6: 5 +case 2: 4 +case 0xff: 3 +case 0: 2 +case 9999: 1 +default: 0 +0"); + verifier.VerifyIL("Program.M", +@"{ + // Code size 174 (0xae) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: brfalse.s IL_002a + IL_0003: ldarg.0 + IL_0004: ldc.i4.2 + IL_0005: conv.i + IL_0006: beq.s IL_003c + IL_0008: ldarg.0 + IL_0009: ldc.i4.6 + IL_000a: conv.i + IL_000b: beq.s IL_004e + IL_000d: ldarg.0 + IL_000e: ldc.i4 0x270f + IL_0013: conv.i + IL_0014: beq.s IL_0060 + IL_0016: ldarg.0 + IL_0017: ldc.i4 0xff + IL_001c: conv.i + IL_001d: beq.s IL_0072 + IL_001f: ldarg.0 + IL_0020: ldc.i4 0x7fffffff + IL_0025: conv.i + IL_0026: beq.s IL_0099 + IL_0028: br.s IL_0084 + IL_002a: ldarg.0 + IL_002b: ldc.i4.1 + IL_002c: sub + IL_002d: starg.s V_0 + IL_002f: ldstr ""case 0: "" + IL_0034: ldarg.0 + IL_0035: call ""void Program.Report(string, nuint)"" + IL_003a: br.s IL_0060 + IL_003c: ldarg.0 + IL_003d: ldc.i4.1 + IL_003e: sub + IL_003f: starg.s V_0 + IL_0041: ldstr ""case 2: "" + IL_0046: ldarg.0 + IL_0047: call ""void Program.Report(string, nuint)"" + IL_004c: br.s IL_0072 + IL_004e: ldarg.0 + IL_004f: ldc.i4.1 + IL_0050: sub + IL_0051: starg.s V_0 + IL_0053: ldstr ""case 6: "" + IL_0058: ldarg.0 + IL_0059: call ""void Program.Report(string, nuint)"" + IL_005e: br.s IL_003c + IL_0060: ldarg.0 + IL_0061: ldc.i4.1 + IL_0062: sub + IL_0063: starg.s V_0 + IL_0065: ldstr ""case 9999: "" + IL_006a: ldarg.0 + IL_006b: call ""void Program.Report(string, nuint)"" + IL_0070: br.s IL_0084 + IL_0072: ldarg.0 + IL_0073: ldc.i4.1 + IL_0074: sub + IL_0075: starg.s V_0 + IL_0077: ldstr ""case 0xff: "" + IL_007c: ldarg.0 + IL_007d: call ""void Program.Report(string, nuint)"" + IL_0082: br.s IL_002a + IL_0084: ldarg.0 + IL_0085: ldc.i4.1 + IL_0086: sub + IL_0087: starg.s V_0 + IL_0089: ldstr ""default: "" + IL_008e: ldarg.0 + IL_008f: call ""void Program.Report(string, nuint)"" + IL_0094: ldarg.0 + IL_0095: ldc.i4.0 + IL_0096: conv.i + IL_0097: ble.un.s IL_00ac + IL_0099: ldc.i4 0x3e7 + IL_009e: conv.i + IL_009f: starg.s V_0 + IL_00a1: ldstr ""case int.MaxValue: "" + IL_00a6: ldarg.0 + IL_00a7: call ""void Program.Report(string, nuint)"" + IL_00ac: ldarg.0 + IL_00ad: ret +}"); + } + [Fact] public void Conversions() { @@ -6362,6 +7454,7 @@ public void ConstantFolding() binaryOperator("bool", "!=", "nuint", "0", "nuint", uintMaxValue, "True"); binaryOperator("bool", "!=", "nuint", uintMaxValue, "nuint", uintMaxValue, "False"); + // PROTOTYPE: Some results of `<<` should be dependent on platform. See https://github.com/dotnet/roslyn/pull/42143#discussion_r389955804. binaryOperator("nint", "<<", "nint", intMinValue, "int", "0", intMinValue); binaryOperator("nint", "<<", "nint", intMinValue, "int", "1", "0"); binaryOperator("nint", "<<", "nint", "-1", "int", "31", intMinValue); diff --git a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs index 219ec3babfa5e07f6204015effa9964a7299a5c5..62f4e1922d183e01c4a2506bff2852682107a5cd 100644 --- a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs @@ -7222,15 +7222,15 @@ class B static void F4(nint[] x, A y) { } }"; var comp = CreateCompilation(new[] { source }, parseOptions: TestOptions.RegularPreview); - var formatWithoutSpecialTypes = new SymbolDisplayFormat( + var formatWithoutOptions = new SymbolDisplayFormat( memberOptions: SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeType | SymbolDisplayMemberOptions.IncludeModifiers, parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeName, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters); - var formatWithSpecialTypes = formatWithoutSpecialTypes.AddMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes); + var formatWithUnderlyingTypes = formatWithoutOptions.WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.UseNativeIntegerUnderlyingType); var method = comp.GetMember("B.F1"); Verify( - method.ToDisplayParts(formatWithoutSpecialTypes), + method.ToDisplayParts(formatWithUnderlyingTypes), "static void F1(IntPtr x, UIntPtr y)", SymbolDisplayPartKind.Keyword, SymbolDisplayPartKind.Space, @@ -7248,7 +7248,7 @@ class B SymbolDisplayPartKind.ParameterName, SymbolDisplayPartKind.Punctuation); Verify( - method.ToDisplayParts(formatWithSpecialTypes), + method.ToDisplayParts(formatWithoutOptions), "static void F1(nint x, nuint y)", SymbolDisplayPartKind.Keyword, SymbolDisplayPartKind.Space, @@ -7265,29 +7265,32 @@ class B SymbolDisplayPartKind.Space, SymbolDisplayPartKind.ParameterName, SymbolDisplayPartKind.Punctuation); + Verify( + method.ToDisplayParts(formatWithoutOptions.AddMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes)), + "static void F1(nint x, nuint y)"); method = comp.GetMember("B.F2"); Verify( - method.ToDisplayParts(formatWithoutSpecialTypes), + method.ToDisplayParts(formatWithUnderlyingTypes), "static void F2(IntPtr x, IntPtr y)"); Verify( - method.ToDisplayParts(formatWithSpecialTypes), + method.ToDisplayParts(formatWithoutOptions), "static void F2(nint x, IntPtr y)"); method = comp.GetMember("B.F3"); Verify( - method.ToDisplayParts(formatWithoutSpecialTypes), + method.ToDisplayParts(formatWithUnderlyingTypes), "static void F3(IntPtr? x, UIntPtr? y)"); Verify( - method.ToDisplayParts(formatWithSpecialTypes), + method.ToDisplayParts(formatWithoutOptions), "static void F3(nint? x, UIntPtr? y)"); method = comp.GetMember("B.F4"); Verify( - method.ToDisplayParts(formatWithoutSpecialTypes), + method.ToDisplayParts(formatWithUnderlyingTypes), "static void F4(IntPtr[] x, A y)"); Verify( - method.ToDisplayParts(formatWithSpecialTypes), + method.ToDisplayParts(formatWithoutOptions), "static void F4(nint[] x, A y)"); } } diff --git a/src/Compilers/Core/Portable/ConstantValue.cs b/src/Compilers/Core/Portable/ConstantValue.cs index 3b649ccc48d162dfb6291ca14e99d280ef4a2648..4039aa3c728a3370a31470dfdb3399b6e9c350f3 100644 --- a/src/Compilers/Core/Portable/ConstantValue.cs +++ b/src/Compilers/Core/Portable/ConstantValue.cs @@ -454,7 +454,6 @@ internal static ConstantValueTypeDiscriminator GetDiscriminator(SpecialType st) return ConstantValueTypeDiscriminator.Bad; } - // PROTOTYPE: Include NInt and NUint. private static SpecialType GetSpecialType(ConstantValueTypeDiscriminator discriminator) { switch (discriminator) @@ -467,6 +466,8 @@ private static SpecialType GetSpecialType(ConstantValueTypeDiscriminator discrim case ConstantValueTypeDiscriminator.UInt32: return SpecialType.System_UInt32; case ConstantValueTypeDiscriminator.Int64: return SpecialType.System_Int64; case ConstantValueTypeDiscriminator.UInt64: return SpecialType.System_UInt64; + case ConstantValueTypeDiscriminator.NInt: return SpecialType.System_IntPtr; + case ConstantValueTypeDiscriminator.NUInt: return SpecialType.System_UIntPtr; case ConstantValueTypeDiscriminator.Char: return SpecialType.System_Char; case ConstantValueTypeDiscriminator.Boolean: return SpecialType.System_Boolean; case ConstantValueTypeDiscriminator.Single: return SpecialType.System_Single; @@ -508,7 +509,6 @@ private static SpecialType GetSpecialType(ConstantValueTypeDiscriminator discrim } } - // PROTOTYPE: Include NInt and NUint. public static bool IsIntegralType(ConstantValueTypeDiscriminator discriminator) { switch (discriminator) @@ -521,6 +521,8 @@ public static bool IsIntegralType(ConstantValueTypeDiscriminator discriminator) case ConstantValueTypeDiscriminator.UInt32: case ConstantValueTypeDiscriminator.Int64: case ConstantValueTypeDiscriminator.UInt64: + case ConstantValueTypeDiscriminator.NInt: + case ConstantValueTypeDiscriminator.NUInt: return true; default: @@ -536,7 +538,6 @@ public bool IsIntegral } } - // PROTOTYPE: Include NInt and NUint. public bool IsNegativeNumeric { get @@ -548,6 +549,7 @@ public bool IsNegativeNumeric case ConstantValueTypeDiscriminator.Int16: return Int16Value < 0; case ConstantValueTypeDiscriminator.Int32: + case ConstantValueTypeDiscriminator.NInt: return Int32Value < 0; case ConstantValueTypeDiscriminator.Int64: return Int64Value < 0; @@ -564,7 +566,6 @@ public bool IsNegativeNumeric } } - // PROTOTYPE: Include NInt and NUint. public bool IsNumeric { get @@ -582,6 +583,8 @@ public bool IsNumeric case ConstantValueTypeDiscriminator.UInt16: case ConstantValueTypeDiscriminator.UInt32: case ConstantValueTypeDiscriminator.UInt64: + case ConstantValueTypeDiscriminator.NInt: + case ConstantValueTypeDiscriminator.NUInt: return true; default: @@ -590,7 +593,6 @@ public bool IsNumeric } } - // PROTOTYPE: Include NInt and NUint. public static bool IsUnsignedIntegralType(ConstantValueTypeDiscriminator discriminator) { switch (discriminator) @@ -599,6 +601,7 @@ public static bool IsUnsignedIntegralType(ConstantValueTypeDiscriminator discrim case ConstantValueTypeDiscriminator.UInt16: case ConstantValueTypeDiscriminator.UInt32: case ConstantValueTypeDiscriminator.UInt64: + case ConstantValueTypeDiscriminator.NUInt: return true; default: @@ -718,7 +721,6 @@ public bool IsNothing } } - // PROTOTYPE: Include NInt and NUint. public void Serialize(BlobBuilder writer) { switch (this.Discriminator) diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs index 613458ebf20616141cfe644478ce72cd9d83cbdf..f965f273c4782f494f2dc0d2de9906ada4dc993f 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis { @@ -56,5 +55,10 @@ internal enum SymbolDisplayCompilerInternalOptions /// Display `System.ValueTuple` instead of tuple syntax `(...)`. /// UseValueTuple = 1 << 6, + + /// + /// Display `System.[U]IntPtr` instead of `n[u]int`. + /// + UseNativeIntegerUnderlyingType = 1 << 7, } } diff --git a/src/Compilers/Test/Utilities/CSharp/NativeIntegerAttributesVisitor.cs b/src/Compilers/Test/Utilities/CSharp/NativeIntegerAttributesVisitor.cs index 9bfb7566cb0fd717d6e3d1217c348a6968f9bc48..0a5bc00d0bf42cee1b9c73a4d7ddd7187fb37518 100644 --- a/src/Compilers/Test/Utilities/CSharp/NativeIntegerAttributesVisitor.cs +++ b/src/Compilers/Test/Utilities/CSharp/NativeIntegerAttributesVisitor.cs @@ -131,7 +131,8 @@ private static string GetIndentString(Symbol symbol) SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeType | SymbolDisplayMemberOptions.IncludeRef | - SymbolDisplayMemberOptions.IncludeExplicitInterface); + SymbolDisplayMemberOptions.IncludeExplicitInterface). + WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.UseNativeIntegerUnderlyingType); private void ReportContainingSymbols(Symbol symbol) {