/// <summary> /// Given a SynthesizedSealedPropertyAccessor (an accessor with a reference to the accessor it overrides), /// construct a BoundBlock body. /// </summary> internal override void GenerateMethodBody( TypeCompilationState compilationState, BindingDiagnosticBag diagnostics ) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory( this, this.GetNonNullSyntaxNode(), compilationState, diagnostics ); F.CurrentFunction = (MethodSymbol)this.OriginalDefinition; try { F.CloseMethod( MethodBodySynthesizer.ConstructSingleInvocationMethodBody( F, this.OverriddenAccessor, useBaseReference: true ) ); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); F.CloseMethod(F.ThrowNull()); } }
/// <summary> /// Given a SynthesizedSealedPropertyAccessor (an accessor with a reference to the accessor it overrides), /// construct a BoundBlock body. /// </summary> internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentFunction = this.OriginalDefinition; try { MethodSymbol methodBeingWrapped = this.BaseMethod; if (this.Arity > 0) { Debug.Assert(this.Arity == methodBeingWrapped.Arity); methodBeingWrapped = methodBeingWrapped.ConstructedFrom.Construct(StaticCast <TypeSymbol> .From(this.TypeParameters)); } BoundBlock body = MethodBodySynthesizer.ConstructSingleInvocationMethodBody(F, methodBeingWrapped, useBaseReference: true); if (body.Kind != BoundKind.Block) { body = F.Block(body); } F.CompilationState.AddMethodWrapper(methodBeingWrapped, this, body); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); } }
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))); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { AnonymousTypeManager manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager; SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory(compilationState, diagnostics); // Method body: // // { // $anonymous$ local = value as $anonymous$; // return (object)local == this || (local != null // && System.Collections.Generic.EqualityComparer<T_1>.Default.Equals(this.backingFld_1, local.backingFld_1) // ... // && System.Collections.Generic.EqualityComparer<T_N>.Default.Equals(this.backingFld_N, local.backingFld_N)); // } // Type and type expression AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType; // local BoundAssignmentOperator assignmentToTemp; BoundLocal boundLocal = F.StoreToTemp(F.As(F.Parameter(_parameters[0]), anonymousType), out assignmentToTemp); // Generate: statement <= 'local = value as $anonymous$' BoundStatement assignment = F.ExpressionStatement(assignmentToTemp); // Generate expression for return statement // retExpression <= 'local != null' BoundExpression retExpression = F.Binary(BinaryOperatorKind.ObjectNotEqual, manager.System_Boolean, F.Convert(manager.System_Object, boundLocal), F.Null(manager.System_Object)); // Compare fields if (anonymousType.Properties.Length > 0) { var fields = ArrayBuilder <FieldSymbol> .GetInstance(anonymousType.Properties.Length); foreach (var prop in anonymousType.Properties) { fields.Add(prop.BackingField); } retExpression = MethodBodySynthesizer.GenerateFieldEquals(retExpression, boundLocal, fields, F); fields.Free(); } // Compare references retExpression = F.LogicalOr(F.ObjectEqual(F.This(), boundLocal), retExpression); // Final return statement BoundStatement retStatement = F.Return(retExpression); // Create a bound block F.CloseMethod(F.Block(ImmutableArray.Create <LocalSymbol>(boundLocal.LocalSymbol), assignment, retStatement)); }
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()); } }
/// <summary> /// Given a SynthesizedExplicitImplementationMethod (effectively a tuple (interface method, implementing method, implementing type)), /// construct a BoundBlock body. Consider the tuple (Interface.Goo, Base.Goo, Derived). The generated method will look like: /// /// R Interface.Goo<T1, T2, ...>(A1 a1, A2 a2, ...) /// { /// //don't return the output if the return type is void /// return this.Goo<T1, T2, ...>(a1, a2, ...); /// } /// </summary> internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentFunction = (MethodSymbol)this.OriginalDefinition; try { MethodSymbol methodToInvoke = this.IsGenericMethod ? this.ImplementingMethod.Construct(this.TypeParameters.Cast <TypeParameterSymbol, TypeSymbol>()) : this.ImplementingMethod; F.CloseMethod(MethodBodySynthesizer.ConstructSingleInvocationMethodBody(F, methodToInvoke, useBaseReference: false)); } 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); 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()); } }
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()); }