コード例 #1
0
            internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics)
            {
                AnonymousTypeManager      manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager;
                SyntheticBoundNodeFactory F       = this.CreateBoundNodeFactory(compilationState, diagnostics);

                //  Method body:
                //
                //  HASH_FACTOR = 0xa5555529;
                //  INIT_HASH = (...((0 * HASH_FACTOR) + GetFNVHashCode(backingFld_1.Name)) * HASH_FACTOR
                //                                     + GetFNVHashCode(backingFld_2.Name)) * HASH_FACTOR
                //                                     + ...
                //                                     + GetFNVHashCode(backingFld_N.Name)
                //
                //  {
                //      return (...((INITIAL_HASH * HASH_FACTOR) + EqualityComparer<T_1>.Default.GetHashCode(this.backingFld_1)) * HASH_FACTOR
                //                                               + EqualityComparer<T_2>.Default.GetHashCode(this.backingFld_2)) * HASH_FACTOR
                //                                               ...
                //                                               + EqualityComparer<T_N>.Default.GetHashCode(this.backingFld_N)
                //  }
                //
                // Where GetFNVHashCode is the FNV-1a hash code.

                // Type expression
                AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType;

                //  INIT_HASH
                int initHash = 0;

                foreach (var property in anonymousType.Properties)
                {
                    initHash = unchecked (initHash * MethodBodySynthesizer.HASH_FACTOR + Hash.GetFNVHashCode(property.BackingField.Name));
                }

                //  Generate expression for return statement
                //      retExpression <= 'INITIAL_HASH'
                BoundExpression retExpression = F.Literal(initHash);

                //  prepare symbols
                MethodSymbol equalityComparer_GetHashCode = manager.System_Collections_Generic_EqualityComparer_T__GetHashCode;
                MethodSymbol equalityComparer_get_Default = manager.System_Collections_Generic_EqualityComparer_T__get_Default;

                //  bound HASH_FACTOR
                BoundLiteral boundHashFactor = null;

                // Process fields
                for (int index = 0; index < anonymousType.Properties.Length; index++)
                {
                    retExpression = MethodBodySynthesizer.GenerateHashCombine(retExpression, equalityComparer_GetHashCode, equalityComparer_get_Default, ref boundHashFactor,
                                                                              F.Field(F.This(), anonymousType.Properties[index].BackingField),
                                                                              F);
                }

                // Create a bound block
                F.CloseMethod(F.Block(F.Return(retExpression)));
            }
コード例 #2
0
        internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics)
        {
            var F = new SyntheticBoundNodeFactory(this, ContainingType.GetNonNullSyntaxNode(), compilationState, diagnostics);

            try
            {
                MethodSymbol equalityComparer_GetHashCode = F.WellKnownMethod(WellKnownMember.System_Collections_Generic_EqualityComparer_T__GetHashCode, isOptional: false) !;
                MethodSymbol equalityComparer_get_Default = F.WellKnownMethod(WellKnownMember.System_Collections_Generic_EqualityComparer_T__get_Default, isOptional: false) !;

                BoundExpression currentHashValue;

                if (ContainingType.BaseTypeNoUseSiteDiagnostics.IsObjectType())
                {
                    // There are no base record types.
                    // Get hash code of the equality contract and combine it with hash codes for field values.
                    currentHashValue = MethodBodySynthesizer.GenerateGetHashCode(equalityComparer_GetHashCode, equalityComparer_get_Default, F.Property(F.This(), _equalityContract), F);
                }
                else
                {
                    // There are base record types.
                    // Get base.GetHashCode() and combine it with hash codes for field values.
                    var overridden = OverriddenMethod;
                    currentHashValue = F.Call(F.Base(overridden.ContainingType), overridden);
                }

                //  bound HASH_FACTOR
                BoundLiteral?boundHashFactor = null;

                foreach (var f in ContainingType.GetFieldsToEmit())
                {
                    if (!f.IsStatic)
                    {
                        currentHashValue = MethodBodySynthesizer.GenerateHashCombine(currentHashValue, equalityComparer_GetHashCode, equalityComparer_get_Default, ref boundHashFactor,
                                                                                     F.Field(F.This(), f),
                                                                                     F);
                    }
                }

                F.CloseMethod(F.Block(F.Return(currentHashValue)));
            }
            catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex)
            {
                diagnostics.Add(ex.Diagnostic);
                F.CloseMethod(F.ThrowNull());
            }
        }
コード例 #3
0
        internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics)
        {
            var F = new SyntheticBoundNodeFactory(this, this.SyntaxNode, compilationState, diagnostics);

            try
            {
                MethodSymbol?   equalityComparer_GetHashCode = null;
                MethodSymbol?   equalityComparer_get_Default = null;
                BoundExpression?currentHashValue;

                if (ContainingType.IsRecordStruct)
                {
                    currentHashValue = null;
                }
                else if (ContainingType.BaseTypeNoUseSiteDiagnostics.IsObjectType())
                {
                    Debug.Assert(_equalityContract is not null);
                    if (_equalityContract.GetMethod is null)
                    {
                        // The equality contract isn't usable, an error was reported elsewhere
                        F.CloseMethod(F.ThrowNull());
                        return;
                    }

                    if (_equalityContract.IsStatic)
                    {
                        F.CloseMethod(F.ThrowNull());
                        return;
                    }

                    // There are no base record types.
                    // Get hash code of the equality contract and combine it with hash codes for field values.
                    ensureEqualityComparerHelpers(F, ref equalityComparer_GetHashCode, ref equalityComparer_get_Default);
                    currentHashValue = MethodBodySynthesizer.GenerateGetHashCode(equalityComparer_GetHashCode, equalityComparer_get_Default, F.Property(F.This(), _equalityContract), F);
                }
                else
                {
                    // There are base record types.
                    // Get base.GetHashCode() and combine it with hash codes for field values.
                    var overridden = OverriddenMethod;

                    if (overridden is null || overridden.ReturnType.SpecialType != SpecialType.System_Int32)
                    {
                        // There was a problem with overriding, an error was reported elsewhere
                        F.CloseMethod(F.ThrowNull());
                        return;
                    }

                    currentHashValue = F.Call(F.Base(overridden.ContainingType), overridden);
                }

                //  bound HASH_FACTOR
                BoundLiteral?boundHashFactor = null;

                foreach (var f in ContainingType.GetFieldsToEmit())
                {
                    if (!f.IsStatic)
                    {
                        ensureEqualityComparerHelpers(F, ref equalityComparer_GetHashCode, ref equalityComparer_get_Default);
                        if (currentHashValue is null)
                        {
                            // EqualityComparer<field type>.Default.GetHashCode(this.field)
                            currentHashValue = MethodBodySynthesizer.GenerateGetHashCode(equalityComparer_GetHashCode, equalityComparer_get_Default, F.Field(F.This(), f), F);
                        }
                        else
                        {
                            currentHashValue = MethodBodySynthesizer.GenerateHashCombine(currentHashValue, equalityComparer_GetHashCode, equalityComparer_get_Default, ref boundHashFactor,
                                                                                         F.Field(F.This(), f),
                                                                                         F);
                        }
                    }
                }

                if (currentHashValue is null)
                {
                    currentHashValue = F.Literal(0);
                }

                F.CloseMethod(F.Block(F.Return(currentHashValue)));
            }
            catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex)
            {
                diagnostics.Add(ex.Diagnostic);
                F.CloseMethod(F.ThrowNull());
            }