File: Symbols\Tuples\TupleErrorFieldSymbol.cs
Web Access
Project: src\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp)
// 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.
 
#nullable disable
 
using System.Collections.Immutable;
using System.Diagnostics;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    /// <summary>
    /// Represents a field of a tuple type (such as (int, byte).Item1)
    /// that doesn't have a corresponding backing field within the tuple underlying type.
    /// Created in response to an error condition.
    /// </summary>
    internal sealed class TupleErrorFieldSymbol : SynthesizedFieldSymbolBase
    {
        private readonly TypeWithAnnotations _type;
 
        /// <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
        /// Otherwise, (-1 - [index in members array]);
        /// </summary>
        private readonly int _tupleElementIndex;
 
        private readonly ImmutableArray<Location> _locations;
        private readonly DiagnosticInfo _useSiteDiagnosticInfo;
        private readonly TupleErrorFieldSymbol _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 TupleErrorFieldSymbol(
            NamedTypeSymbol container,
            string name,
            int tupleElementIndex,
            Location location,
            TypeWithAnnotations type,
            DiagnosticInfo useSiteDiagnosticInfo,
            bool isImplicitlyDeclared,
            TupleErrorFieldSymbol correspondingDefaultFieldOpt)
 
            : base(container, name, isPublic: true, isReadOnly: false, isStatic: false)
        {
            Debug.Assert(name != null);
            _type = type;
            _locations = location == null ? ImmutableArray<Location>.Empty : ImmutableArray.Create(location);
            _useSiteDiagnosticInfo = useSiteDiagnosticInfo;
            _tupleElementIndex = (object)correspondingDefaultFieldOpt == null ? tupleElementIndex << 1 : (tupleElementIndex << 1) + 1;
            _isImplicitlyDeclared = isImplicitlyDeclared;
 
            Debug.Assert((correspondingDefaultFieldOpt == null) == this.IsDefaultTupleElement);
            Debug.Assert(correspondingDefaultFieldOpt == null || correspondingDefaultFieldOpt.IsDefaultTupleElement);
 
            _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 override int TupleElementIndex
        {
            get
            {
                if (_tupleElementIndex < 0)
                {
                    return -1;
                }
 
                return _tupleElementIndex >> 1;
            }
        }
 
        public override bool IsDefaultTupleElement
        {
            get
            {
                // not negative and even
                return (_tupleElementIndex & ((1 << 31) | 1)) == 0;
            }
        }
 
        public override bool IsExplicitlyNamedTupleElement
        {
            get
            {
                return _tupleElementIndex >= 0 && !_isImplicitlyDeclared;
            }
        }
 
        public override FieldSymbol TupleUnderlyingField
        {
            get
            {
                // Failed to find one
                return null;
            }
        }
 
        public override FieldSymbol OriginalDefinition
        {
            get
            {
                return this;
            }
        }
 
        public override ImmutableArray<Location> Locations
        {
            get
            {
                return _locations;
            }
        }
 
        public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
        {
            get
            {
                return _isImplicitlyDeclared ?
                    ImmutableArray<SyntaxReference>.Empty :
                    GetDeclaringSyntaxReferenceHelper<CSharpSyntaxNode>(_locations);
            }
        }
 
        public override bool IsImplicitlyDeclared
        {
            get
            {
                return _isImplicitlyDeclared;
            }
        }
 
        public override FieldSymbol CorrespondingTupleField
        {
            get
            {
                return _correspondingDefaultField;
            }
        }
 
        internal override bool SuppressDynamicAttribute
        {
            get
            {
                return true;
            }
        }
 
        public override RefKind RefKind => RefKind.None;
 
        public override ImmutableArray<CustomModifier> RefCustomModifiers => ImmutableArray<CustomModifier>.Empty;
 
        internal override TypeWithAnnotations GetFieldType(ConsList<FieldSymbol> fieldsBeingBound)
        {
            return _type;
        }
 
        internal override UseSiteInfo<AssemblySymbol> GetUseSiteInfo()
        {
            return new UseSiteInfo<AssemblySymbol>(_useSiteDiagnosticInfo);
        }
 
        public sealed override int GetHashCode()
        {
            return Hash.Combine(ContainingType.GetHashCode(), _tupleElementIndex.GetHashCode());
        }
 
        public override bool Equals(Symbol obj, TypeCompareKind compareKind)
        {
            return Equals(obj as TupleErrorFieldSymbol, compareKind);
        }
 
        public bool Equals(TupleErrorFieldSymbol other, TypeCompareKind compareKind)
        {
            if ((object)other == this)
            {
                return true;
            }
 
            return (object)other != null &&
                _tupleElementIndex == other._tupleElementIndex &&
                TypeSymbol.Equals(ContainingType, other.ContainingType, compareKind);
        }
 
        internal override FieldSymbol AsMember(NamedTypeSymbol newOwner)
        {
            Debug.Assert(newOwner.IsTupleType && newOwner.TupleElementTypesWithAnnotations.Length > TupleElementIndex);
            if (ReferenceEquals(newOwner, ContainingType))
            {
                return this;
            }
 
            TupleErrorFieldSymbol newCorrespondingField = null;
            if (!ReferenceEquals(_correspondingDefaultField, this))
            {
                newCorrespondingField = (TupleErrorFieldSymbol)_correspondingDefaultField.AsMember(newOwner);
            }
 
            return new TupleErrorFieldSymbol(
                newOwner,
                Name,
                TupleElementIndex,
                _locations.IsEmpty ? null : GetFirstLocation(),
                newOwner.TupleElementTypesWithAnnotations[TupleElementIndex],
                _useSiteDiagnosticInfo,
                _isImplicitlyDeclared,
                newCorrespondingField);
        }
    }
}