internal AnonymousTypePublicSymbol(AnonymousTypeManager manager, AnonymousTypeDescriptor typeDescr) { typeDescr.AssertIsGood(); this.Manager = manager; this.TypeDescriptor = typeDescr; int fieldsCount = typeDescr.Fields.Length; // members Symbol[] members = new Symbol[fieldsCount * 2 + 1]; int memberIndex = 0; // The array storing property symbols to be used in // generation of constructor and other methods if (fieldsCount > 0) { AnonymousTypePropertySymbol[] propertiesArray = new AnonymousTypePropertySymbol[fieldsCount]; // Process fields for (int fieldIndex = 0; fieldIndex < fieldsCount; fieldIndex++) { // Add a property AnonymousTypePropertySymbol property = new AnonymousTypePropertySymbol(this, typeDescr.Fields[fieldIndex]); propertiesArray[fieldIndex] = property; // Property related symbols members[memberIndex++] = property; members[memberIndex++] = property.GetMethod; } this.Properties = propertiesArray.AsImmutableOrNull(); } else { this.Properties = ImmutableArray<AnonymousTypePropertySymbol>.Empty; } // Add a constructor members[memberIndex++] = new AnonymousTypeConstructorSymbol(this, this.Properties); _members = members.AsImmutableOrNull(); Debug.Assert(memberIndex == _members.Length); // fill nameToSymbols map foreach (var symbol in _members) { _nameToSymbols.Add(symbol.Name, symbol); } }
private CSharpCompilation( string assemblyName, CSharpCompilationOptions options, ImmutableArray<MetadataReference> references, ImmutableArray<SyntaxTree> syntaxTrees, ImmutableDictionary<SyntaxTree, int> syntaxTreeOrdinalMap, ImmutableDictionary<SyntaxTree, Lazy<RootSingleNamespaceDeclaration>> rootNamespaces, DeclarationTable declarationTable, CSharpCompilation previousSubmission, Type submissionReturnType, Type hostObjectType, bool isSubmission, ReferenceManager referenceManager, bool reuseReferenceManager, AsyncQueue<CompilationEvent> eventQueue = null) : base(assemblyName, references, submissionReturnType, hostObjectType, isSubmission, syntaxTreeOrdinalMap, eventQueue) { using (Logger.LogBlock(FunctionId.CSharp_Compilation_Create, message: assemblyName)) { this.wellKnownMemberSignatureComparer = new WellKnownMembersSignatureComparer(this); this.options = options; this.syntaxTrees = syntaxTrees; this.rootNamespaces = rootNamespaces; this.declarationTable = declarationTable; Debug.Assert(syntaxTrees.All(tree => syntaxTrees[syntaxTreeOrdinalMap[tree]] == tree)); Debug.Assert(syntaxTrees.SetEquals(rootNamespaces.Keys.AsImmutable(), EqualityComparer<SyntaxTree>.Default)); this.builtInOperators = new BuiltInOperators(this); this.scriptClass = new Lazy<ImplicitNamedTypeSymbol>(BindScriptClass); this.globalImports = new Lazy<Imports>(BindGlobalUsings); this.globalNamespaceAlias = new Lazy<AliasSymbol>(CreateGlobalNamespaceAlias); this.anonymousTypeManager = new AnonymousTypeManager(this); if (isSubmission) { Debug.Assert(previousSubmission == null || previousSubmission.HostObjectType == hostObjectType); this.previousSubmission = previousSubmission; } else { Debug.Assert(previousSubmission == null && submissionReturnType == null && hostObjectType == null); } if (reuseReferenceManager) { referenceManager.AssertCanReuseForCompilation(this); this.referenceManager = referenceManager; } else { this.referenceManager = new ReferenceManager( MakeSourceAssemblySimpleName(), options.AssemblyIdentityComparer, (referenceManager != null) ? referenceManager.ObservedMetadata : null); } Debug.Assert((object)this.lazyAssemblySymbol == null); if (EventQueue != null) EventQueue.Enqueue(new CompilationStartedEvent(this)); } }
internal AnonymousTypeTemplateSymbol(AnonymousTypeManager manager, AnonymousTypeDescriptor typeDescr) { this.Manager = manager; this.TypeDescriptorKey = typeDescr.Key; _smallestLocation = typeDescr.Location; // Will be set when the type's metadata is ready to be emitted, // <anonymous-type>.Name will throw exception if requested // before that moment. _nameAndIndex = null; int fieldsCount = typeDescr.Fields.Length; int membersCount = fieldsCount * 3 + 1; // members var membersBuilder = ArrayBuilder <Symbol> .GetInstance(membersCount); var propertiesBuilder = ArrayBuilder <AnonymousTypePropertySymbol> .GetInstance(fieldsCount); var typeParametersBuilder = ArrayBuilder <TypeParameterSymbol> .GetInstance(fieldsCount); // Process fields for (int fieldIndex = 0; fieldIndex < fieldsCount; fieldIndex++) { AnonymousTypeField field = typeDescr.Fields[fieldIndex]; // Add a type parameter AnonymousTypeParameterSymbol typeParameter = new AnonymousTypeParameterSymbol(this, fieldIndex, GeneratedNames.MakeAnonymousTypeParameterName(field.Name)); typeParametersBuilder.Add(typeParameter); // Add a property AnonymousTypePropertySymbol property = new AnonymousTypePropertySymbol(this, field, TypeWithAnnotations.Create(typeParameter), fieldIndex); propertiesBuilder.Add(property); // Property related symbols membersBuilder.Add(property); membersBuilder.Add(property.BackingField); membersBuilder.Add(property.GetMethod); } _typeParameters = typeParametersBuilder.ToImmutableAndFree(); this.Properties = propertiesBuilder.ToImmutableAndFree(); // Add a constructor membersBuilder.Add(new AnonymousTypeConstructorSymbol(this, this.Properties)); _members = membersBuilder.ToImmutableAndFree(); Debug.Assert(membersCount == _members.Length); // fill nameToSymbols map foreach (var symbol in _members) { _nameToSymbols.Add(symbol.Name, symbol); } // special members: Equals, GetHashCode, ToString this.SpecialMembers = ImmutableArray.Create <MethodSymbol>( new AnonymousTypeEqualsMethodSymbol(this), new AnonymousTypeGetHashCodeMethodSymbol(this), new AnonymousTypeToStringMethodSymbol(this)); }
internal AnonymousTypeTemplateSymbol(AnonymousTypeManager manager, AnonymousTypeDescriptor typeDescr) { this.Manager = manager; this.TypeDescriptorKey = typeDescr.Key; _smallestLocation = typeDescr.Location; // Will be set when the type's metadata is ready to be emitted, // <anonymous-type>.Name will throw exception if requested // before that moment. _nameAndIndex = null; int fieldsCount = typeDescr.Fields.Length; // members Symbol[] members = new Symbol[fieldsCount * 3 + 1]; int memberIndex = 0; // The array storing property symbols to be used in // generation of constructor and other methods if (fieldsCount > 0) { AnonymousTypePropertySymbol[] propertiesArray = new AnonymousTypePropertySymbol[fieldsCount]; TypeParameterSymbol[] typeParametersArray = new TypeParameterSymbol[fieldsCount]; // Process fields for (int fieldIndex = 0; fieldIndex < fieldsCount; fieldIndex++) { AnonymousTypeField field = typeDescr.Fields[fieldIndex]; // Add a type parameter AnonymousTypeParameterSymbol typeParameter = new AnonymousTypeParameterSymbol(this, fieldIndex, GeneratedNames.MakeAnonymousTypeParameterName(field.Name)); typeParametersArray[fieldIndex] = typeParameter; // Add a property AnonymousTypePropertySymbol property = new AnonymousTypePropertySymbol(this, field, typeParameter); propertiesArray[fieldIndex] = property; // Property related symbols members[memberIndex++] = property; members[memberIndex++] = property.BackingField; members[memberIndex++] = property.GetMethod; } _typeParameters = typeParametersArray.AsImmutable(); this.Properties = propertiesArray.AsImmutable(); } else { _typeParameters = ImmutableArray<TypeParameterSymbol>.Empty; this.Properties = ImmutableArray<AnonymousTypePropertySymbol>.Empty; } // Add a constructor members[memberIndex++] = new AnonymousTypeConstructorSymbol(this, this.Properties); _members = members.AsImmutable(); Debug.Assert(memberIndex == _members.Length); // fill nameToSymbols map foreach (var symbol in _members) { _nameToSymbols.Add(symbol.Name, symbol); } // special members: Equals, GetHashCode, ToString MethodSymbol[] specialMembers = new MethodSymbol[3]; specialMembers[0] = new AnonymousTypeEqualsMethodSymbol(this); specialMembers[1] = new AnonymousTypeGetHashCodeMethodSymbol(this); specialMembers[2] = new AnonymousTypeToStringMethodSymbol(this); this.SpecialMembers = specialMembers.AsImmutable(); }
internal CodeblockTypePublicSymbol(AnonymousTypeManager manager, TypeSymbol[] codeblockParams, Location location) : base(manager, codeblockParams, location) { }
internal AnonymousTypeTemplateSymbol(AnonymousTypeManager manager, AnonymousTypeDescriptor typeDescr) { this.Manager = manager; this.TypeDescriptorKey = typeDescr.Key; this.smallestLocation = typeDescr.Location; // Will be set when the type's metadata is ready to be emitted, // <anonymous-type>.Name will throw exception if requested // before that moment. this.nameAndIndex = null; int fieldsCount = typeDescr.Fields.Length; // members Symbol[] members = new Symbol[fieldsCount * 3 + 1]; int memberIndex = 0; // The array storing property symbols to be used in // generation of constructor and other methods if (fieldsCount > 0) { AnonymousTypePropertySymbol[] propertiesArray = new AnonymousTypePropertySymbol[fieldsCount]; TypeParameterSymbol[] typeParametersArray = new TypeParameterSymbol[fieldsCount]; // Process fields for (int fieldIndex = 0; fieldIndex < fieldsCount; fieldIndex++) { AnonymousTypeField field = typeDescr.Fields[fieldIndex]; // Add a type parameter AnonymousTypeParameterSymbol typeParameter = new AnonymousTypeParameterSymbol(this, fieldIndex, GeneratedNames.MakeAnonymousTypeParameterName(field.Name)); typeParametersArray[fieldIndex] = typeParameter; // Add a property AnonymousTypePropertySymbol property = new AnonymousTypePropertySymbol(this, field, typeParameter); propertiesArray[fieldIndex] = property; // Property related symbols members[memberIndex++] = property; members[memberIndex++] = property.BackingField; members[memberIndex++] = property.GetMethod; } this.typeParameters = typeParametersArray.AsImmutable(); this.Properties = propertiesArray.AsImmutable(); } else { this.typeParameters = ImmutableArray <TypeParameterSymbol> .Empty; this.Properties = ImmutableArray <AnonymousTypePropertySymbol> .Empty; } // Add a constructor members[memberIndex++] = new AnonymousTypeConstructorSymbol(this, this.Properties); this.members = members.AsImmutable(); Debug.Assert(memberIndex == this.members.Length); // fill name2symbol map foreach (var symbol in this.members) { this.name2symbol.Add(symbol.Name, symbol); } // special members: Equals, GetHashCode, ToString MethodSymbol[] specialMembers = new MethodSymbol[3]; specialMembers[0] = new AnonymousTypeEqualsMethodSymbol(this); specialMembers[1] = new AnonymousTypeGetHashCodeMethodSymbol(this); specialMembers[2] = new AnonymousTypeToStringMethodSymbol(this); this.SpecialMembers = specialMembers.AsImmutable(); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { AnonymousTypeManager manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager; SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory(compilationState, diagnostics); // Method body: // // { // $anonymous$ local = value as $anonymous$; // return 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)); // prepare symbols MethodSymbol equalityComparer_Equals = manager.System_Collections_Generic_EqualityComparer_T__Equals; MethodSymbol equalityComparer_get_Default = manager.System_Collections_Generic_EqualityComparer_T__get_Default; NamedTypeSymbol equalityComparerType = equalityComparer_Equals.ContainingType; // Compare fields for (int index = 0; index < anonymousType.Properties.Length; index++) { // Prepare constructed symbols TypeParameterSymbol typeParameter = anonymousType.TypeParameters[index]; FieldSymbol fieldSymbol = anonymousType.Properties[index].BackingField; NamedTypeSymbol constructedEqualityComparer = equalityComparerType.Construct(typeParameter); // Generate 'retExpression' = 'retExpression && System.Collections.Generic.EqualityComparer<T_index>. // Default.Equals(this.backingFld_index, local.backingFld_index)' retExpression = F.LogicalAnd(retExpression, F.Call(F.StaticCall(constructedEqualityComparer, equalityComparer_get_Default.AsMember(constructedEqualityComparer)), equalityComparer_Equals.AsMember(constructedEqualityComparer), F.Field(F.This(), fieldSymbol), F.Field(boundLocal, fieldSymbol))); } // Final return statement BoundStatement retStatement = F.Return(retExpression); // Create a bound block F.CloseMethod(F.Block(ImmutableArray.Create <LocalSymbol>(boundLocal.LocalSymbol), assignment, retStatement)); }
public SynthesizedDelegateValue(AnonymousTypeManager manager, SynthesizedDelegateSymbol @delegate) { Debug.Assert(manager != null && (object)@delegate != null); this.Manager = manager; this.Delegate = @delegate; }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { AnonymousTypeManager manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager; SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory(compilationState, diagnostics); // Method body: // // { // return String.Format( // "{ <name1> = {0}", <name2> = {1}", ... <nameN> = {N-1}", // this.backingFld_1, // this.backingFld_2, // ... // this.backingFld_N // } // Type expression AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType; // build arguments int fieldCount = anonymousType.Properties.Length; BoundExpression retExpression = null; if (fieldCount > 0) { // we do have fields, so have to use String.Format(...) BoundExpression[] arguments = new BoundExpression[fieldCount]; // process properties PooledStringBuilder formatString = PooledStringBuilder.GetInstance(); for (int i = 0; i < fieldCount; i++) { AnonymousTypePropertySymbol property = anonymousType.Properties[i]; // build format string formatString.Builder.AppendFormat(i == 0 ? "{{{{ {0} = {{{1}}}" : ", {0} = {{{1}}}", property.Name, i); // build argument arguments[i] = F.Convert(manager.System_Object, new BoundLoweredConditionalAccess(F.Syntax, F.Field(F.This(), property.BackingField), null, F.Call(new BoundConditionalReceiver( F.Syntax, id: i, type: property.BackingField.Type), manager.System_Object__ToString), null, id: i, type: manager.System_String), ConversionKind.ImplicitReference); } formatString.Builder.Append(" }}"); // add format string argument BoundExpression format = F.Literal(formatString.ToStringAndFree()); // Generate expression for return statement // retExpression <= System.String.Format(args) var formatMethod = manager.System_String__Format_IFormatProvider; retExpression = F.StaticCall(manager.System_String, formatMethod, F.Null(formatMethod.Parameters[0].Type), format, F.ArrayOrEmpty(manager.System_Object, arguments)); } else { // this is an empty anonymous type, just return "{ }" retExpression = F.Literal("{ }"); } F.CloseMethod(F.Block(F.Return(retExpression))); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { AnonymousTypeManager manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager; SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory(compilationState, diagnostics); // Method body: // // HASH_FACTOR = 0xa5555529; // INIT_HASH = (...((0 * HASH_FACTOR) + backingFld_1.Name.GetHashCode()) * HASH_FACTOR // + backingFld_2.Name.GetHashCode()) * HASH_FACTOR // + ... // + backingFld_N.Name.GetHashCode() // // { // 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) // } const int HASH_FACTOR = -1521134295; // (int)0xa5555529 // Type expression AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType; // INIT_HASH int initHash = 0; foreach (var property in anonymousType.Properties) { initHash = unchecked (initHash * HASH_FACTOR + property.BackingField.Name.GetHashCode()); } // 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; NamedTypeSymbol equalityComparerType = equalityComparer_GetHashCode.ContainingType; // bound HASH_FACTOR BoundLiteral boundHashFactor = F.Literal(HASH_FACTOR); // Process fields for (int index = 0; index < anonymousType.Properties.Length; index++) { // Prepare constructed symbols TypeParameterSymbol typeParameter = anonymousType.TypeParameters[index]; NamedTypeSymbol constructedEqualityComparer = equalityComparerType.Construct(typeParameter); // Generate 'retExpression' <= 'retExpression * HASH_FACTOR retExpression = F.Binary(BinaryOperatorKind.IntMultiplication, manager.System_Int32, retExpression, boundHashFactor); // Generate 'retExpression' <= 'retExpression + EqualityComparer<T_index>.Default.GetHashCode(this.backingFld_index)' retExpression = F.Binary(BinaryOperatorKind.IntAddition, manager.System_Int32, retExpression, F.Call( F.StaticCall(constructedEqualityComparer, equalityComparer_get_Default.AsMember(constructedEqualityComparer)), equalityComparer_GetHashCode.AsMember(constructedEqualityComparer), F.Field(F.This(), anonymousType.Properties[index].BackingField))); } // Create a bound block F.CloseMethod(F.Block(F.Return(retExpression))); }
/// <summary> /// SubstType, but for NamedTypeSymbols only. This is used for concrete types, so no alpha substitution appears in the result. /// </summary> internal NamedTypeSymbol SubstituteNamedType(NamedTypeSymbol previous) { if (ReferenceEquals(previous, null)) { return(null); } if (previous.IsUnboundGenericType) { return(previous); } if (previous.IsAnonymousType) { ImmutableArray <TypeSymbol> oldFieldTypes = AnonymousTypeManager.GetAnonymousTypePropertyTypes(previous); ImmutableArray <TypeSymbol> newFieldTypes = SubstituteTypesWithoutModifiers(oldFieldTypes); return((oldFieldTypes == newFieldTypes) ? previous : AnonymousTypeManager.ConstructAnonymousTypeSymbol(previous, newFieldTypes)); } if (previous.IsTupleType) { var previousTuple = (TupleTypeSymbol)previous; NamedTypeSymbol oldUnderlyingType = previousTuple.TupleUnderlyingType; NamedTypeSymbol newUnderlyingType = (NamedTypeSymbol)SubstituteType(oldUnderlyingType).Type; return(((object)newUnderlyingType == (object)oldUnderlyingType) ? previous : previousTuple.WithUnderlyingType(newUnderlyingType)); } // TODO: we could construct the result's ConstructedFrom lazily by using a "deep" // construct operation here (as VB does), thereby avoiding alpha renaming in most cases. // Aleksey has shown that would reduce GC pressure if substitutions of deeply nested generics are common. NamedTypeSymbol oldConstructedFrom = previous.ConstructedFrom; NamedTypeSymbol newConstructedFrom = SubstituteMemberType(oldConstructedFrom); ImmutableArray <TypeSymbol> oldTypeArguments = previous.TypeArgumentsNoUseSiteDiagnostics; bool changed = !ReferenceEquals(oldConstructedFrom, newConstructedFrom); ImmutableArray <ImmutableArray <CustomModifier> > modifiers = previous.HasTypeArgumentsCustomModifiers ? previous.TypeArgumentsCustomModifiers : default(ImmutableArray <ImmutableArray <CustomModifier> >); var newTypeArguments = ArrayBuilder <TypeWithModifiers> .GetInstance(oldTypeArguments.Length); for (int i = 0; i < oldTypeArguments.Length; i++) { var oldArgument = modifiers.IsDefault ? new TypeWithModifiers(oldTypeArguments[i]) : new TypeWithModifiers(oldTypeArguments[i], modifiers[i]); var newArgument = oldArgument.SubstituteTypeWithTupleUnification(this); if (!changed && oldArgument != newArgument) { changed = true; } newTypeArguments.Add(newArgument); } if (!changed) { newTypeArguments.Free(); return(previous); } return(newConstructedFrom.ConstructIfGeneric(newTypeArguments.ToImmutableAndFree())); }
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 ) ); }