/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Portable/Symbols/Tuples/TupleFieldSymbol.cs
348 строк
13 KB
Jan Jones
Unsafe evolution: extend compat mode to legacy callers (#83660)
26 июн 2026, 17:00
Не верифицирован
26 июн 2026, 17:00
8a40f56
Код
Авторство
О чём код?
// 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 Roslyn.Utilities; using System; using System.Collections.Immutable; using System.Diagnostics; using System.Threading; namespace Microsoft.CodeAnalysis.CSharp.Symbols { /// <summary> /// A plain TupleElementFieldSymbol (as opposed to a TupleVirtualElementFieldSymbol) represents /// an element field of a tuple type (such as (int, byte).Item1) that is backed by a real field /// with the same name within the tuple underlying type. /// /// Note that original tuple fields (like 'System.ValueTuple`2.Item1') do not get wrapped. /// </summary> internal class TupleElementFieldSymbol : WrappedFieldSymbol { /// <summary> /// If this field represents a tuple element with index X /// 2X if this field represents Default-named element /// 2X + 1 if this field represents Friendly-named element /// </summary> private readonly int _tupleElementIndex; protected readonly NamedTypeSymbol _containingTuple; private readonly ImmutableArray<Location> _locations; protected readonly FieldSymbol _correspondingDefaultField; // default tuple elements like Item1 or Item20 could be provided by the user or // otherwise implicitly declared by compiler private readonly bool _isImplicitlyDeclared; public TupleElementFieldSymbol( NamedTypeSymbol container, FieldSymbol underlyingField, int tupleElementIndex, ImmutableArray<Location> locations, bool isImplicitlyDeclared, FieldSymbol? correspondingDefaultFieldOpt = null) : base(underlyingField) { Debug.Assert(tupleElementIndex >= 0); Debug.Assert(container.Equals(underlyingField.ContainingType, TypeCompareKind.IgnoreDynamicAndTupleNames) || this is TupleVirtualElementFieldSymbol, "virtual fields should be represented by " + nameof(TupleVirtualElementFieldSymbol)); Debug.Assert(!(underlyingField is TupleElementFieldSymbol)); // The fields on definition of ValueTuple<...> types don't need to be wrapped Debug.Assert(!container.IsDefinition); Debug.Assert(container.IsTupleType); _containingTuple = container; _tupleElementIndex = correspondingDefaultFieldOpt is null ? tupleElementIndex << 1 : (tupleElementIndex << 1) + 1; Debug.Assert(!locations.IsDefault); _locations = locations; _isImplicitlyDeclared = isImplicitlyDeclared; _correspondingDefaultField = correspondingDefaultFieldOpt ?? this; } /// <summary> /// If this is a field representing a tuple element, /// returns the index of the element (zero-based). /// Otherwise returns -1 /// </summary> public sealed override int TupleElementIndex => _tupleElementIndex >> 1; public sealed override bool IsDefaultTupleElement { get { // even return (_tupleElementIndex & 1) == 0; } } public sealed override bool IsExplicitlyNamedTupleElement { get { return !_isImplicitlyDeclared; } } public sealed override FieldSymbol TupleUnderlyingField { get { return _underlyingField; } } public sealed override Symbol? AssociatedSymbol { get { return null; } } public override FieldSymbol OriginalDefinition { get { NamedTypeSymbol originalContainer = ContainingType.OriginalDefinition; if (!originalContainer.IsTupleType) { return this; } return originalContainer.GetTupleMemberSymbolForUnderlyingMember(_underlyingField.OriginalDefinition)!; } } public sealed override Symbol ContainingSymbol { get { return _containingTuple; } } public sealed override RefKind RefKind => _underlyingField.RefKind; internal sealed override CallerUnsafeMode GetCallerUnsafeMode(ConsList<FieldSymbol> fieldsBeingBound) => _underlyingField.GetCallerUnsafeMode(fieldsBeingBound); public sealed override ImmutableArray<CustomModifier> RefCustomModifiers => _underlyingField.RefCustomModifiers; internal override TypeWithAnnotations GetFieldType(ConsList<FieldSymbol> fieldsBeingBound) { return _underlyingField.GetFieldType(fieldsBeingBound); } public override ImmutableArray<CSharpAttributeData> GetAttributes() { return _underlyingField.GetAttributes(); } internal override UseSiteInfo<AssemblySymbol> GetUseSiteInfo() { return _underlyingField.GetUseSiteInfo(); } internal override bool RequiresCompletion => _underlyingField.RequiresCompletion; internal override bool HasComplete(CompletionPart part) => _underlyingField.HasComplete(part); internal override void ForceComplete(SourceLocation? locationOpt, Predicate<Symbol>? filter, CancellationToken cancellationToken) { _underlyingField.ForceComplete(locationOpt, filter, cancellationToken); } public sealed override int GetHashCode() { return Hash.Combine(_containingTuple.GetHashCode(), _tupleElementIndex.GetHashCode()); } public sealed override bool Equals(Symbol obj, TypeCompareKind compareKind) { var other = obj as TupleElementFieldSymbol; if ((object?)other == this) { return true; } // note we have to compare both index and name because // in nameless tuple there could be fields that differ only by index // and in named tuples there could be fields that differ only by name return (object?)other != null && _tupleElementIndex == other._tupleElementIndex && TypeSymbol.Equals(_containingTuple, other._containingTuple, compareKind); } public sealed override ImmutableArray<Location> Locations { get { return _locations; } } public sealed override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences { get { return _isImplicitlyDeclared ? ImmutableArray<SyntaxReference>.Empty : GetDeclaringSyntaxReferenceHelper<CSharpSyntaxNode>(_locations); } } public sealed override bool IsImplicitlyDeclared { get { return _isImplicitlyDeclared; } } public sealed override FieldSymbol CorrespondingTupleField { get { return _correspondingDefaultField; } } internal override FieldSymbol AsMember(NamedTypeSymbol newOwner) { Debug.Assert(newOwner.IsTupleType); NamedTypeSymbol newUnderlyingOwner = GetNewUnderlyingOwner(newOwner); return new TupleElementFieldSymbol(newOwner, _underlyingField.OriginalDefinition.AsMember(newUnderlyingOwner), TupleElementIndex, Locations, IsImplicitlyDeclared); } protected NamedTypeSymbol GetNewUnderlyingOwner(NamedTypeSymbol newOwner) { int currentIndex = TupleElementIndex; NamedTypeSymbol newUnderlyingOwner = newOwner; while (currentIndex >= NamedTypeSymbol.ValueTupleRestIndex) { newUnderlyingOwner = (NamedTypeSymbol)newUnderlyingOwner.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[NamedTypeSymbol.ValueTupleRestIndex].Type; currentIndex -= NamedTypeSymbol.ValueTupleRestIndex; } return newUnderlyingOwner; } } /// <summary> /// Represents an element field of a tuple type that is not backed by a real field /// with the same name within the tuple type. /// /// Examples /// // alias to Item1 with a different name /// (int a, byte b).a /// /// // not backed directly by the type /// (int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8).i8 /// /// // Item8, which is also not backed directly by the type /// (int, int, int, int, int, int, int, int).Item8 /// /// NOTE: For any virtual element, there is a nonvirtual way to access the same underlying field. /// In scenarios where we need to enumerate actual fields of a struct, /// virtual fields should be ignored. /// </summary> internal sealed class TupleVirtualElementFieldSymbol : TupleElementFieldSymbol { private readonly string _name; private readonly bool _cannotUse; // With LanguageVersion 7, we will produce named elements that should not be used public TupleVirtualElementFieldSymbol( NamedTypeSymbol container, FieldSymbol underlyingField, string name, int tupleElementIndex, ImmutableArray<Location> locations, bool cannotUse, bool isImplicitlyDeclared, FieldSymbol? correspondingDefaultFieldOpt) : base(container, underlyingField, tupleElementIndex, locations, isImplicitlyDeclared, correspondingDefaultFieldOpt) { // The underlying field for 'Hanna' (an 8-th named element) in a long tuple is Item1. The corresponding field is Item8. Debug.Assert(container.IsTupleType); Debug.Assert(underlyingField.ContainingType.IsTupleType); Debug.Assert(name != null); Debug.Assert(name != underlyingField.Name || !container.Equals(underlyingField.ContainingType, TypeCompareKind.IgnoreDynamicAndTupleNames), "fields that map directly to underlying should not be represented by " + nameof(TupleVirtualElementFieldSymbol)); Debug.Assert((correspondingDefaultFieldOpt is null) == (NamedTypeSymbol.TupleMemberName(tupleElementIndex + 1) == name)); Debug.Assert(!(correspondingDefaultFieldOpt is TupleErrorFieldSymbol)); _name = name; _cannotUse = cannotUse; } internal override UseSiteInfo<AssemblySymbol> GetUseSiteInfo() { if (_cannotUse) { return new UseSiteInfo<AssemblySymbol>(new CSDiagnosticInfo(ErrorCode.ERR_TupleInferredNamesNotAvailable, _name, new CSharpRequiredLanguageVersion(MessageID.IDS_FeatureInferredTupleNames.RequiredVersion()))); } return base.GetUseSiteInfo(); } public override string Name { get { return _name; } } internal override int? TypeLayoutOffset { get { return null; } } public override FieldSymbol OriginalDefinition { get { return this; } } public override bool IsVirtualTupleField { get { return true; } } internal override TypeWithAnnotations GetFieldType(ConsList<FieldSymbol> fieldsBeingBound) => _underlyingField.GetFieldType(fieldsBeingBound); public override ImmutableArray<CSharpAttributeData> GetAttributes() { return _underlyingField.GetAttributes(); } internal override FieldSymbol AsMember(NamedTypeSymbol newOwner) { Debug.Assert(newOwner.IsTupleType); Debug.Assert(newOwner.TupleElements.Length == this._containingTuple.TupleElements.Length); NamedTypeSymbol newUnderlyingOwner = GetNewUnderlyingOwner(newOwner); FieldSymbol? newCorrespondingDefaultFieldOpt = null; if ((object)_correspondingDefaultField != this) { newCorrespondingDefaultFieldOpt = _correspondingDefaultField.OriginalDefinition.AsMember(newOwner); } return new TupleVirtualElementFieldSymbol(newOwner, _underlyingField.OriginalDefinition.AsMember(newUnderlyingOwner), _name, TupleElementIndex, Locations, _cannotUse, IsImplicitlyDeclared, newCorrespondingDefaultFieldOpt); } } }