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