Example #1
0
        internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics)
        {
            var F = new SyntheticBoundNodeFactory(this, this.SyntaxNode, compilationState, diagnostics);

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

                if (ContainingType.BaseTypeNoUseSiteDiagnostics.IsObjectType())
                {
                    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);
                        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());
            }
        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());
            }
        }
Example #3
0
        internal override void GenerateMethodBodyStatements(SyntheticBoundNodeFactory F, ArrayBuilder <BoundStatement> statements, BindingDiagnosticBag diagnostics)
        {
            // Tracking issue for copy constructor in inheritance scenario: https://github.com/dotnet/roslyn/issues/44902
            // Write assignments to fields
            // .ctor(DerivedRecordType original) : base((BaseRecordType)original)
            // {
            //     this.field1 = parameter.field1
            //     ...
            //     this.fieldN = parameter.fieldN
            // }
            var param = F.Parameter(Parameters[0]);

            foreach (var field in ContainingType.GetFieldsToEmit())
            {
                if (!field.IsStatic)
                {
                    statements.Add(F.Assignment(F.Field(F.This(), field), F.Field(param, field)));
                }
            }
        }
        internal override void GenerateMethodBodyStatements(SyntheticBoundNodeFactory F, ArrayBuilder <BoundStatement> statements, DiagnosticBag diagnostics)
        {
            // PROTOTYPE: Handle inheritance
            // Write assignments to fields
            //
            // {
            //     this.field1 = parameter.field1
            //     ...
            //     this.fieldN = parameter.fieldN
            // }
            var param = F.Parameter(Parameters[0]);

            foreach (var field in ContainingType.GetFieldsToEmit())
            {
                if (!field.IsStatic)
                {
                    statements.Add(F.Assignment(F.Field(F.This(), field), F.Field(param, field)));
                }
            }
        }
Example #5
0
        internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics)
        {
            var             F     = new SyntheticBoundNodeFactory(this, ContainingType.GetNonNullSyntaxNode(), compilationState, diagnostics);
            var             other = F.Parameter(Parameters[0]);
            BoundExpression?retExpr;

            if (IsOverride)
            {
                // This method is an override of a strongly-typed Equals method from a base record type.
                // The definition of the method is as follows, and _otherEqualsMethod
                // is the method to delegate to (see B.Equals(A), C.Equals(A), C.Equals(B) above):
                //
                // override bool Equals(Base other) => Equals(other as Derived);
                retExpr = F.Call(
                    F.This(),
                    _otherEqualsMethod !,
                    F.As(other, ContainingType));
            }
            else
            {
                // This method is the strongly-typed Equals method where the parameter type is
                // the containing type.

                if (_otherEqualsMethod is null)
                {
                    // There are no base record types.
                    // The definition of the method is as follows (see A.Equals(A) above):
                    //
                    // virtual bool Equals(T other) =>
                    //     other != null &&
                    //     EqualityContract == other.EqualityContract &&
                    //     field1 == other.field1 && ... && fieldN == other.fieldN;

                    // other != null
                    Debug.Assert(!other.Type.IsStructType());
                    retExpr = F.ObjectNotEqual(other, F.Null(F.SpecialType(SpecialType.System_Object)));

                    // EqualityContract == other.EqualityContract
                    var contractsEqual = F.Binary(
                        BinaryOperatorKind.ObjectEqual,
                        F.SpecialType(SpecialType.System_Boolean),
                        F.Property(F.This(), _equalityContract),
                        F.Property(other, _equalityContract));

                    retExpr = retExpr is null ? contractsEqual : F.LogicalAnd(retExpr, contractsEqual);
                }
                else
                {
                    // There are base record types.
                    // The definition of the method is as follows, and _otherEqualsMethod
                    // is the corresponding method on the nearest base record type to
                    // delegate to (see B.Equals(B), C.Equals(C) above):
                    //
                    // virtual bool Equals(Derived other) =>
                    //     base.Equals((Base)other) &&
                    //     field1 == other.field1 && ... && fieldN == other.fieldN;
                    retExpr = F.Call(
                        F.Base(_otherEqualsMethod.ContainingType),
                        _otherEqualsMethod !,
                        F.Convert(_otherEqualsMethod.Parameters[0].Type, other));
                }

                // field1 == other.field1 && ... && fieldN == other.fieldN
                // https://github.com/dotnet/roslyn/issues/44895: Should compare fields from non-record base classes.
                var fields = ArrayBuilder <FieldSymbol> .GetInstance();

                foreach (var f in ContainingType.GetFieldsToEmit())
                {
                    if (!f.IsStatic)
                    {
                        fields.Add(f);
                    }
                }
                if (fields.Count > 0)
                {
                    retExpr = MethodBodySynthesizer.GenerateFieldEquals(
                        retExpr,
                        other,
                        fields,
                        F);
                }
                fields.Free();
            }

            F.CloseMethod(F.Block(F.Return(retExpr)));
        }
        internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics)
        {
            var F = new SyntheticBoundNodeFactory(this, ContainingType.GetNonNullSyntaxNode(), compilationState, diagnostics);

            try
            {
                var             other = F.Parameter(Parameters[0]);
                BoundExpression?retExpr;

                // This method is the strongly-typed Equals method where the parameter type is
                // the containing type.

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

                    if (_equalityContract.IsStatic || !_equalityContract.Type.Equals(DeclaringCompilation.GetWellKnownType(WellKnownType.System_Type), TypeCompareKind.AllIgnoreOptions))
                    {
                        // There is a signature mismatch, an error was reported elsewhere
                        F.CloseMethod(F.ThrowNull());
                        return;
                    }

                    // There are no base record types.
                    // The definition of the method is as follows
                    //
                    // virtual bool Equals(T other) =>
                    //     other != null &&
                    //     EqualityContract == other.EqualityContract &&
                    //     field1 == other.field1 && ... && fieldN == other.fieldN;

                    // other != null
                    Debug.Assert(!other.Type.IsStructType());
                    retExpr = F.ObjectNotEqual(other, F.Null(F.SpecialType(SpecialType.System_Object)));

                    // EqualityContract == other.EqualityContract
                    var contractsEqual = F.Call(receiver: null, F.WellKnownMethod(WellKnownMember.System_Type__op_Equality),
                                                F.Property(F.This(), _equalityContract),
                                                F.Property(other, _equalityContract));

                    retExpr = F.LogicalAnd(retExpr, contractsEqual);
                }
                else
                {
                    MethodSymbol?baseEquals = ContainingType.GetMembersUnordered().OfType <SynthesizedRecordBaseEquals>().Single().OverriddenMethod;

                    if (baseEquals is null || !baseEquals.ContainingType.Equals(ContainingType.BaseTypeNoUseSiteDiagnostics, TypeCompareKind.AllIgnoreOptions) ||
                        baseEquals.ReturnType.SpecialType != SpecialType.System_Boolean)
                    {
                        // There was a problem with overriding of base equals, an error was reported elsewhere
                        F.CloseMethod(F.ThrowNull());
                        return;
                    }

                    // There are base record types.
                    // The definition of the method is as follows, and baseEquals
                    // is the corresponding method on the nearest base record type to
                    // delegate to:
                    //
                    // virtual bool Equals(Derived other) =>
                    //     base.Equals((Base)other) &&
                    //     field1 == other.field1 && ... && fieldN == other.fieldN;
                    retExpr = F.Call(
                        F.Base(baseEquals.ContainingType),
                        baseEquals,
                        F.Convert(baseEquals.Parameters[0].Type, other));
                }

                // field1 == other.field1 && ... && fieldN == other.fieldN
                var fields = ArrayBuilder <FieldSymbol> .GetInstance();

                bool foundBadField = false;
                foreach (var f in ContainingType.GetFieldsToEmit())
                {
                    if (!f.IsStatic)
                    {
                        fields.Add(f);

                        var parameterType = f.Type;
                        if (parameterType.IsUnsafe())
                        {
                            diagnostics.Add(ErrorCode.ERR_BadFieldTypeInRecord, f.Locations.FirstOrNone(), parameterType);
                            foundBadField = true;
                        }
                        else if (parameterType.IsRestrictedType())
                        {
                            // We'll have reported a diagnostic elsewhere (SourceMemberFieldSymbol.TypeChecks)
                            foundBadField = true;
                        }
                    }
                }
                if (fields.Count > 0 && !foundBadField)
                {
                    retExpr = MethodBodySynthesizer.GenerateFieldEquals(
                        retExpr,
                        other,
                        fields,
                        F);
                }

                fields.Free();

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