提交 f74c37d6 编写于 作者: A AlekseyTs

Tuple and underlying type unification. Part 3.

- Added support for properties and events in tuple type symbol.
- Made additional adjustments to implementation of tuple symbol display around presence of element names.
上级 ffd32423
......@@ -349,7 +349,7 @@ private BoundExpression CreateTupleConversion(CSharpSyntaxNode syntax, BoundTupl
var destTupleType = (TupleTypeSymbol)targetType;
// do not lose the original element names in the literal if different from names in the target
// PROTOTYPE(tuples): Come back to this, what about locations?
// Come back to this, what about locations? (https://github.com/dotnet/roslyn/issues/11013)
targetType = destTupleType.WithElementNames(sourceTuple.ArgumentNamesOpt);
}
......
......@@ -221,6 +221,11 @@ private static bool IsNamedTypeAccessible(NamedTypeSymbol type, Symbol within, r
failedThroughTypeCheck = false;
if (containingType.IsTupleType)
{
containingType = containingType.TupleUnderlyingType;
}
// easy case - members of containing type are accessible.
if ((object)containingType == (object)within)
{
......
......@@ -511,10 +511,12 @@
<Compile Include="Symbols\AnonymousTypes\SynthesizedSymbols\AnonymousType.TemplateSymbol.cs" />
<Compile Include="Symbols\AnonymousTypes\SynthesizedSymbols\AnonymousType.ToStringMethodSymbol.cs" />
<Compile Include="Symbols\AnonymousTypes\SynthesizedSymbols\AnonymousType.TypeParameterSymbol.cs" />
<Compile Include="Symbols\Tuples\TupleEventSymbol.cs" />
<Compile Include="Symbols\Tuples\TupleFieldSymbol.cs" />
<Compile Include="Symbols\Tuples\TupleMethodSymbol.cs" />
<Compile Include="Symbols\Tuples\TupleParameterSymbol.cs" />
<Compile Include="Symbols\Tuples\TupleErrorFieldSymbol.cs" />
<Compile Include="Symbols\Tuples\TuplePropertySymbol.cs" />
<Compile Include="Symbols\Tuples\TupleTypeSymbol.cs" />
<Compile Include="Symbols\ArrayTypeSymbol.cs" />
<Compile Include="Symbols\AssemblySymbol.cs" />
......
......@@ -766,10 +766,12 @@ protected virtual Cci.IModuleReference TranslateModule(ModuleSymbol module, Diag
// Anonymous type being translated
if (namedTypeSymbol.IsAnonymousType)
{
Debug.Assert(!needDeclaration);
namedTypeSymbol = AnonymousTypeManager.TranslateAnonymousTypeSymbol(namedTypeSymbol);
}
else if (namedTypeSymbol.IsTupleType)
{
Debug.Assert(!needDeclaration);
namedTypeSymbol = namedTypeSymbol.TupleUnderlyingType;
}
......@@ -1088,13 +1090,18 @@ internal override Cci.IMethodReference Translate(MethodSymbol symbol, Diagnostic
// Method of anonymous type being translated
if (container.IsAnonymousType)
{
Debug.Assert(!needDeclaration);
methodSymbol = AnonymousTypeManager.TranslateAnonymousTypeMethodSymbol(methodSymbol);
}
else if (methodSymbol.IsTupleMethod)
{
Debug.Assert(!needDeclaration);
Debug.Assert(container.IsTupleType);
container = container.TupleUnderlyingType;
methodSymbol = methodSymbol.TupleUnderlyingMethod;
}
Debug.Assert(!container.IsTupleType);
Debug.Assert(methodSymbol.IsDefinitionOrDistinct());
if (!methodSymbol.IsDefinition)
......
......@@ -240,7 +240,9 @@ private void AddNameAndTypeArgumentsOrParameters(INamedTypeSymbol symbol)
}
else if (symbol.IsTupleType)
{
if (CanUseTupleTypeName(symbol))
// If top level tuple uses non-default names, there is no way to preserve them
// unless we use tuple syntax for the type. So, we give them priority.
if (HasNonDefaultTupleElementNames(symbol) || CanUseTupleTypeName(symbol))
{
AddTupleTypeName(symbol);
return;
......@@ -393,37 +395,43 @@ private void AddAnonymousTypeName(INamedTypeSymbol symbol)
/// Returns true if tuple type syntax can be used to refer to the tuple type without loss of information.
/// For example, it cannot be used when extension tuple is using non-default friendly names.
/// </summary>
/// <param name="symbol"></param>
/// <param name="tupleSymbol"></param>
/// <returns></returns>
private bool CanUseTupleTypeName(INamedTypeSymbol symbol)
private bool CanUseTupleTypeName(INamedTypeSymbol tupleSymbol)
{
INamedTypeSymbol currentUnderlying = symbol.TupleUnderlyingType;
INamedTypeSymbol currentUnderlying = tupleSymbol.TupleUnderlyingType;
if (currentUnderlying.Arity == TupleTypeSymbol.RestPosition)
while (currentUnderlying.Arity == TupleTypeSymbol.RestPosition)
{
do
tupleSymbol = (INamedTypeSymbol)currentUnderlying.TypeArguments[TupleTypeSymbol.RestPosition - 1];
Debug.Assert(tupleSymbol.IsTupleType);
if (HasNonDefaultTupleElementNames(tupleSymbol))
{
var currentTuple = (INamedTypeSymbol)currentUnderlying.TypeArguments[TupleTypeSymbol.RestPosition - 1];
Debug.Assert(currentTuple.IsTupleType);
return false;
}
currentUnderlying = tupleSymbol.TupleUnderlyingType;
}
var elementNames = currentTuple.TupleElementNames;
if (!elementNames.IsDefault)
return true;
}
private bool HasNonDefaultTupleElementNames(INamedTypeSymbol tupleSymbol)
{
var elementNames = tupleSymbol.TupleElementNames;
if (!elementNames.IsDefault)
{
for (int i = 0; i < elementNames.Length; i++)
{
if (elementNames[i] != TupleTypeSymbol.TupleMemberName(i + 1))
{
for (int i = 0; i < elementNames.Length; i++)
{
if (elementNames[i] != TupleTypeSymbol.TupleMemberName(i + 1))
{
return false;
}
}
return true;
}
currentUnderlying = currentTuple.TupleUnderlyingType;
}
while (currentUnderlying.Arity == TupleTypeSymbol.RestPosition);
}
return true;
return false;
}
private void AddTupleTypeName(INamedTypeSymbol symbol)
......
......@@ -139,10 +139,8 @@ internal TypeWithModifiers SubstituteTypeWithTupleUnification(TypeSymbol previou
TypeWithModifiers result = SubstituteType(previous);
// Make it a tuple if it became compatible with one.
if ((object)result.Type != null)
if ((object)result.Type != null && !previous.IsTupleCompatible())
{
Debug.Assert(!previous.IsTupleCompatible());
var possiblyTuple = TupleTypeSymbol.TransformToTupleIfCompatible(result.Type);
if ((object)result.Type != possiblyTuple)
{
......
......@@ -302,6 +302,29 @@ public sealed override bool HasUnsupportedMetadata
#endregion
/// <summary>
/// Is this an event of a tuple type?
/// </summary>
public virtual bool IsTupleEvent
{
get
{
return false;
}
}
/// <summary>
/// If this is an event of a tuple type, return corresponding underlying event from the
/// tuple underlying type. Otherwise, null.
/// </summary>
public virtual EventSymbol TupleUnderlyingEvent
{
get
{
return null;
}
}
#region IEventSymbol Members
ITypeSymbol IEventSymbol.Type
......@@ -379,7 +402,7 @@ public override TResult Accept<TResult>(SymbolVisitor<TResult> visitor)
#region Equality
public sealed override bool Equals(object obj)
public override bool Equals(object obj)
{
EventSymbol other = obj as EventSymbol;
......
......@@ -377,6 +377,29 @@ public sealed override bool HasUnsupportedMetadata
#endregion
/// <summary>
/// Is this a property of a tuple type?
/// </summary>
public virtual bool IsTupleProperty
{
get
{
return false;
}
}
/// <summary>
/// If this is a property of a tuple type, return corresponding underlying property from the
/// tuple underlying type. Otherwise, null.
/// </summary>
public virtual PropertySymbol TupleUnderlyingProperty
{
get
{
return null;
}
}
#region IPropertySymbol Members
bool IPropertySymbol.IsIndexer
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
/// <summary>
/// Represents an event of a tuple type (such as (int, byte).SomeEvent)
/// that is backed by an event within the tuple underlying type.
/// </summary>
internal sealed class TupleEventSymbol : WrapperEventSymbol
{
private readonly TupleTypeSymbol _containingType;
public TupleEventSymbol(TupleTypeSymbol container, EventSymbol underlyingEvent)
: base(underlyingEvent)
{
_containingType = container;
}
public override bool IsTupleEvent
{
get
{
return true;
}
}
public override EventSymbol TupleUnderlyingEvent
{
get
{
return _underlyingEvent;
}
}
public override Symbol ContainingSymbol
{
get
{
return _containingType;
}
}
public override TypeSymbol Type
{
get
{
return _underlyingEvent.Type;
}
}
public override MethodSymbol AddMethod
{
get
{
return _containingType.GetTupleMemberSymbolForUnderlyingMember(_underlyingEvent.AddMethod);
}
}
public override MethodSymbol RemoveMethod
{
get
{
return _containingType.GetTupleMemberSymbolForUnderlyingMember(_underlyingEvent.RemoveMethod);
}
}
internal override FieldSymbol AssociatedField
{
get
{
return _containingType.GetTupleMemberSymbolForUnderlyingMember(_underlyingEvent.AssociatedField);
}
}
internal override bool IsExplicitInterfaceImplementation
{
get
{
return _underlyingEvent.IsExplicitInterfaceImplementation;
}
}
public override ImmutableArray<EventSymbol> ExplicitInterfaceImplementations
{
get
{
return _underlyingEvent.ExplicitInterfaceImplementations;
}
}
internal override bool MustCallMethodsDirectly
{
get
{
return _underlyingEvent.MustCallMethodsDirectly;
}
}
internal override DiagnosticInfo GetUseSiteDiagnostic()
{
DiagnosticInfo result = base.GetUseSiteDiagnostic();
MergeUseSiteDiagnostics(ref result, _underlyingEvent.GetUseSiteDiagnostic());
return result;
}
public override int GetHashCode()
{
return _underlyingEvent.GetHashCode();
}
public override bool Equals(object obj)
{
return Equals(obj as TupleEventSymbol);
}
public bool Equals(TupleEventSymbol other)
{
if ((object)other == this)
{
return true;
}
return (object)other != null && _containingType == other._containingType && _underlyingEvent == other._underlyingEvent;
}
public override ImmutableArray<CSharpAttributeData> GetAttributes()
{
return _underlyingEvent.GetAttributes();
}
}
}
\ No newline at end of file
......@@ -61,13 +61,7 @@ public override Symbol AssociatedSymbol
{
get
{
Symbol underlyingAssociated = _underlyingField.AssociatedSymbol;
if ((object)underlyingAssociated == null)
{
return null;
}
return _containingTuple.GetTupleMemberSymbolForUnderlyingMember(underlyingAssociated);
return _containingTuple.GetTupleMemberSymbolForUnderlyingMember(_underlyingField.AssociatedSymbol);
}
}
......
......@@ -58,13 +58,7 @@ public override Symbol AssociatedSymbol
{
get
{
Symbol underlyingAssociated = _underlyingMethod.ConstructedFrom.AssociatedSymbol;
if ((object)underlyingAssociated == null)
{
return null;
}
return _containingType.GetTupleMemberSymbolForUnderlyingMember(underlyingAssociated);
return _containingType.GetTupleMemberSymbolForUnderlyingMember(_underlyingMethod.ConstructedFrom.AssociatedSymbol);
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Roslyn.Utilities;
using System.Collections.Immutable;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
/// <summary>
/// Represents a property of a tuple type (such as (int, byte).SomeProperty)
/// that is backed by a property within the tuple underlying type.
/// </summary>
internal sealed class TuplePropertySymbol : WrapperPropertySymbol
{
private readonly TupleTypeSymbol _containingType;
private ImmutableArray<ParameterSymbol> _lazyParameters;
public TuplePropertySymbol(TupleTypeSymbol container, PropertySymbol underlyingProperty)
: base(underlyingProperty)
{
_containingType = container;
}
public override bool IsTupleProperty
{
get
{
return true;
}
}
public override PropertySymbol TupleUnderlyingProperty
{
get
{
return _underlyingProperty;
}
}
public override TypeSymbol Type
{
get
{
return _underlyingProperty.Type;
}
}
public override ImmutableArray<CustomModifier> TypeCustomModifiers
{
get
{
return _underlyingProperty.TypeCustomModifiers;
}
}
public override ImmutableArray<ParameterSymbol> Parameters
{
get
{
if (_lazyParameters.IsDefault)
{
InterlockedOperations.Initialize(ref _lazyParameters, CreateParameters());
}
return _lazyParameters;
}
}
private ImmutableArray<ParameterSymbol> CreateParameters()
{
ImmutableArray<ParameterSymbol> underlying = _underlyingProperty.Parameters;
var builder = ArrayBuilder<ParameterSymbol>.GetInstance(underlying.Length);
foreach (var parameter in underlying)
{
builder.Add(new TupleParameterSymbol(this, parameter));
}
return builder.ToImmutableAndFree();
}
public override MethodSymbol GetMethod
{
get
{
return _containingType.GetTupleMemberSymbolForUnderlyingMember(_underlyingProperty.GetMethod);
}
}
public override MethodSymbol SetMethod
{
get
{
return _containingType.GetTupleMemberSymbolForUnderlyingMember(_underlyingProperty.SetMethod);
}
}
internal override bool IsExplicitInterfaceImplementation
{
get
{
return _underlyingProperty.IsExplicitInterfaceImplementation;
}
}
public override ImmutableArray<PropertySymbol> ExplicitInterfaceImplementations
{
get
{
return _underlyingProperty.ExplicitInterfaceImplementations;
}
}
public override Symbol ContainingSymbol
{
get
{
return _containingType;
}
}
internal override bool MustCallMethodsDirectly
{
get
{
return _underlyingProperty.MustCallMethodsDirectly;
}
}
internal override DiagnosticInfo GetUseSiteDiagnostic()
{
DiagnosticInfo result = base.GetUseSiteDiagnostic();
MergeUseSiteDiagnostics(ref result, _underlyingProperty.GetUseSiteDiagnostic());
return result;
}
public override int GetHashCode()
{
return _underlyingProperty.GetHashCode();
}
public override bool Equals(object obj)
{
return Equals(obj as TuplePropertySymbol);
}
public bool Equals(TuplePropertySymbol other)
{
if ((object)other == this)
{
return true;
}
return (object)other != null && _containingType == other._containingType && _underlyingProperty == other._underlyingProperty;
}
public override ImmutableArray<CSharpAttributeData> GetAttributes()
{
return _underlyingProperty.GetAttributes();
}
}
}
\ No newline at end of file
......@@ -568,6 +568,9 @@ internal static Symbol GetWellKnownMemberInType(NamedTypeSymbol type, WellKnownM
/// <summary>
/// The ValueTuple type for this tuple.
/// The type argument corresponding to the type of the extension field (VT[8].Rest),
/// which is at the 8th (one based) position is always a symbol for another tuple,
/// rather than its underlying type.
/// </summary>
public override NamedTypeSymbol TupleUnderlyingType
{
......@@ -766,8 +769,17 @@ private ImmutableArray<Symbol> CreateMembers()
break;
case SymbolKind.Property:
if (currentNestingLevel == 0)
{
members.Add(new TuplePropertySymbol(this, ((PropertySymbol)member).AsMember(currentUnderlying)));
}
break;
case SymbolKind.Event:
// PROTOTYPE(tuples): TODO
if (currentNestingLevel == 0)
{
members.Add(new TupleEventSymbol(this, ((EventSymbol)member).AsMember(currentUnderlying)));
}
break;
default:
......@@ -850,48 +862,53 @@ private static void CollectTargetTupleFields(NamedTypeSymbol underlying, ArrayBu
}
}
private SmallDictionary<Symbol, Symbol> UnderlyingDefinitionToMemberMap
internal SmallDictionary<Symbol, Symbol> UnderlyingDefinitionToMemberMap
{
get
{
if (_lazyUnderlyingDefinitionToMemberMap == null)
{
var map = new SmallDictionary<Symbol, Symbol>();
var map = new SmallDictionary<Symbol, Symbol>(ReferenceEqualityComparer.Instance);
var underlyingDefinition = _underlyingType.OriginalDefinition;
var members = GetMembers();
Symbol underlyingMemberDefinition;
foreach (var member in members)
// Go in reverse becaus we want members with default name, which precede the ones with
// friendly names, to be in the map.
for (int i = members.Length - 1; i >= 0; i--)
{
var member = members[i];
switch (member.Kind)
{
case SymbolKind.Method:
underlyingMemberDefinition = ((MethodSymbol)member).TupleUnderlyingMethod.OriginalDefinition;
map.Add(((MethodSymbol)member).TupleUnderlyingMethod.OriginalDefinition, member);
break;
case SymbolKind.Field:
underlyingMemberDefinition = ((FieldSymbol)member).TupleUnderlyingField?.OriginalDefinition;
map[((FieldSymbol)member).TupleUnderlyingField?.OriginalDefinition] = member;
break;
case SymbolKind.NamedType:
underlyingMemberDefinition = null;
case SymbolKind.Property:
map.Add(((PropertySymbol)member).TupleUnderlyingProperty.OriginalDefinition, member);
break;
case SymbolKind.Property:
case SymbolKind.Event:
// PROTOTYPE(tuples): TODO
underlyingMemberDefinition = null;
var underlyingEvent = ((EventSymbol)member).TupleUnderlyingEvent;
var underlyingAssociatedField = underlyingEvent.AssociatedField;
// The field is not part of the members list
if ((object)underlyingAssociatedField != null)
{
Debug.Assert((object)underlyingAssociatedField.ContainingSymbol == _underlyingType);
Debug.Assert(_underlyingType.GetMembers(underlyingAssociatedField.Name).IndexOf(underlyingAssociatedField) < 0);
map.Add(underlyingAssociatedField.OriginalDefinition, new TupleFieldSymbol(this, underlyingAssociatedField, -i - 1));
}
map.Add(underlyingEvent.OriginalDefinition, member);
break;
default:
throw ExceptionUtilities.UnexpectedValue(member.Kind);
}
if ((object)underlyingMemberDefinition != null && underlyingMemberDefinition.ContainingType == underlyingDefinition)
{
map.Add(underlyingMemberDefinition, member);
}
}
_lazyUnderlyingDefinitionToMemberMap = map;
......@@ -901,15 +918,20 @@ private static void CollectTargetTupleFields(NamedTypeSymbol underlying, ArrayBu
}
}
public Symbol GetTupleMemberSymbolForUnderlyingMember(Symbol underlyingMember)
public TMember GetTupleMemberSymbolForUnderlyingMember<TMember>(TMember underlyingMemberOpt) where TMember : Symbol
{
underlyingMember = underlyingMember.OriginalDefinition;
if (underlyingMember.ContainingType == _underlyingType.OriginalDefinition)
if ((object)underlyingMemberOpt == null)
{
return null;
}
Symbol underlyingMemberDefinition = underlyingMemberOpt.OriginalDefinition;
if (underlyingMemberDefinition.ContainingType == _underlyingType.OriginalDefinition)
{
Symbol result;
if (UnderlyingDefinitionToMemberMap.TryGetValue(underlyingMember, out result))
if (UnderlyingDefinitionToMemberMap.TryGetValue(underlyingMemberDefinition, out result))
{
return result;
return (TMember)result;
}
}
......
......@@ -597,6 +597,9 @@ public bool IsTupleOrCompatibleWithTupleOfCardinality(int targetCardinality)
/// <summary>
/// If this is a tuple type symbol, returns the symbol for its underlying type.
/// Otherwise, returns null.
/// The type argument corresponding to the type of the extension field (VT[8].Rest),
/// which is at the 8th (one based) position is always a symbol for another tuple,
/// rather than its underlying type.
/// </summary>
public virtual NamedTypeSymbol TupleUnderlyingType
{
......
......@@ -153,6 +153,9 @@ public interface INamedTypeSymbol : ITypeSymbol
/// <summary>
/// If this is a tuple type symbol, returns the symbol for its underlying type.
/// Otherwise, returns null.
/// The type argument corresponding to the type of the extension field (VT[8].Rest),
/// which is at the 8th (one based) position is always a symbol for another tuple,
/// rather than its underlying type.
/// </summary>
INamedTypeSymbol TupleUnderlyingType { get; }
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册