File: Symbols\Synthesized\Records\SynthesizedRecordObjEquals.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.
 
using System.Collections.Immutable;
 
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    /// <summary>
    /// The record type includes a synthesized override of object.Equals(object? obj).
    /// It is an error if the override is declared explicitly. The synthesized override
    /// returns Equals(other as R) where R is the record type.
    /// </summary>
    internal sealed class SynthesizedRecordObjEquals : SynthesizedRecordObjectMethod
    {
        private readonly MethodSymbol _typedRecordEquals;
 
        public SynthesizedRecordObjEquals(SourceMemberContainerTypeSymbol containingType, MethodSymbol typedRecordEquals, int memberOffset)
            : base(containingType, WellKnownMemberNames.ObjectEquals, memberOffset, isReadOnly: containingType.IsRecordStruct)
        {
            _typedRecordEquals = typedRecordEquals;
        }
 
        protected override SpecialMember OverriddenSpecialMember => SpecialMember.System_Object__Equals;
 
        protected override (TypeWithAnnotations ReturnType, ImmutableArray<ParameterSymbol> Parameters)
            MakeParametersAndBindReturnType(BindingDiagnosticBag diagnostics)
        {
            var compilation = DeclaringCompilation;
            var location = ReturnTypeLocation;
            var annotation = ContainingType.IsRecordStruct ? NullableAnnotation.Oblivious : NullableAnnotation.Annotated;
            return (ReturnType: TypeWithAnnotations.Create(Binder.GetSpecialType(compilation, SpecialType.System_Boolean, location, diagnostics)),
                    Parameters: ImmutableArray.Create<ParameterSymbol>(
                                    new SourceSimpleParameterSymbol(owner: this,
                                                                    TypeWithAnnotations.Create(Binder.GetSpecialType(compilation, SpecialType.System_Object, location, diagnostics), annotation),
                                                                    ordinal: 0, RefKind.None, "obj", Locations)));
        }
 
        protected override int GetParameterCountFromSyntax() => 1;
 
        internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics)
        {
            var F = new SyntheticBoundNodeFactory(this, this.SyntaxNode, compilationState, diagnostics);
 
            try
            {
                if (_typedRecordEquals.ReturnType.SpecialType != SpecialType.System_Boolean)
                {
                    // There is a signature mismatch, an error was reported elsewhere
                    F.CloseMethod(F.ThrowNull());
                    return;
                }
 
                var paramAccess = F.Parameter(Parameters[0]);
 
                BoundExpression expression;
                if (ContainingType.IsRecordStruct)
                {
                    // For record structs:
                    //      return other is R && Equals((R)other)
                    expression = F.LogicalAnd(
                        F.Is(paramAccess, ContainingType),
                        F.Call(F.This(), _typedRecordEquals, F.Convert(ContainingType, paramAccess)));
                }
                else
                {
                    // For record classes:
                    //      return this.Equals(param as ContainingType);
                    expression = F.Call(F.This(), _typedRecordEquals, F.As(paramAccess, ContainingType));
                }
 
                F.CloseMethod(F.Block(ImmutableArray.Create<BoundStatement>(F.Return(expression))));
            }
            catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex)
            {
                diagnostics.Add(ex.Diagnostic);
                F.CloseMethod(F.ThrowNull());
            }
        }
    }
}