// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Immutable;
using System.Linq;
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.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
{
public class NativeIntegerTests : CSharpTestBase
{
[Fact]
public void LanguageVersion()
{
var source =
@"interface I
{
nint Add(nint x, nuint y);
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (3,5): error CS8652: The feature 'native-sized integers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// nint Add(nint x, nuint y);
Diagnostic(ErrorCode.ERR_FeatureInPreview, "nint").WithArguments("native-sized integers").WithLocation(3, 5),
// (3,14): error CS8652: The feature 'native-sized integers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// nint Add(nint x, nuint y);
Diagnostic(ErrorCode.ERR_FeatureInPreview, "nint").WithArguments("native-sized integers").WithLocation(3, 14),
// (3,22): error CS8652: The feature 'native-sized integers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// nint Add(nint x, nuint y);
Diagnostic(ErrorCode.ERR_FeatureInPreview, "nuint").WithArguments("native-sized integers").WithLocation(3, 22));
comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics();
}
///
/// System.IntPtr and System.UIntPtr definitions from metadata.
///
[Fact]
public void TypeDefinitions_FromMetadata()
{
var source =
@"interface I
{
void F1(System.IntPtr x, nint y);
void F2(System.UIntPtr x, nuint y);
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics();
var type = comp.GetTypeByMetadataName("System.IntPtr");
VerifyType(type, signed: true, isNativeInt: false);
VerifyType(type.GetPublicSymbol(), signed: true, isNativeInt: false);
type = comp.GetTypeByMetadataName("System.UIntPtr");
VerifyType(type, signed: false, isNativeInt: false);
VerifyType(type.GetPublicSymbol(), signed: false, isNativeInt: false);
var method = comp.GetMember("I.F1");
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.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);
}
///
/// System.IntPtr and System.UIntPtr definitions from source.
///
[Fact]
public void TypeDefinitions_FromSource()
{
var sourceA =
@"namespace System
{
public class Object
{
public virtual string ToString() => null;
public virtual int GetHashCode() => 0;
public virtual bool Equals(object obj) => false;
}
public class String { }
public abstract class ValueType
{
public override string ToString() => null;
public override int GetHashCode() => 0;
public override bool Equals(object obj) => false;
}
public struct Void { }
public struct Boolean { }
public struct Int32 { }
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 : 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 =
@"interface I
{
void F1(System.IntPtr x, nint y);
void F2(System.UIntPtr x, nuint y);
}";
var comp = CreateEmptyCompilation(new[] { sourceA, sourceB }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics();
verify(comp);
comp = CreateEmptyCompilation(sourceA);
comp.VerifyDiagnostics();
var ref1 = comp.ToMetadataReference();
var ref2 = comp.EmitToImageReference();
comp = CreateEmptyCompilation(sourceB, references: new[] { ref1 }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics();
verify(comp);
comp = CreateEmptyCompilation(sourceB, references: new[] { ref2 }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics();
verify(comp);
static void verify(CSharpCompilation comp)
{
var type = comp.GetTypeByMetadataName("System.IntPtr");
VerifyType(type, signed: true, isNativeInt: false);
VerifyType(type.GetPublicSymbol(), signed: true, isNativeInt: false);
type = comp.GetTypeByMetadataName("System.UIntPtr");
VerifyType(type, signed: false, isNativeInt: false);
VerifyType(type.GetPublicSymbol(), signed: false, isNativeInt: false);
var method = comp.GetMember("I.F1");
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.ToTestDisplayString());
VerifyTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: false);
}
}
private static void VerifyType(NamedTypeSymbol type, bool signed, bool isNativeInt)
{
Assert.Equal(signed ? SpecialType.System_IntPtr : SpecialType.System_UIntPtr, type.SpecialType);
Assert.Equal(SymbolKind.NamedType, type.Kind);
Assert.Equal(TypeKind.Struct, type.TypeKind);
Assert.Same(type, type.ConstructedFrom);
Assert.Equal(isNativeInt, type.IsNativeIntegerType);
Assert.Equal(signed ? "IntPtr" : "UIntPtr", type.Name);
if (isNativeInt)
{
VerifyMembers(type);
}
}
private static void VerifyType(INamedTypeSymbol type, bool signed, bool isNativeInt)
{
Assert.Equal(signed ? SpecialType.System_IntPtr : SpecialType.System_UIntPtr, type.SpecialType);
Assert.Equal(SymbolKind.NamedType, type.Kind);
Assert.Equal(TypeKind.Struct, type.TypeKind);
Assert.Same(type, type.ConstructedFrom);
Assert.Equal(isNativeInt, type.IsNativeIntegerType);
Assert.Equal(signed ? "IntPtr" : "UIntPtr", type.Name);
}
private static void VerifyTypes(INamedTypeSymbol underlyingType, INamedTypeSymbol nativeIntegerType, bool signed)
{
VerifyType(underlyingType, signed, isNativeInt: false);
VerifyType(nativeIntegerType, signed, isNativeInt: true);
Assert.Same(underlyingType.ContainingSymbol, nativeIntegerType.ContainingSymbol);
Assert.Same(underlyingType.Name, nativeIntegerType.Name);
Assert.Empty(nativeIntegerType.GetTypeMembers());
var memberNames = nativeIntegerType.MemberNames;
var members = nativeIntegerType.GetMembers();
Assert.Equal(members.SelectAsArray(m => m.Name), memberNames);
var baseMembers = members.SelectAsArray(m => ((IMethodSymbol)m).OverriddenMethod);
Assert.Empty(baseMembers);
verifyInterfaces(underlyingType, underlyingType.Interfaces, nativeIntegerType, nativeIntegerType.Interfaces);
Assert.NotSame(underlyingType, nativeIntegerType);
Assert.Same(underlyingType, nativeIntegerType.NativeIntegerUnderlyingType);
Assert.Equal(underlyingType, nativeIntegerType);
Assert.Equal(nativeIntegerType, underlyingType);
Assert.True(underlyingType.Equals(nativeIntegerType));
Assert.True(((IEquatable)underlyingType).Equals(nativeIntegerType));
Assert.True(underlyingType.Equals(nativeIntegerType, SymbolEqualityComparer.Default));
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)
{
VerifyType(underlyingType, signed, isNativeInt: false);
VerifyType(nativeIntegerType, signed, isNativeInt: true);
Assert.Same(underlyingType.ContainingSymbol, nativeIntegerType.ContainingSymbol);
Assert.Same(underlyingType.Name, nativeIntegerType.Name);
Assert.Empty(nativeIntegerType.GetTypeMembers());
var memberNames = nativeIntegerType.MemberNames;
var members = nativeIntegerType.GetMembers();
Assert.Equal(members.SelectAsArray(m => m.Name), memberNames);
var baseMembers = members.SelectAsArray(m => ((MethodSymbol)m).OverriddenMethod);
Assert.Empty(baseMembers);
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());
Assert.Same(underlyingType, nativeIntegerType.NativeIntegerUnderlyingType);
verifyEqualButDistinct(underlyingType, underlyingType.AsNativeInteger());
verifyEqualButDistinct(nativeIntegerType, nativeIntegerType.NativeIntegerUnderlyingType);
verifyEqualButDistinct(underlyingType, nativeIntegerType);
VerifyTypes(underlyingType.GetPublicSymbol(), nativeIntegerType.GetPublicSymbol(), signed);
static void verifyEqualButDistinct(NamedTypeSymbol underlyingType, NamedTypeSymbol nativeIntegerType)
{
Assert.NotSame(underlyingType, nativeIntegerType);
Assert.Equal(underlyingType, nativeIntegerType);
Assert.Equal(nativeIntegerType, underlyingType);
Assert.True(underlyingType.Equals(nativeIntegerType, TypeCompareKind.ConsiderEverything));
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)
{
var memberNames = type.MemberNames;
var allMembers = type.GetMembers();
Assert.Equal(allMembers, type.GetMembers(), ReferenceEqualityComparer.Instance);
foreach (var member in allMembers)
{
Assert.Contains(member.Name, memberNames);
verifyMember(type, member);
}
var unorderedMembers = type.GetMembersUnordered();
Assert.Equal(allMembers.Length, unorderedMembers.Length);
verifyMembers(type, allMembers, unorderedMembers);
foreach (var memberName in memberNames)
{
var members = type.GetMembers(memberName);
Assert.False(members.IsDefaultOrEmpty);
verifyMembers(type, allMembers, members);
}
static void verifyMembers(NamedTypeSymbol type, ImmutableArray allMembers, ImmutableArray members)
{
foreach (var member in members)
{
Assert.Contains(member, allMembers);
verifyMember(type, member);
}
}
static void verifyMember(NamedTypeSymbol type, Symbol member)
{
Assert.Same(type, member.ContainingSymbol);
Assert.Same(type, member.ContainingType);
}
}
[Fact]
public void MissingTypes()
{
var sourceA =
@"namespace System
{
public class Object { }
public abstract class ValueType { }
public struct Void { }
}";
var sourceB =
@"interface I
{
void F1(System.IntPtr x, nint y);
void F2(System.UIntPtr x, nuint y);
}";
var diagnostics = new[]
{
// (3,20): error CS0234: The underlyingType or namespace name 'IntPtr' does not exist in the namespace 'System' (are you missing an assembly reference?)
// void F1(System.IntPtr x, nint y);
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "IntPtr").WithArguments("IntPtr", "System").WithLocation(3, 20),
// (3,30): error CS0518: Predefined underlyingType 'System.IntPtr' is not defined or imported
// void F1(System.IntPtr x, nint y);
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "nint").WithArguments("System.IntPtr").WithLocation(3, 30),
// (4,20): error CS0234: The underlyingType or namespace name 'UIntPtr' does not exist in the namespace 'System' (are you missing an assembly reference?)
// void F2(System.UIntPtr x, nuint y);
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "UIntPtr").WithArguments("UIntPtr", "System").WithLocation(4, 20),
// (4,31): error CS0518: Predefined underlyingType 'System.UIntPtr' is not defined or imported
// void F2(System.UIntPtr x, nuint y);
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "nuint").WithArguments("System.UIntPtr").WithLocation(4, 31)
};
var comp = CreateEmptyCompilation(new[] { sourceA, sourceB }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(diagnostics);
verify(comp);
comp = CreateEmptyCompilation(sourceA);
comp.VerifyDiagnostics();
var ref1 = comp.ToMetadataReference();
var ref2 = comp.EmitToImageReference();
comp = CreateEmptyCompilation(sourceB, references: new[] { ref1 }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(diagnostics);
verify(comp);
comp = CreateEmptyCompilation(sourceB, references: new[] { ref2 }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(diagnostics);
verify(comp);
static void verify(CSharpCompilation comp)
{
var method = comp.GetMember("I.F1");
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.ToTestDisplayString());
VerifyErrorTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: false);
}
}
private static void VerifyErrorType(NamedTypeSymbol type, SpecialType specialType, bool isNativeInt)
{
Assert.Equal(SymbolKind.ErrorType, type.Kind);
Assert.Equal(TypeKind.Error, type.TypeKind);
Assert.Equal(isNativeInt, type.IsNativeIntegerType);
Assert.Equal(specialType, type.SpecialType);
}
private static void VerifyErrorType(INamedTypeSymbol type, SpecialType specialType, bool isNativeInt)
{
Assert.Equal(SymbolKind.ErrorType, type.Kind);
Assert.Equal(TypeKind.Error, type.TypeKind);
Assert.Equal(isNativeInt, type.IsNativeIntegerType);
Assert.Equal(specialType, type.SpecialType);
}
private static void VerifyErrorTypes(NamedTypeSymbol underlyingType, NamedTypeSymbol nativeIntegerType, bool signed)
{
var specialType = signed ? SpecialType.System_IntPtr : SpecialType.System_UIntPtr;
VerifyErrorType(underlyingType, SpecialType.None, isNativeInt: false);
VerifyErrorType(nativeIntegerType, specialType, isNativeInt: true);
Assert.Null(underlyingType.NativeIntegerUnderlyingType);
VerifyErrorType(nativeIntegerType.NativeIntegerUnderlyingType, specialType, isNativeInt: false);
VerifyErrorTypes(underlyingType.GetPublicSymbol(), nativeIntegerType.GetPublicSymbol(), signed);
}
private static void VerifyErrorTypes(INamedTypeSymbol underlyingType, INamedTypeSymbol nativeIntegerType, bool signed)
{
var specialType = signed ? SpecialType.System_IntPtr : SpecialType.System_UIntPtr;
VerifyErrorType(underlyingType, SpecialType.None, isNativeInt: false);
VerifyErrorType(nativeIntegerType, specialType, isNativeInt: true);
Assert.Null(underlyingType.NativeIntegerUnderlyingType);
VerifyErrorType(nativeIntegerType.NativeIntegerUnderlyingType, specialType, isNativeInt: false);
}
[Fact]
public void Retargeting_01()
{
var sourceA =
@"public class A
{
public static nint F1 = int.MinValue;
public static nuint F2 = int.MaxValue;
public static nint F3 = -1;
public static nuint F4 = 1;
}";
var comp = CreateCompilation(sourceA, parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.Mscorlib40);
var refA = comp.ToMetadataReference();
var typeA = comp.GetMember("A.F1").Type;
var corLibA = comp.Assembly.CorLibrary;
Assert.Equal(corLibA, typeA.ContainingAssembly);
var sourceB =
@"class B : A
{
static void Main()
{
System.Console.WriteLine(""{0}, {1}, {2}, {3}"", F1, F2, F3, F4);
}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.Mscorlib45);
CompileAndVerify(comp, expectedOutput: $"{int.MinValue}, {int.MaxValue}, -1, 1");
var corLibB = comp.Assembly.CorLibrary;
Assert.NotEqual(corLibA, corLibB);
var f1 = comp.GetMember("A.F1");
verifyField(f1, "nint A.F1", corLibB);
var f2 = comp.GetMember("A.F2");
verifyField(f2, "nuint A.F2", corLibB);
var f3 = comp.GetMember("A.F3");
verifyField(f3, "nint A.F3", corLibB);
var f4 = comp.GetMember("A.F4");
verifyField(f4, "nuint A.F4", corLibB);
Assert.Same(f1.Type, f3.Type);
Assert.Same(f2.Type, f4.Type);
static void verifyField(FieldSymbol field, string expectedSymbol, AssemblySymbol expectedAssembly)
{
Assert.IsType(field);
Assert.Equal(expectedSymbol, field.ToTestDisplayString());
var type = (NamedTypeSymbol)field.Type;
Assert.True(type.IsNativeIntegerType);
Assert.IsType(type);
Assert.Equal(expectedAssembly, type.NativeIntegerUnderlyingType.ContainingAssembly);
}
}
[Fact]
public void Retargeting_02()
{
var source1 =
@"namespace System
{
public class Object { }
public class String { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
public struct Int32 { }
public struct IntPtr { }
public struct UIntPtr { }
}";
var assemblyName = GetUniqueName();
var comp = CreateCompilation(new AssemblyIdentity(assemblyName, new Version(1, 0, 0, 0)), new[] { source1 }, references: null);
var ref1 = comp.EmitToImageReference();
var sourceA =
@"public class A
{
public static nint F1 = -1;
public static nuint F2 = 1;
public static nint F3 = -2;
public static nuint F4 = 2;
}";
comp = CreateEmptyCompilation(sourceA, references: new[] { ref1 }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics();
var refA = comp.ToMetadataReference();
var typeA = comp.GetMember("A.F1").Type;
var corLibA = comp.Assembly.CorLibrary;
Assert.Equal(corLibA, typeA.ContainingAssembly);
var source2 =
@"namespace System
{
public class Object { }
public class String { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
public struct Int32 { }
}";
comp = CreateCompilation(new AssemblyIdentity(assemblyName, new Version(2, 0, 0, 0)), new[] { source2 }, references: null);
var ref2 = comp.EmitToImageReference();
var sourceB =
@"class B : A
{
static void Main()
{
_ = F1;
_ = F2;
}
}";
comp = CreateEmptyCompilation(sourceB, references: new[] { ref2, refA }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(
// (5,13): error CS0518: Predefined type 'System.IntPtr' is not defined or imported
// _ = F1;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "F1").WithArguments("System.IntPtr").WithLocation(5, 13),
// (6,13): error CS0518: Predefined type 'System.UIntPtr' is not defined or imported
// _ = F2;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "F2").WithArguments("System.UIntPtr").WithLocation(6, 13));
var corLibB = comp.Assembly.CorLibrary;
Assert.NotEqual(corLibA, corLibB);
var f1 = comp.GetMember("A.F1");
verifyField(f1, "nint A.F1", corLibB);
var f2 = comp.GetMember("A.F2");
verifyField(f2, "nuint A.F2", corLibB);
var f3 = comp.GetMember("A.F3");
verifyField(f3, "nint A.F3", corLibB);
var f4 = comp.GetMember("A.F4");
verifyField(f4, "nuint A.F4", corLibB);
// MissingMetadataTypeSymbol.TopLevel instances are not reused.
Assert.Equal(f1.Type, f3.Type);
Assert.NotSame(f1.Type, f3.Type);
Assert.Equal(f2.Type, f4.Type);
Assert.NotSame(f2.Type, f4.Type);
static void verifyField(FieldSymbol field, string expectedSymbol, AssemblySymbol expectedAssembly)
{
Assert.IsType(field);
Assert.Equal(expectedSymbol, field.ToTestDisplayString());
var type = (NamedTypeSymbol)field.Type;
Assert.True(type.IsNativeIntegerType);
Assert.IsType(type);
Assert.Equal(expectedAssembly, type.NativeIntegerUnderlyingType.ContainingAssembly);
}
}
[Fact]
public void Retargeting_03()
{
var source1 =
@"namespace System
{
public class Object { }
public class String { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
public struct Int32 { }
}";
var assemblyName = GetUniqueName();
var comp = CreateCompilation(new AssemblyIdentity(assemblyName, new Version(1, 0, 0, 0)), new[] { source1 }, references: null);
var ref1 = comp.EmitToImageReference();
var sourceA =
@"public class A
{
public static nint F1 = -1;
public static nuint F2 = 1;
}";
comp = CreateEmptyCompilation(sourceA, references: new[] { ref1 }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(
// (3,19): error CS0518: Predefined type 'System.IntPtr' is not defined or imported
// public static nint F1 = -1;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "nint").WithArguments("System.IntPtr").WithLocation(3, 19),
// (4,19): error CS0518: Predefined type 'System.UIntPtr' is not defined or imported
// public static nuint F2 = 1;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "nuint").WithArguments("System.UIntPtr").WithLocation(4, 19));
var refA = comp.ToMetadataReference();
var typeA = comp.GetMember("A.F1").Type;
var corLibA = comp.Assembly.CorLibrary;
Assert.Equal(corLibA, typeA.ContainingAssembly);
var source2 =
@"namespace System
{
public class Object { }
public class String { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
public struct Int32 { }
public struct IntPtr { }
public struct UIntPtr { }
}";
comp = CreateCompilation(new AssemblyIdentity(assemblyName, new Version(2, 0, 0, 0)), new[] { source2 }, references: null);
var ref2 = comp.EmitToImageReference();
var sourceB =
@"class B : A
{
static void Main()
{
_ = F1;
_ = F2;
}
}";
comp = CreateEmptyCompilation(sourceB, references: new[] { ref2, refA }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(
// (5,13): error CS0518: Predefined type 'System.IntPtr' is not defined or imported
// _ = F1;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "F1").WithArguments("System.IntPtr").WithLocation(5, 13),
// (6,13): error CS0518: Predefined type 'System.UIntPtr' is not defined or imported
// _ = F2;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "F2").WithArguments("System.UIntPtr").WithLocation(6, 13));
var corLibB = comp.Assembly.CorLibrary;
Assert.NotEqual(corLibA, corLibB);
var f1 = comp.GetMember("A.F1");
verifyField(f1, "nint A.F1", corLibA);
var f2 = comp.GetMember("A.F2");
verifyField(f2, "nuint A.F2", corLibA);
static void verifyField(FieldSymbol field, string expectedSymbol, AssemblySymbol expectedAssembly)
{
Assert.IsType(field);
Assert.Equal(expectedSymbol, field.ToTestDisplayString());
var type = (NamedTypeSymbol)field.Type;
Assert.True(type.IsNativeIntegerType);
Assert.IsType(type);
Assert.Equal(expectedAssembly, type.NativeIntegerUnderlyingType.ContainingAssembly);
}
}
[Fact]
public void Retargeting_04()
{
var sourceA =
@"public class A
{
}";
var assemblyName = GetUniqueName();
var references = TargetFrameworkUtil.GetReferences(TargetFramework.Standard).ToArray();
var comp = CreateCompilation(new AssemblyIdentity(assemblyName, new Version(1, 0, 0, 0)), new[] { sourceA }, references: references);
var refA1 = comp.EmitToImageReference();
comp = CreateCompilation(new AssemblyIdentity(assemblyName, new Version(2, 0, 0, 0)), new[] { sourceA }, references: references);
var refA2 = comp.EmitToImageReference();
var sourceB =
@"public class B
{
public static A F0 = new A();
public static nint F1 = int.MinValue;
public static nuint F2 = int.MaxValue;
public static nint F3 = -1;
public static nuint F4 = 1;
}";
comp = CreateCompilation(sourceB, references: new[] { refA1 }, parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.Standard);
var refB = comp.ToMetadataReference();
var f0B = comp.GetMember("B.F0");
var t1B = comp.GetMember("B.F1").Type;
var t2B = comp.GetMember("B.F2").Type;
var sourceC =
@"class C : B
{
static void Main()
{
_ = F0;
_ = F1;
_ = F2;
}
}";
comp = CreateCompilation(sourceC, references: new[] { refA2, refB }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.Standard);
comp.VerifyDiagnostics();
var f0 = comp.GetMember("B.F0");
Assert.NotEqual(f0B.Type.ContainingAssembly, f0.Type.ContainingAssembly);
Assert.IsType(f0);
var f1 = comp.GetMember("B.F1");
verifyField(f1, "nint B.F1");
var f2 = comp.GetMember("B.F2");
verifyField(f2, "nuint B.F2");
var f3 = comp.GetMember("B.F3");
verifyField(f3, "nint B.F3");
var f4 = comp.GetMember("B.F4");
verifyField(f4, "nuint B.F4");
Assert.Same(t1B, f1.Type);
Assert.Same(t2B, f2.Type);
Assert.Same(f1.Type, f3.Type);
Assert.Same(f2.Type, f4.Type);
static void verifyField(FieldSymbol field, string expectedSymbol)
{
Assert.IsType(field);
Assert.Equal(expectedSymbol, field.ToTestDisplayString());
var type = (NamedTypeSymbol)field.Type;
Assert.True(type.IsNativeIntegerType);
Assert.IsType(type);
}
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public void Retargeting_05(bool useCompilationReference)
{
var source1 =
@"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 struct IntPtr { }
public struct UIntPtr { }
}";
var comp = CreateCompilation(new AssemblyIdentity("9ef8b1e0-1ae0-4af6-b9a1-00f2078f299e", new Version(1, 0, 0, 0)), new[] { source1 }, references: null);
var ref1 = comp.EmitToImageReference(EmitOptions.Default.WithRuntimeMetadataVersion("0.0.0.0"));
var sourceA =
@"public abstract class A
{
public abstract void F() where U : T;
}
public class B : A
{
public override void F() { }
}";
comp = CreateEmptyCompilation(sourceA, references: new[] { ref1 }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var type1 = getConstraintType(comp);
Assert.True(type1.IsNativeIntegerType);
Assert.False(type1.IsErrorType());
var sourceB =
@"class C : B
{
}";
comp = CreateEmptyCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(
// (1,7): error CS0518: Predefined type 'System.Void' is not defined or imported
// class C : B
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "C").WithArguments("System.Void").WithLocation(1, 7),
// (1,11): error CS0518: Predefined type 'System.IntPtr' is not defined or imported
// class C : B
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "B").WithArguments("System.IntPtr").WithLocation(1, 11),
// (1,11): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly '9ef8b1e0-1ae0-4af6-b9a1-00f2078f299e, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
// class C : B
Diagnostic(ErrorCode.ERR_NoTypeDef, "B").WithArguments("System.Object", "9ef8b1e0-1ae0-4af6-b9a1-00f2078f299e, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 11));
var type2 = getConstraintType(comp);
Assert.True(type2.ContainingAssembly.IsMissing);
Assert.False(type2.IsNativeIntegerType);
Assert.True(type2.IsErrorType());
static TypeSymbol getConstraintType(CSharpCompilation comp) =>
comp.GetMember("B.F").TypeParameters[0].ConstraintTypesNoUseSiteDiagnostics[0].Type;
}
[Fact]
public void Retargeting_06()
{
var source1 =
@"namespace System
{
public class Object { }
public class String { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
public struct Int32 { }
public class IntPtr { }
public class UIntPtr { }
}";
var comp = CreateCompilation(new AssemblyIdentity("c804cc09-8f73-44a1-9cfe-9567bed1def6", new Version(1, 0, 0, 0)), new[] { source1 }, references: null);
var ref1 = comp.EmitToImageReference();
var sourceA =
@"public class A : nint
{
}";
comp = CreateEmptyCompilation(sourceA, references: new[] { ref1 }, parseOptions: TestOptions.RegularPreview);
var refA = comp.ToMetadataReference();
var typeA = comp.GetMember("A").BaseTypeNoUseSiteDiagnostics;
Assert.True(typeA.IsNativeIntegerType);
Assert.False(typeA.IsErrorType());
var sourceB =
@"class B : A
{
}";
comp = CreateEmptyCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(
// (1,7): error CS0518: Predefined type 'System.Void' is not defined or imported
// class B : A
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "B").WithArguments("System.Void").WithLocation(1, 7),
// (1,11): error CS0012: The type 'IntPtr' is defined in an assembly that is not referenced. You must add a reference to assembly 'c804cc09-8f73-44a1-9cfe-9567bed1def6, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
// class B : A
Diagnostic(ErrorCode.ERR_NoTypeDef, "A").WithArguments("System.IntPtr", "c804cc09-8f73-44a1-9cfe-9567bed1def6, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 11));
var typeB = comp.GetMember("A").BaseTypeNoUseSiteDiagnostics;
Assert.True(typeB.ContainingAssembly.IsMissing);
Assert.False(typeB.IsNativeIntegerType);
Assert.True(typeB.IsErrorType());
}
[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