internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { var F = new SyntheticBoundNodeFactory(this, this.SyntaxNode, compilationState, diagnostics); try { ParameterSymbol parameter = Parameters[0]; if (parameter.Type.IsErrorType()) { F.CloseMethod(F.ThrowNull()); return; } var retExpr = F.Call( F.This(), ContainingType.GetMembersUnordered().OfType <SynthesizedRecordObjEquals>().Single(), F.Convert(F.SpecialType(SpecialType.System_Object), F.Parameter(parameter))); F.CloseMethod(F.Block(F.Return(retExpr))); } 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 { 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()); } }