未验证 提交 ea74b218 编写于 作者: C Charles Stoner 提交者: GitHub

Support System.IntPtr and System.UIntPtr from source (#40994)

上级 973c2b99
......@@ -1465,11 +1465,11 @@ private static CSDiagnosticInfo CreateReflectionTypeNotFoundError(Type type)
HostObjectType.Name,
useCLSCompliantNameArityEncoding: true);
symbol = new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(
symbol = new MissingMetadataTypeSymbol.TopLevel(
new MissingAssemblySymbol(AssemblyIdentity.FromAssemblyDefinition(HostObjectType.GetTypeInfo().Assembly)).Modules[0],
ref mdName,
CreateReflectionTypeNotFoundError(HostObjectType),
SpecialType.None);
SpecialType.None,
CreateReflectionTypeNotFoundError(HostObjectType));
}
Interlocked.CompareExchange(ref _lazyHostObjectTypeSymbol, symbol, null);
......
......@@ -373,13 +373,13 @@ internal virtual NamedTypeSymbol TryLookupForwardedMetadataTypeWithCycleDetectio
internal ErrorTypeSymbol CreateCycleInTypeForwarderErrorTypeSymbol(ref MetadataTypeName emittedName)
{
DiagnosticInfo diagnosticInfo = new CSDiagnosticInfo(ErrorCode.ERR_CycleInTypeForwarder, emittedName.FullName, this.Name);
return new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(this.Modules[0], ref emittedName, diagnosticInfo);
return new MissingMetadataTypeSymbol.TopLevel(this.Modules[0], ref emittedName, diagnosticInfo);
}
internal ErrorTypeSymbol CreateMultipleForwardingErrorTypeSymbol(ref MetadataTypeName emittedName, ModuleSymbol forwardingModule, AssemblySymbol destination1, AssemblySymbol destination2)
{
var diagnosticInfo = new CSDiagnosticInfo(ErrorCode.ERR_TypeForwardedToMultipleAssemblies, forwardingModule, this, emittedName.FullName, destination1, destination2);
return new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(forwardingModule, ref emittedName, diagnosticInfo);
return new MissingMetadataTypeSymbol.TopLevel(forwardingModule, ref emittedName, diagnosticInfo);
}
/// <summary>
......
......@@ -166,7 +166,7 @@ internal NamedTypeSymbol GetWellKnownType(WellKnownType type)
errorInfo = new CSDiagnosticInfo(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, emittedName.FullName, conflicts.Item1, conflicts.Item2);
}
result = new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(this.Assembly.Modules[0], ref emittedName, errorInfo, type);
result = new MissingMetadataTypeSymbol.TopLevel(this.Assembly.Modules[0], ref emittedName, type, errorInfo);
}
else
{
......
......@@ -2320,19 +2320,6 @@ private sealed class PENamedTypeSymbolNonGeneric : PENamedTypeSymbol
protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData)
=> throw ExceptionUtilities.Unreachable;
// PROTOTYPE: Temporary approach for AsNativeInt().
private PENamedTypeSymbolNonGeneric(PENamedTypeSymbolNonGeneric other, bool isNativeInt) :
base(other)
{
Debug.Assert(isNativeInt != other.IsNativeInt);
_underlying = other;
IsNativeInt = isNativeInt;
Debug.Assert(this.Equals(other));
Debug.Assert(other.Equals(this));
}
public override int Arity
{
get
......@@ -2358,36 +2345,20 @@ internal override int MetadataArity
}
}
private readonly PENamedTypeSymbolNonGeneric _underlying;
internal override bool IsNativeInt { get; }
internal override NamedTypeSymbol AsNativeInt(bool asNativeInt)
{
Debug.Assert(this.SpecialType == SpecialType.System_IntPtr || this.SpecialType == SpecialType.System_UIntPtr);
if (IsNativeInt == asNativeInt)
{
return this;
}
return asNativeInt ? new PENamedTypeSymbolNonGeneric(this, isNativeInt: true) : _underlying;
return asNativeInt ?
(NamedTypeSymbol)new NativeIntegerTypeSymbol(this) : // PROTOTYPE: Consider caching instance, perhaps on containing assembly.
this;
}
// PROTOTYPE: Temporary approach for AsNativeInt().
internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary<TypeParameterSymbol, bool> isValueTypeOverrideOpt = null)
{
if ((object)t2 == null) return false;
if ((object)t2 == this) return true;
var other = t2 as PENamedTypeSymbolNonGeneric;
if ((object)other != null &&
(this.IsNativeInt || other.IsNativeInt) &&
this.SpecialType == other.SpecialType)
{
return true;
}
return base.Equals(t2, comparison, isValueTypeOverrideOpt);
return t2 is NativeIntegerTypeSymbol nativeInteger ?
nativeInteger.Equals(this, comparison, isValueTypeOverrideOpt) :
base.Equals(t2, comparison, isValueTypeOverrideOpt);
}
}
......
......@@ -4,14 +4,11 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using System;
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
......@@ -126,60 +123,75 @@ internal override DiagnosticInfo ErrorInfo
/// <summary>
/// Represents not nested missing type.
/// </summary>
internal class TopLevel : MissingMetadataTypeSymbol
internal sealed class TopLevel : MissingMetadataTypeSymbol
{
private readonly string _namespaceName;
private readonly ModuleSymbol _containingModule;
private readonly bool _isNativeInt;
private DiagnosticInfo? _lazyErrorInfo;
private NamespaceSymbol? _lazyContainingNamespace;
/// <summary>
/// Either <see cref="SpecialType"/>, <see cref="WellKnownType"/>, or -1 if not initialized.
/// </summary>
private int _lazyTypeId = -1;
private int _lazyTypeId;
public TopLevel(ModuleSymbol module, string @namespace, string name, int arity, bool mangleName, TupleExtraData? tupleData = null)
: base(name, arity, mangleName, tupleData)
public TopLevel(ModuleSymbol module, string @namespace, string name, int arity, bool mangleName)
: this(module, @namespace, name, arity, mangleName, errorInfo: null, isNativeInt: false, containingNamespace: null, typeId: -1, tupleData: null)
{
RoslynDebug.Assert((object)module != null);
RoslynDebug.Assert(@namespace != null);
_namespaceName = @namespace;
_containingModule = module;
}
public TopLevel(ModuleSymbol module, ref MetadataTypeName fullName)
: this(module, ref fullName, -1)
public TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, DiagnosticInfo? errorInfo = null)
: this(module, ref fullName, -1, errorInfo)
{
}
public TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, SpecialType specialType)
: this(module, ref fullName, (int)specialType)
public TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, SpecialType specialType, DiagnosticInfo? errorInfo = null)
: this(module, ref fullName, (int)specialType, errorInfo)
{
}
public TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, WellKnownType wellKnownType)
: this(module, ref fullName, (int)wellKnownType)
public TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, WellKnownType wellKnownType, DiagnosticInfo? errorInfo = null)
: this(module, ref fullName, (int)wellKnownType, errorInfo)
{
}
private TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, int typeId)
: this(module, ref fullName, fullName.ForcedArity == -1 || fullName.ForcedArity == fullName.InferredArity)
private TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, int typeId, DiagnosticInfo? errorInfo)
: this(module, ref fullName, fullName.ForcedArity == -1 || fullName.ForcedArity == fullName.InferredArity, errorInfo, typeId)
{
Debug.Assert(typeId == -1 || typeId == (int)SpecialType.None || Arity == 0 || MangleName);
_lazyTypeId = typeId;
}
private TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, bool mangleName)
private TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, bool mangleName, DiagnosticInfo? errorInfo, int typeId)
: this(module, fullName.NamespaceName,
mangleName ? fullName.UnmangledTypeName : fullName.TypeName,
mangleName ? fullName.InferredArity : fullName.ForcedArity,
mangleName)
mangleName,
isNativeInt: false,
errorInfo,
containingNamespace: null,
typeId,
tupleData: null)
{
}
private TopLevel(ModuleSymbol module, string @namespace, string name, int arity, bool mangleName, bool isNativeInt, DiagnosticInfo? errorInfo, NamespaceSymbol? containingNamespace, int typeId, TupleExtraData? tupleData)
: base(name, arity, mangleName, tupleData)
{
RoslynDebug.Assert((object)module != null);
RoslynDebug.Assert(@namespace != null);
RoslynDebug.Assert(typeId == -1 || typeId == (int)SpecialType.None || arity == 0 || mangleName);
_namespaceName = @namespace;
_containingModule = module;
_isNativeInt = isNativeInt;
_lazyErrorInfo = errorInfo;
_lazyContainingNamespace = containingNamespace;
_lazyTypeId = typeId;
}
protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData)
{
return new TopLevel(_containingModule, _namespaceName, Name, Arity, MangleName, newData);
return new TopLevel(_containingModule, _namespaceName, name, arity, mangleName, _isNativeInt, _lazyErrorInfo, _lazyContainingNamespace, _lazyTypeId, newData);
}
/// <summary>
......@@ -292,12 +304,14 @@ internal override DiagnosticInfo ErrorInfo
{
get
{
if (this.TypeId != (int)SpecialType.None)
if (_lazyErrorInfo == null)
{
return new CSDiagnosticInfo(ErrorCode.ERR_PredefinedTypeNotFound, MetadataHelpers.BuildQualifiedName(_namespaceName, MetadataName));
var errorInfo = this.TypeId != (int)SpecialType.None ?
new CSDiagnosticInfo(ErrorCode.ERR_PredefinedTypeNotFound, MetadataHelpers.BuildQualifiedName(_namespaceName, MetadataName)) :
base.ErrorInfo;
Interlocked.CompareExchange(ref _lazyErrorInfo, errorInfo, null);
}
return base.ErrorInfo;
return _lazyErrorInfo;
}
}
......@@ -312,6 +326,22 @@ public override int GetHashCode()
return Hash.Combine(MetadataName, Hash.Combine(_containingModule, Hash.Combine(_namespaceName, arity)));
}
internal override NamedTypeSymbol AsNativeInt(bool asNativeInt)
{
Debug.Assert(this.SpecialType == SpecialType.System_IntPtr || this.SpecialType == SpecialType.System_UIntPtr);
var other = asNativeInt == _isNativeInt ?
this :
new TopLevel(_containingModule, _namespaceName, name, arity, mangleName, isNativeInt: asNativeInt, _lazyErrorInfo, _lazyContainingNamespace, _lazyTypeId, TupleData);
Debug.Assert(other.Equals(this));
Debug.Assert(other.SpecialType == this.SpecialType);
return other;
}
internal override bool IsNativeInt => _isNativeInt;
internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary<TypeParameterSymbol, bool>? isValueTypeOverrideOpt = null)
{
if (ReferenceEquals(this, t2))
......@@ -338,44 +368,10 @@ internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOn
}
}
internal class TopLevelWithCustomErrorInfo : TopLevel
{
private readonly DiagnosticInfo _errorInfo;
public TopLevelWithCustomErrorInfo(ModuleSymbol module, ref MetadataTypeName emittedName, DiagnosticInfo errorInfo)
: base(module, ref emittedName)
{
RoslynDebug.Assert(errorInfo != null);
_errorInfo = errorInfo;
}
public TopLevelWithCustomErrorInfo(ModuleSymbol module, ref MetadataTypeName emittedName, DiagnosticInfo errorInfo, SpecialType typeId)
: base(module, ref emittedName, typeId)
{
RoslynDebug.Assert(errorInfo != null);
_errorInfo = errorInfo;
}
public TopLevelWithCustomErrorInfo(ModuleSymbol module, ref MetadataTypeName emittedName, DiagnosticInfo errorInfo, WellKnownType typeId)
: base(module, ref emittedName, typeId)
{
RoslynDebug.Assert(errorInfo != null);
_errorInfo = errorInfo;
}
internal override DiagnosticInfo ErrorInfo
{
get
{
return _errorInfo;
}
}
}
/// <summary>
/// Represents nested missing type.
/// </summary>
internal class Nested : MissingMetadataTypeSymbol
internal sealed class Nested : MissingMetadataTypeSymbol
{
private readonly NamedTypeSymbol _containingType;
......
......@@ -1510,9 +1510,18 @@ internal bool IsTupleTypeOfCardinality(out int tupleCardinality)
}
// PROTOTYPE: Should be abstract.
internal virtual NamedTypeSymbol AsNativeInt(bool asNativeInt) => this;
/// <summary>
/// Returns an instance of a symbol that has <see cref="IsNativeInt"/> set to <paramref name="asNativeInt"/>
/// if the underlying symbol represents System.IntPtr or System.UIntPtr.
/// For other symbols, throws <see cref="System.InvalidOperationException"/>.
/// </summary>
internal virtual NamedTypeSymbol AsNativeInt(bool asNativeInt) => throw ExceptionUtilities.Unreachable;
// PROTOTYPE: Should be abstract.
/// <summary>
/// Returns true if the symbol represents a native integer
/// (corresponding to the language tokens nint or nuint).
/// </summary>
internal virtual bool IsNativeInt => false;
protected override ISymbol CreateISymbol()
......
// 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.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal sealed class NativeIntegerTypeSymbol : WrappedNamedTypeSymbol
{
internal NativeIntegerTypeSymbol(NamedTypeSymbol underlying) : base(underlying, tupleData: null)
{
Debug.Assert(underlying.TupleData is null);
Debug.Assert(!underlying.IsNativeInt);
Debug.Assert(underlying.SpecialType == SpecialType.System_IntPtr || underlying.SpecialType == SpecialType.System_UIntPtr);
Debug.Assert(this.Equals(underlying));
Debug.Assert(underlying.Equals(this));
}
public override ImmutableArray<TypeParameterSymbol> TypeParameters => ImmutableArray<TypeParameterSymbol>.Empty;
public override NamedTypeSymbol ConstructedFrom => this;
public override Symbol ContainingSymbol => _underlyingType.ContainingSymbol;
internal override ImmutableArray<TypeWithAnnotations> TypeArgumentsWithAnnotationsNoUseSiteDiagnostics => ImmutableArray<TypeWithAnnotations>.Empty;
internal override bool IsComImport => _underlyingType.IsComImport;
internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics => _underlyingType.BaseTypeNoUseSiteDiagnostics;
public override SpecialType SpecialType => _underlyingType.SpecialType;
public override IEnumerable<string> MemberNames => Array.Empty<string>();
/// <summary>
/// There are no members on <see cref="System.IntPtr"/> that should be exposed directly on nint:
/// constructors for nint other than the default parameterless constructor are not supported;
/// operators are handled explicitly as built-in operators and conversions;
/// 0 should be used instead of Zero;
/// sizeof(nint) should be used instead of Size;
/// + and - should be used instead of Add() and Subtract();
/// ToInt32(), ToInt64(), ToPointer() should be used from System.IntPtr only;
/// overridden methods Equals(), GetHashCode(), and ToString() are referenced from System.Object.
/// The one remaining member is <see cref="System.IntPtr.ToString(string)"/> which we could expose if needed.
/// </summary>
public override ImmutableArray<Symbol> GetMembers() => ImmutableArray<Symbol>.Empty;
public override ImmutableArray<Symbol> GetMembers(string name) => ImmutableArray<Symbol>.Empty;
public override ImmutableArray<NamedTypeSymbol> GetTypeMembers() => ImmutableArray<NamedTypeSymbol>.Empty;
public override ImmutableArray<NamedTypeSymbol> GetTypeMembers(string name) => ImmutableArray<NamedTypeSymbol>.Empty;
public override ImmutableArray<NamedTypeSymbol> GetTypeMembers(string name, int arity) => ImmutableArray<NamedTypeSymbol>.Empty;
internal override NamedTypeSymbol GetDeclaredBaseType(ConsList<TypeSymbol> basesBeingResolved) => _underlyingType.GetDeclaredBaseType(basesBeingResolved);
internal override ImmutableArray<NamedTypeSymbol> GetDeclaredInterfaces(ConsList<TypeSymbol> basesBeingResolved) => _underlyingType.GetDeclaredInterfaces(basesBeingResolved);
internal override ImmutableArray<Symbol> GetEarlyAttributeDecodingMembers() => throw ExceptionUtilities.Unreachable;
internal override ImmutableArray<Symbol> GetEarlyAttributeDecodingMembers(string name) => throw ExceptionUtilities.Unreachable;
internal override IEnumerable<FieldSymbol> GetFieldsToEmit() => throw ExceptionUtilities.Unreachable;
internal override ImmutableArray<NamedTypeSymbol> GetInterfacesToEmit() => throw ExceptionUtilities.Unreachable;
// PROTOTYPE: Include certain interfaces defined on the underlying type, with substitution
// of [U]IntPtr (for instance, IEquatable<nint> rather than IEquatable<IntPtr>).
internal override ImmutableArray<NamedTypeSymbol> InterfacesNoUseSiteDiagnostics(ConsList<TypeSymbol> basesBeingResolved = null) => ImmutableArray<NamedTypeSymbol>.Empty;
protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) => throw ExceptionUtilities.Unreachable;
public override bool AreLocalsZeroed => throw ExceptionUtilities.Unreachable;
internal override bool IsNativeInt => true;
internal override NamedTypeSymbol AsNativeInt(bool asNativeInt) => asNativeInt ? this : _underlyingType;
internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary<TypeParameterSymbol, bool> isValueTypeOverrideOpt = null) => _underlyingType.Equals(t2, comparison, isValueTypeOverrideOpt);
public override int GetHashCode() => _underlyingType.GetHashCode();
}
}
......@@ -10,7 +10,6 @@
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
......@@ -1367,5 +1366,21 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r
}
#endregion
internal override NamedTypeSymbol AsNativeInt(bool asNativeInt)
{
Debug.Assert(this.SpecialType == SpecialType.System_IntPtr || this.SpecialType == SpecialType.System_UIntPtr);
return asNativeInt ?
(NamedTypeSymbol)new NativeIntegerTypeSymbol(this) : // PROTOTYPE: Consider caching instance, perhaps on containing assembly.
this;
}
internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison, IReadOnlyDictionary<TypeParameterSymbol, bool> isValueTypeOverrideOpt = null)
{
return t2 is NativeIntegerTypeSymbol nativeInteger ?
nativeInteger.Equals(this, comparison, isValueTypeOverrideOpt) :
base.Equals(t2, comparison, isValueTypeOverrideOpt);
}
}
}
......@@ -265,6 +265,22 @@ static void F(A<nint, nuint> a)
comp = CreateCompilation(source1, new[] { ref0 }, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics();
var type = comp.GetTypeByMetadataName("B");
Assert.Equal("void B.F1(A<nint, nuint> a)", type.GetMember("F1").ToDisplayString(FormatWithSpecialTypes));
Assert.Equal("void B.F2(A<System.IntPtr, System.UIntPtr> a)", type.GetMember("F2").ToDisplayString(FormatWithSpecialTypes));
Assert.Equal("void B.F3(A<System.IntPtr, System.UIntPtr> a)", type.GetMember("F3").ToDisplayString(FormatWithSpecialTypes));
var expected =
@"B
void F1(A<System.IntPtr, System.UIntPtr> a)
[NativeInteger({ False, True, True })] A<System.IntPtr, System.UIntPtr> a
void F2(A<System.IntPtr, System.UIntPtr> a)
[NativeInteger({ False, True })] A<System.IntPtr, System.UIntPtr> a
void F3(A<System.IntPtr, System.UIntPtr> a)
[NativeInteger({ False, False, True, True })] A<System.IntPtr, System.UIntPtr> a
";
AssertNativeIntegerAttributes(type.ContainingModule, expected);
}
[Fact]
......@@ -897,7 +913,7 @@ private static CustomAttribute GetAttributeByConstructorName(MetadataReader read
private static void AssertAttributes(MetadataReader reader, CustomAttributeHandleCollection handles, params string[] expectedNames)
{
var actualNames = handles.Select(h => GetAttributeConstructorName(reader, h)).ToArray();
AssertEx.SetEqual(actualNames, expectedNames);
AssertEx.Equal(actualNames, expectedNames);
}
private static void AssertNoNativeIntegerAttribute(ImmutableArray<CSharpAttributeData> attributes)
......@@ -913,7 +929,7 @@ private static void AssertNativeIntegerAttribute(ImmutableArray<CSharpAttributeD
private static void AssertAttributes(ImmutableArray<CSharpAttributeData> attributes, params string[] expectedNames)
{
var actualNames = attributes.Select(a => a.AttributeClass.ToTestDisplayString()).ToArray();
AssertEx.SetEqual(actualNames, expectedNames);
AssertEx.Equal(actualNames, expectedNames);
}
private static void AssertNoNativeIntegerAttributes(CSharpCompilation comp)
......
......@@ -15,6 +15,8 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
{
public class NativeIntTests : CSharpTestBase
{
private static readonly SymbolDisplayFormat FormatWithSpecialTypes = SymbolDisplayFormat.TestFormat.WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes);
[Fact]
public void LanguageVersion()
{
......@@ -40,12 +42,252 @@ public void LanguageVersion()
comp.VerifyDiagnostics();
}
/// <summary>
/// System.IntPtr and System.UIntPtr definitions from metadata.
/// </summary>
[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<MethodSymbol>("I.F1");
Assert.Equal("void I.F1(System.IntPtr x, nint y)", method.ToDisplayString(FormatWithSpecialTypes));
VerifyTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: true);
method = comp.GetMember<MethodSymbol>("I.F2");
Assert.Equal("void I.F2(System.UIntPtr x, nuint y)", method.ToDisplayString(FormatWithSpecialTypes));
VerifyTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: false);
}
/// <summary>
/// System.IntPtr and System.UIntPtr definitions from source.
/// </summary>
[Fact]
public void TypeDefinitions_FromSource()
{
var sourceA =
@"namespace System
{
public class Object { }
public abstract class ValueType { }
public struct Void { }
public struct IntPtr { }
public struct UIntPtr { }
}";
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<MethodSymbol>("I.F1");
Assert.Equal("void I.F1(System.IntPtr x, nint y)", method.ToDisplayString(FormatWithSpecialTypes));
VerifyTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: true);
method = comp.GetMember<MethodSymbol>("I.F2");
Assert.Equal("void I.F2(System.UIntPtr x, nuint y)", method.ToDisplayString(FormatWithSpecialTypes));
VerifyTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: false);
}
}
private static void VerifyType(NamedTypeSymbol type, bool signed, bool isNativeInt)
{
var specialType = signed ? SpecialType.System_IntPtr : SpecialType.System_UIntPtr;
Assert.Equal(specialType, type.SpecialType);
Assert.Equal(SymbolKind.NamedType, type.Kind);
Assert.Equal(TypeKind.Struct, type.TypeKind);
Assert.Same(type, type.ConstructedFrom);
Assert.Equal(isNativeInt, type.IsNativeInt);
}
private static void VerifyType(INamedTypeSymbol type, bool signed, bool isNativeInt)
{
var specialType = signed ? SpecialType.System_IntPtr : SpecialType.System_UIntPtr;
Assert.Equal(specialType, type.SpecialType);
Assert.Equal(SymbolKind.NamedType, type.Kind);
Assert.Equal(TypeKind.Struct, type.TypeKind);
Assert.Same(type, type.ConstructedFrom);
}
private static void VerifyTypes(INamedTypeSymbol underlyingType, INamedTypeSymbol nativeIntegerType, bool signed)
{
VerifyType(underlyingType, signed, isNativeInt: false);
VerifyType(nativeIntegerType, signed, isNativeInt: false);
Assert.Empty(nativeIntegerType.MemberNames);
Assert.Empty(nativeIntegerType.GetTypeMembers());
Assert.Empty(nativeIntegerType.GetMembers());
// PROTOTYPE: Include certain interfaces defined on the underlying underlyingType.
Assert.Empty(nativeIntegerType.Interfaces);
Assert.NotSame(underlyingType, nativeIntegerType);
Assert.Equal(underlyingType, nativeIntegerType);
Assert.Equal(nativeIntegerType, underlyingType);
Assert.Equal(underlyingType.GetHashCode(), nativeIntegerType.GetHashCode());
}
private static void VerifyTypes(NamedTypeSymbol underlyingType, NamedTypeSymbol nativeIntegerType, bool signed)
{
VerifyType(underlyingType, signed, isNativeInt: false);
VerifyType(nativeIntegerType, signed, isNativeInt: true);
Assert.Empty(nativeIntegerType.MemberNames);
Assert.Empty(nativeIntegerType.GetTypeMembers());
Assert.Empty(nativeIntegerType.GetMembers());
// PROTOTYPE: Include certain interfaces defined on the underlying underlyingType.
Assert.Empty(nativeIntegerType.InterfacesNoUseSiteDiagnostics());
Assert.Same(underlyingType, underlyingType.AsNativeInt(false));
Assert.Same(nativeIntegerType, nativeIntegerType.AsNativeInt(true));
Assert.Equal(nativeIntegerType, underlyingType.AsNativeInt(true));
Assert.Equal(underlyingType, nativeIntegerType.AsNativeInt(false));
VerifyEqualButDistinct(underlyingType, underlyingType.AsNativeInt(true));
VerifyEqualButDistinct(nativeIntegerType, nativeIntegerType.AsNativeInt(false));
VerifyEqualButDistinct(underlyingType, nativeIntegerType);
VerifyTypes(underlyingType.GetPublicSymbol(), nativeIntegerType.GetPublicSymbol(), signed);
}
private 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());
}
[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<MethodSymbol>("I.F1");
Assert.Equal("void I.F1(System.IntPtr x, nint y)", method.ToDisplayString(FormatWithSpecialTypes));
verifyTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: true);
method = comp.GetMember<MethodSymbol>("I.F2");
Assert.Equal("void I.F2(System.UIntPtr x, nuint y)", method.ToDisplayString(FormatWithSpecialTypes));
verifyTypes((NamedTypeSymbol)method.Parameters[0].Type, (NamedTypeSymbol)method.Parameters[1].Type, signed: false);
}
static void verifyTypes(NamedTypeSymbol underlyingType, NamedTypeSymbol nativeIntegerType, bool signed)
{
Assert.Equal(SpecialType.None, underlyingType.SpecialType);
Assert.Equal(SymbolKind.ErrorType, underlyingType.Kind);
Assert.Equal(TypeKind.Error, underlyingType.TypeKind);
Assert.False(underlyingType.IsNativeInt);
var specialType = signed ? SpecialType.System_IntPtr : SpecialType.System_UIntPtr;
Assert.Equal(specialType, nativeIntegerType.SpecialType);
Assert.Equal(SymbolKind.ErrorType, nativeIntegerType.Kind);
Assert.Equal(TypeKind.Error, nativeIntegerType.TypeKind);
Assert.True(nativeIntegerType.IsNativeInt);
Assert.Same(nativeIntegerType, nativeIntegerType.AsNativeInt(true));
VerifyEqualButDistinct(nativeIntegerType, nativeIntegerType.AsNativeInt(false));
}
}
// 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<System.IntPtr> and I<nint>
[Fact]
public void ClassName()
......@@ -75,17 +317,17 @@ static void verify(CSharpCompilation comp)
var tree = comp.SyntaxTrees[0];
var nodes = tree.GetRoot().DescendantNodes().ToArray();
var model = comp.GetSemanticModel(tree);
var type = model.GetDeclaredSymbol(nodes.OfType<ClassDeclarationSyntax>().Single());
Assert.Equal("nint", type.ToTestDisplayString());
Assert.Equal(SpecialType.None, type.SpecialType);
var underlyingType = model.GetDeclaredSymbol(nodes.OfType<ClassDeclarationSyntax>().Single());
Assert.Equal("nint", underlyingType.ToTestDisplayString());
Assert.Equal(SpecialType.None, underlyingType.SpecialType);
var method = model.GetDeclaredSymbol(nodes.OfType<MethodDeclarationSyntax>().Single());
Assert.Equal("nint I.Add(nint x, System.UIntPtr y)", method.ToTestDisplayString());
var type0 = method.Parameters[0].Type;
var type1 = method.Parameters[1].Type;
Assert.Equal(SpecialType.None, type0.SpecialType);
Assert.False(IsNativeInt(type0));
Assert.Equal(SpecialType.System_UIntPtr, type1.SpecialType);
Assert.True(IsNativeInt(type1));
var underlyingType0 = method.Parameters[0].Type.GetSymbol<NamedTypeSymbol>();
var underlyingType1 = method.Parameters[1].Type.GetSymbol<NamedTypeSymbol>();
Assert.Equal(SpecialType.None, underlyingType0.SpecialType);
Assert.False(underlyingType0.IsNativeInt);
Assert.Equal(SpecialType.System_UIntPtr, underlyingType1.SpecialType);
Assert.True(underlyingType1.IsNativeInt);
}
}
......@@ -112,25 +354,17 @@ interface I
static void verify(CSharpCompilation comp)
{
var tree = comp.SyntaxTrees[0];
var nodes = tree.GetRoot().DescendantNodes().ToArray();
var model = comp.GetSemanticModel(tree);
var method = model.GetDeclaredSymbol(nodes.OfType<MethodDeclarationSyntax>().Single());
var method = comp.GetMember<MethodSymbol>("I.Add");
Assert.Equal("System.Int16 I.Add(System.Int16 x, System.UIntPtr y)", method.ToTestDisplayString());
var type0 = method.Parameters[0].Type;
var type1 = method.Parameters[1].Type;
Assert.Equal(SpecialType.System_Int16, type0.SpecialType);
Assert.False(IsNativeInt(type0));
Assert.Equal(SpecialType.System_UIntPtr, type1.SpecialType);
Assert.True(IsNativeInt(type1));
var underlyingType0 = (NamedTypeSymbol)method.Parameters[0].Type;
var underlyingType1 = (NamedTypeSymbol)method.Parameters[1].Type;
Assert.Equal(SpecialType.System_Int16, underlyingType0.SpecialType);
Assert.False(underlyingType0.IsNativeInt);
Assert.Equal(SpecialType.System_UIntPtr, underlyingType1.SpecialType);
Assert.True(underlyingType1.IsNativeInt);
}
}
private static bool IsNativeInt(ITypeSymbol type)
{
return type.GetSymbol<NamedTypeSymbol>()?.IsNativeInt == true;
}
// PROTOTYPE: nint and nuint should be allowed.
[Fact]
public void MemberName()
......@@ -364,15 +598,15 @@ static void verifyOperators(CSharpCompilation comp)
_ = operators.Single(op => isNullableNativeInt(op.LeftType, signed: false));
}
static bool isNativeInt(TypeSymbol type, bool signed)
static bool isNativeInt(TypeSymbol underlyingType, bool signed)
{
return type is NamedTypeSymbol { IsNativeInt: true } &&
type.SpecialType == (signed ? SpecialType.System_IntPtr : SpecialType.System_UIntPtr);
return underlyingType is NamedTypeSymbol { IsNativeInt: true } &&
underlyingType.SpecialType == (signed ? SpecialType.System_IntPtr : SpecialType.System_UIntPtr);
}
static bool isNullableNativeInt(TypeSymbol type, bool signed)
static bool isNullableNativeInt(TypeSymbol underlyingType, bool signed)
{
return type.IsNullableType() && isNativeInt(type.GetNullableUnderlyingType(), signed);
return underlyingType.IsNullableType() && isNativeInt(underlyingType.GetNullableUnderlyingType(), signed);
}
}
}
......@@ -464,7 +698,7 @@ void conversions(string sourceType, string destType, string expectedImplicitIL,
useChecked: true,
expectedCheckedIL is null ? ErrorCode.ERR_NoExplicitConv : 0);
static bool usesIntPtrOrUIntPtr(string type) => type.Contains("IntPtr");
static bool usesIntPtrOrUIntPtr(string underlyingType) => underlyingType.Contains("IntPtr");
}
conversions(sourceType: "object", destType: "nint", expectedImplicitIL: null,
......@@ -1420,12 +1654,12 @@ .maxstack 1
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var expr = tree.GetRoot().DescendantNodes().OfType<ReturnStatementSyntax>().Single().Expression;
var typeInfo = model.GetTypeInfo(expr);
var underlyingTypeInfo = model.GetTypeInfo(expr);
if (!skipTypeChecks)
{
Assert.Equal(sourceType, typeInfo.Type.ToString());
Assert.Equal(destType, typeInfo.ConvertedType.ToString());
Assert.Equal(sourceType, underlyingTypeInfo.Type.ToString());
Assert.Equal(destType, underlyingTypeInfo.ConvertedType.ToString());
}
if (expectedIL != null)
......@@ -1434,7 +1668,7 @@ .maxstack 1
verifier.VerifyIL("Program.Convert", expectedIL);
}
static bool useUnsafe(string type) => type == "void*";
static bool useUnsafe(string underlyingType) => underlyingType == "void*";
}
// PROTOTYPE:Test pre- and postfix increment and decrement. See UnopEasyOut.s_increment.
......@@ -2654,7 +2888,7 @@ private void BinaryOperator(string op, string leftType, string rightType, string
CompileAndVerify(comp);
}
static bool useUnsafe(string type) => type == "void*";
static bool useUnsafe(string underlyingType) => underlyingType == "void*";
}
[Fact]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册