| File: Symbols\SubstitutedFieldSymbol.cs | Web Access |
| Project: src\roslyn\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; using System.Collections.Immutable; using System.Threading; using Roslyn.Utilities; using Microsoft.CodeAnalysis.CSharp.Emit; namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal sealed class SubstitutedFieldSymbol : WrappedFieldSymbol { private readonly SubstitutedNamedTypeSymbol _containingType; private TypeWithAnnotations.Boxed _lazyType; internal SubstitutedFieldSymbol(SubstitutedNamedTypeSymbol containingType, FieldSymbol substitutedFrom) : base((FieldSymbol)substitutedFrom.OriginalDefinition) { _containingType = containingType; } internal override TypeWithAnnotations GetFieldType(ConsList<FieldSymbol> fieldsBeingBound) { if (_lazyType == null) { var type = _containingType.TypeSubstitution.SubstituteType(OriginalDefinition.GetFieldType(fieldsBeingBound)); Interlocked.CompareExchange(ref _lazyType, new TypeWithAnnotations.Boxed(type), null); } return _lazyType.Value; } public override Symbol ContainingSymbol { get { return _containingType; } } public override NamedTypeSymbol ContainingType { get { return _containingType; } } public override FieldSymbol OriginalDefinition { get { return _underlyingField; } } public override bool IsImplicitlyDeclared { get { if (this.ContainingType.IsTupleType && this.IsDefaultTupleElement) { // To improve backwards compatibility with earlier implementation of tuples, // we pretend that default tuple element fields are implicitly declared, despite having locations return true; } return base.IsImplicitlyDeclared; } } public override ImmutableArray<CSharpAttributeData> GetAttributes() { return OriginalDefinition.GetAttributes(); } public override Symbol AssociatedSymbol { get { Symbol underlying = OriginalDefinition.AssociatedSymbol; if ((object)underlying == null) { return null; } return underlying.SymbolAsMember(ContainingType); } } internal sealed override CallerUnsafeMode GetCallerUnsafeMode(ConsList<FieldSymbol> fieldsBeingBound) => _underlyingField.GetCallerUnsafeMode(fieldsBeingBound); internal override NamedTypeSymbol FixedImplementationType(PEModuleBuilder emitModule) { // This occurs rarely, if ever. The scenario would be a generic struct // containing a fixed-size buffer. Given the rarity there would be little // benefit to "optimizing" the performance of this by caching the // translated implementation type. return (NamedTypeSymbol)_containingType.TypeSubstitution.SubstituteType(OriginalDefinition.FixedImplementationType(emitModule)).Type; } public override RefKind RefKind => _underlyingField.RefKind; public override ImmutableArray<CustomModifier> RefCustomModifiers => _containingType.TypeSubstitution.SubstituteCustomModifiers(_underlyingField.RefCustomModifiers); public override bool Equals(Symbol obj, TypeCompareKind compareKind) { if ((object)this == obj) { return true; } var other = obj as FieldSymbol; return (object)other != null && TypeSymbol.Equals(_containingType, other.ContainingType, compareKind) && OriginalDefinition == other.OriginalDefinition; } public override int GetHashCode() { var code = this.OriginalDefinition.GetHashCode(); // If the containing type of the original definition is the same as our containing type // it's possible that we will compare equal to the original definition under certain conditions // (e.g, ignoring nullability) and want to retain the same hashcode. As such only make // the containing type part of the hashcode when we know equality isn't possible var containingHashCode = _containingType.GetHashCode(); if (containingHashCode != this.OriginalDefinition.ContainingType.GetHashCode()) { code = Hash.Combine(containingHashCode, code); } return code; } } }