protected MethodToClassRewriter(TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo) { Debug.Assert(compilationState != null); this.CompilationState = compilationState; this.Diagnostics = diagnostics; this.globalGenerateDebugInfo = generateDebugInfo; }
protected MethodToClassRewriter(TypeCompilationState compilationState, DiagnosticBag diagnostics) { Debug.Assert(compilationState != null); Debug.Assert(diagnostics != null); this.CompilationState = compilationState; this.Diagnostics = diagnostics; }
protected MethodToClassRewriter(VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) { Debug.Assert(compilationState != null); Debug.Assert(diagnostics != null); this.CompilationState = compilationState; this.Diagnostics = diagnostics; this.slotAllocatorOpt = slotAllocatorOpt; }
protected MethodToClassRewriter(TypeCompilationState compilationState, HashSet<Symbol> variablesCaptured, DiagnosticBag diagnostics, bool generateDebugInfo) { Debug.Assert(compilationState != null); Debug.Assert(diagnostics != null); this.CompilationState = compilationState; this.Diagnostics = diagnostics; this.globalGenerateDebugInfo = generateDebugInfo; this.variablesCaptured = variablesCaptured; }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { // Method body: // // { // return this.backingField; // } SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory(compilationState, diagnostics); F.CloseMethod(F.Block(F.Return(F.Field(F.This(), _property.BackingField)))); }
internal static BoundStatement ParseAndBindMethodBody(string program, bool lower, string typeName = DefaultTypeName, string methodName = DefaultMethodName) { var compilation = CreateCompilationWithMscorlib(program); var method = (MethodSymbol)compilation.GlobalNamespace.GetTypeMembers(typeName).Single().GetMembers(methodName).Single(); var diagnostics = DiagnosticBag.GetInstance(); try { // Provide an Emit.Module so that the lowering passes will be run var module = new PEAssemblyBuilder( (SourceAssemblySymbol)compilation.Assembly, EmitOptions.Default, OutputKind.ConsoleApplication, GetDefaultModulePropertiesForSerialization(), Enumerable.Empty<ResourceDescription>(), assemblySymbolMapper: null); TypeCompilationState compilationState = new TypeCompilationState(method.ContainingType, compilation, module); var block = MethodCompiler.BindMethodBody(method, compilationState, diagnostics); if ((block == null) || !lower) { return block; } StateMachineTypeSymbol stateMachineTypeOpt; VariableSlotAllocator lazyVariableSlotAllocator = null; var lambdaDebugInfoBuilder = ArrayBuilder<LambdaDebugInfo>.GetInstance(); var closureDebugInfoBuilder = ArrayBuilder<ClosureDebugInfo>.GetInstance(); var body = MethodCompiler.LowerBodyOrInitializer( method: method, methodOrdinal: 0, body: block, previousSubmissionFields: null, compilationState: compilationState, diagnostics: diagnostics, lazyVariableSlotAllocator: ref lazyVariableSlotAllocator, lambdaDebugInfoBuilder: lambdaDebugInfoBuilder, closureDebugInfoBuilder: closureDebugInfoBuilder, stateMachineTypeOpt: out stateMachineTypeOpt); lambdaDebugInfoBuilder.Free(); closureDebugInfoBuilder.Free(); return body; } finally { diagnostics.Free(); } }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { CSharpSyntaxNode syntax = this.GetNonNullSyntaxNode(); SyntheticBoundNodeFactory factory = new SyntheticBoundNodeFactory(this, syntax, compilationState, diagnostics); factory.CurrentMethod = this; ArrayBuilder<BoundStatement> body = ArrayBuilder<BoundStatement>.GetInstance(); // Initialize the payload root for each kind of dynamic analysis instrumentation. // A payload root is an array of arrays of per-method instrumentation payloads. // For each kind of instrumentation: // // payloadRoot = new T[MaximumMethodDefIndex + 1][]; // // where T is the type of the payload at each instrumentation point, and MaximumMethodDefIndex is the // index portion of the greatest method definition token in the compilation. This guarantees that any // method can use the index portion of its own method definition token as an index into the payload array. try { foreach (KeyValuePair<int, InstrumentationPayloadRootField> payloadRoot in ContainingPrivateImplementationDetailsType.GetInstrumentationPayloadRoots()) { int analysisKind = payloadRoot.Key; ArrayTypeSymbol payloadArrayType = (ArrayTypeSymbol)payloadRoot.Value.Type; BoundStatement payloadInitialization = factory.Assignment( factory.InstrumentationPayloadRoot(analysisKind, payloadArrayType), factory.Array(payloadArrayType.ElementType, factory.Binary(BinaryOperatorKind.Addition, factory.SpecialType(SpecialType.System_Int32), factory.MaximumMethodDefIndex(), factory.Literal(1)))); body.Add(payloadInitialization); } // Initialize the module version ID (MVID) field. Dynamic instrumentation requires the MVID of the executing module, and this field makes that accessible. // MVID = Guid.Parse(ModuleVersionIdString); body.Add( factory.Assignment( factory.ModuleVersionId(), factory.StaticCall( WellKnownMember.System_Guid__Parse, factory.ModuleVersionIdString()))); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember missing) { diagnostics.Add(missing.Diagnostic); } BoundStatement returnStatement = factory.Return(); body.Add(returnStatement); factory.CloseMethod(factory.Block(body.ToImmutableAndFree())); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { var noLocals = ImmutableArray<LocalSymbol>.Empty; var initializerInvocation = MethodCompiler.BindConstructorInitializer(this, diagnostics, compilationState.Compilation); var syntax = initializerInvocation.Syntax; compilationState.AddSynthesizedMethod(this, new BoundBlock( syntax, noLocals, ImmutableArray.Create<BoundStatement>( new BoundExpressionStatement(syntax, initializerInvocation), new BoundReturnStatement(syntax, RefKind.None, null)))); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { // Method body: // // { // Object..ctor(); // this.backingField_1 = arg1; // ... // this.backingField_N = argN; // } SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory(compilationState, diagnostics); int paramCount = this.ParameterCount; // List of statements BoundStatement[] statements = new BoundStatement[paramCount + 2]; int statementIndex = 0; // explicit base constructor call BoundExpression call = MethodCompiler.GenerateObjectConstructorInitializer(this, diagnostics); if (call == null) { // This may happen if Object..ctor is not found or is unaccessible return; } statements[statementIndex++] = F.ExpressionStatement(call); if (paramCount > 0) { AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType; Debug.Assert(anonymousType.Properties.Length == paramCount); // Assign fields for (int index = 0; index < this.ParameterCount; index++) { // Generate 'field' = 'parameter' statement statements[statementIndex++] = F.Assignment(F.Field(F.This(), anonymousType.Properties[index].BackingField), F.Parameter(_parameters[index])); } } // Final return statement statements[statementIndex++] = F.Return(); // Create a bound block F.CloseMethod(F.Block(statements)); }
internal static BoundBlock ParseAndBindMethodBody(string program, string typeName = DefaultTypeName, string methodName = DefaultMethodName) { var compilation = CreateCompilationWithMscorlib(program); var method = (MethodSymbol)compilation.GlobalNamespace.GetTypeMembers(typeName).Single().GetMembers(methodName).Single(); // Provide an Emit.Module so that the lowering passes will be run var module = new PEAssemblyBuilder( (SourceAssemblySymbol)compilation.Assembly, emitOptions: EmitOptions.Default, outputKind: OutputKind.ConsoleApplication, serializationProperties: GetDefaultModulePropertiesForSerialization(), manifestResources: Enumerable.Empty<ResourceDescription>()); TypeCompilationState compilationState = new TypeCompilationState(method.ContainingType, compilation, module); var diagnostics = DiagnosticBag.GetInstance(); var block = MethodCompiler.BindMethodBody(method, compilationState, diagnostics); diagnostics.Free(); return block; }
internal static BoundStatement ParseAndBindMethodBody(string program, bool lower, string typeName = DefaultTypeName, string methodName = DefaultMethodName) { var compilation = CreateCompilationWithMscorlib(program); var method = (MethodSymbol)compilation.GlobalNamespace.GetTypeMembers(typeName).Single().GetMembers(methodName).Single(); var diagnostics = DiagnosticBag.GetInstance(); try { var block = Compiler.BindMethodBody(method, diagnostics); if ((block == null) || !lower) { return block; } // Provide an Emit.Module so that the lowering passes will be run var module = new PEAssemblyBuilder( (SourceAssemblySymbol)compilation.Assembly, null, OutputKind.ConsoleApplication, GetDefaultModulePropertiesForSerialization(), Enumerable.Empty<ResourceDescription>(), assemblySymbolMapper: null); TypeCompilationState compilationState = new TypeCompilationState(method.ContainingType, module); var body = Compiler.LowerStatement( generateDebugInfo: true, method: method, body: block, previousSubmissionFields: null, compilationState: compilationState, diagnostics: diagnostics); return body; } finally { diagnostics.Free(); } }
internal abstract override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics);
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))); }
protected SyntheticBoundNodeFactory CreateBoundNodeFactory(TypeCompilationState compilationState, DiagnosticBag diagnostics) { var F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentMethod = this; return F; }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { var factory = new SyntheticBoundNodeFactory(this, _syntax, compilationState, diagnostics); factory.CurrentMethod = this; // The method body is "throw null;" although the body // is arbitrary since the method will not be invoked. var body = factory.Block(factory.ThrowNull()); factory.CloseMethod(body); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { var body = _generateMethodBody(this, diagnostics); var compilation = compilationState.Compilation; _lazyReturnType = CalculateReturnType(compilation, body); // Can't do this until the return type has been computed. TypeParameterChecker.Check(this, _allTypeParameters); if (diagnostics.HasAnyErrors()) { return; } DiagnosticsPass.IssueDiagnostics(compilation, body, diagnostics, this); if (diagnostics.HasAnyErrors()) { return; } // Check for use-site diagnostics (e.g. missing types in the signature). DiagnosticInfo useSiteDiagnosticInfo = null; this.CalculateUseSiteDiagnostic(ref useSiteDiagnosticInfo); if (useSiteDiagnosticInfo != null && useSiteDiagnosticInfo.Severity == DiagnosticSeverity.Error) { diagnostics.Add(useSiteDiagnosticInfo, this.Locations[0]); return; } var declaredLocals = PooledHashSet<LocalSymbol>.GetInstance(); try { // Rewrite local declaration statement. body = (BoundStatement)LocalDeclarationRewriter.Rewrite(compilation, _container, declaredLocals, body); // Verify local declaration names. foreach (var local in declaredLocals) { Debug.Assert(local.Locations.Length > 0); var name = local.Name; if (name.StartsWith("$", StringComparison.Ordinal)) { diagnostics.Add(ErrorCode.ERR_UnexpectedCharacter, local.Locations[0], name[0]); return; } } // Rewrite references to placeholder "locals". body = (BoundStatement)PlaceholderLocalRewriter.Rewrite(compilation, _container, declaredLocals, body); } finally { declaredLocals.Free(); } var syntax = body.Syntax; var statementsBuilder = ArrayBuilder<BoundStatement>.GetInstance(); statementsBuilder.Add(body); // Insert an implicit return statement if necessary. if (body.Kind != BoundKind.ReturnStatement) { statementsBuilder.Add(new BoundReturnStatement(syntax, expressionOpt: null)); } var localsBuilder = ArrayBuilder<LocalSymbol>.GetInstance(); var localsSet = PooledHashSet<LocalSymbol>.GetInstance(); foreach (var local in this.LocalsForBinding) { Debug.Assert(!localsSet.Contains(local)); localsBuilder.Add(local); localsSet.Add(local); } foreach (var local in this.Locals) { if (!localsSet.Contains(local)) { localsBuilder.Add(local); } } localsSet.Free(); body = new BoundBlock(syntax, localsBuilder.ToImmutableAndFree(), statementsBuilder.ToImmutableAndFree()) { WasCompilerGenerated = true }; Debug.Assert(!diagnostics.HasAnyErrors()); Debug.Assert(!body.HasErrors); bool sawLambdas; bool sawAwaitInExceptionHandler; body = LocalRewriter.Rewrite( compilation: this.DeclaringCompilation, method: this, methodOrdinal: _methodOrdinal, containingType: _container, statement: body, compilationState: compilationState, previousSubmissionFields: null, allowOmissionOfConditionalCalls: false, diagnostics: diagnostics, sawLambdas: out sawLambdas, sawAwaitInExceptionHandler: out sawAwaitInExceptionHandler); Debug.Assert(!sawAwaitInExceptionHandler); if (body.HasErrors) { return; } // Variables may have been captured by lambdas in the original method // or in the expression, and we need to preserve the existing values of // those variables in the expression. This requires rewriting the variables // in the expression based on the closure classes from both the original // method and the expression, and generating a preamble that copies // values into the expression closure classes. // // Consider the original method: // static void M() // { // int x, y, z; // ... // F(() => x + y); // } // and the expression in the EE: "F(() => x + z)". // // The expression is first rewritten using the closure class and local <1> // from the original method: F(() => <1>.x + z) // Then lambda rewriting introduces a new closure class that includes // the locals <1> and z, and a corresponding local <2>: F(() => <2>.<1>.x + <2>.z) // And a preamble is added to initialize the fields of <2>: // <2> = new <>c__DisplayClass0(); // <2>.<1> = <1>; // <2>.z = z; // Rewrite "this" and "base" references to parameter in this method. // Rewrite variables within body to reference existing display classes. body = (BoundStatement)CapturedVariableRewriter.Rewrite( this.SubstitutedSourceMethod.IsStatic ? null : _parameters[0], compilation.Conversions, _displayClassVariables, body, diagnostics); if (body.HasErrors) { Debug.Assert(false, "Please add a test case capturing whatever caused this assert."); return; } if (diagnostics.HasAnyErrors()) { return; } if (sawLambdas) { var closureDebugInfoBuilder = ArrayBuilder<ClosureDebugInfo>.GetInstance(); var lambdaDebugInfoBuilder = ArrayBuilder<LambdaDebugInfo>.GetInstance(); body = LambdaRewriter.Rewrite( loweredBody: body, thisType: this.SubstitutedSourceMethod.ContainingType, thisParameter: _thisParameter, method: this, methodOrdinal: _methodOrdinal, closureDebugInfoBuilder: closureDebugInfoBuilder, lambdaDebugInfoBuilder: lambdaDebugInfoBuilder, slotAllocatorOpt: null, compilationState: compilationState, diagnostics: diagnostics, assignLocals: true); // we don't need this information: closureDebugInfoBuilder.Free(); lambdaDebugInfoBuilder.Free(); } // Insert locals from the original method, // followed by any new locals. var block = (BoundBlock)body; var localBuilder = ArrayBuilder<LocalSymbol>.GetInstance(); foreach (var local in this.Locals) { Debug.Assert(!(local is EELocalSymbol) || (((EELocalSymbol)local).Ordinal == localBuilder.Count)); localBuilder.Add(local); } foreach (var local in block.Locals) { var oldLocal = local as EELocalSymbol; if (oldLocal != null) { Debug.Assert(localBuilder[oldLocal.Ordinal] == oldLocal); continue; } localBuilder.Add(local); } body = block.Update(localBuilder.ToImmutableAndFree(), block.Statements); TypeParameterChecker.Check(body, _allTypeParameters); compilationState.AddSynthesizedMethod(this, body); }
/// <summary> /// Generates bound block representing method's body for methods in lowered form and adds it to /// a collection of method bodies of the current module. This method is supposed to only be /// called for method symbols which return SynthesizesLoweredBoundBody == true. /// </summary> internal virtual void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { throw ExceptionUtilities.Unreachable; }
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)); }
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.TypeSymbol), manager.System_Object__ToString), null, id: i, type: manager.System_String), Conversion.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.TypeSymbol), 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) + 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. 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 + 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; 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))); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { GenerateMethodBodyCore(compilationState, diagnostics); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { var F = new SyntheticBoundNodeFactory(this, ContainingType.GetNonNullSyntaxNode(), compilationState, diagnostics); try { ImmutableArray <Symbol> printableMembers = ContainingType.GetMembers().WhereAsArray(m => isPrintable(m)); if (ReturnType.IsErrorType() || printableMembers.Any(m => m.GetTypeOrReturnType().Type.IsErrorType())) { F.CloseMethod(F.ThrowNull()); return; } ArrayBuilder <BoundStatement> block; BoundParameter builder = F.Parameter(this.Parameters[0]); if (ContainingType.BaseTypeNoUseSiteDiagnostics.IsObjectType() || ContainingType.IsRecordStruct) { if (printableMembers.IsEmpty) { // return false; F.CloseMethod(F.Return(F.Literal(false))); return; } block = ArrayBuilder <BoundStatement> .GetInstance(); if (!ContainingType.IsRecordStruct) { var ensureStackMethod = F.WellKnownMethod( WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__EnsureSufficientExecutionStack, isOptional: true); if (ensureStackMethod is not null) { block.Add(F.ExpressionStatement( F.Call(receiver: null, ensureStackMethod))); } } } else { MethodSymbol?basePrintMethod = OverriddenMethod; if (basePrintMethod is null || basePrintMethod.ReturnType.SpecialType != SpecialType.System_Boolean) { F.CloseMethod(F.ThrowNull()); // an error was reported in base checks already return; } var basePrintCall = F.Call(receiver: F.Base(ContainingType.BaseTypeNoUseSiteDiagnostics), basePrintMethod, builder); if (printableMembers.IsEmpty) { // return base.PrintMembers(builder); F.CloseMethod(F.Return(basePrintCall)); return; } else { block = ArrayBuilder <BoundStatement> .GetInstance(); // if (base.PrintMembers(builder)) // builder.Append(", ") block.Add(F.If(basePrintCall, makeAppendString(F, builder, ", "))); } } Debug.Assert(!printableMembers.IsEmpty); for (var i = 0; i < printableMembers.Length; i++) { // builder.Append(", <name> = "); // if previous members exist // builder.Append("<name> = "); // if it is the first member // The only printable members are fields and properties, // which cannot be generic so as to have variant names var member = printableMembers[i]; var memberHeader = $"{member.Name} = "; if (i > 0) { memberHeader = ", " + memberHeader; } block.Add(makeAppendString(F, builder, memberHeader)); var value = member.Kind switch { SymbolKind.Field => F.Field(F.This(), (FieldSymbol)member), SymbolKind.Property => F.Property(F.This(), (PropertySymbol)member), _ => throw ExceptionUtilities.UnexpectedValue(member.Kind) }; // builder.Append((object)<value>); OR builder.Append(<value>.ToString()); for value types Debug.Assert(value.Type is not null); if (value.Type.IsValueType) { block.Add(F.ExpressionStatement( F.Call(receiver: builder, F.WellKnownMethod(WellKnownMember.System_Text_StringBuilder__AppendString), F.Call(value, F.SpecialMethod(SpecialMember.System_Object__ToString))))); } else { block.Add(F.ExpressionStatement( F.Call(receiver: builder, F.WellKnownMethod(WellKnownMember.System_Text_StringBuilder__AppendObject), F.Convert(F.SpecialType(SpecialType.System_Object), value)))); } } block.Add(F.Return(F.Literal(true))); F.CloseMethod(F.Block(block.ToImmutableAndFree())); } 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.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) { 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 { 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.Call(receiver: null, F.WellKnownMethod(WellKnownMember.System_Type__op_Equality), F.Property(F.This(), _equalityContract), F.Property(other, _equalityContract)); retExpr = retExpr is null ? (BoundExpression)contractsEqual : F.LogicalAnd(retExpr, contractsEqual); } else { if (_otherEqualsMethod.ReturnType.SpecialType != SpecialType.System_Boolean) { // There was a problem with overriding, an error was reported elsewhere F.CloseMethod(F.ThrowNull()); return; } // 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))); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); F.CloseMethod(F.ThrowNull()); } }
internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { ImmutableArray <LocalSymbol> declaredLocalsArray; var body = _generateMethodBody(this, diagnostics.DiagnosticBag, out declaredLocalsArray, out _lazyResultProperties); var compilation = compilationState.Compilation; _lazyReturnType = TypeWithAnnotations.Create(CalculateReturnType(compilation, body)); // Can't do this until the return type has been computed. TypeParameterChecker.Check(this, _allTypeParameters); if (diagnostics.HasAnyErrors()) { return; } DiagnosticsPass.IssueDiagnostics(compilation, body, diagnostics, this); if (diagnostics.HasAnyErrors()) { return; } // Check for use-site diagnostics (e.g. missing types in the signature). UseSiteInfo <AssemblySymbol> useSiteInfo = default; this.CalculateUseSiteDiagnostic(ref useSiteInfo); if (useSiteInfo.DiagnosticInfo != null && useSiteInfo.DiagnosticInfo.Severity == DiagnosticSeverity.Error) { diagnostics.Add(useSiteInfo.DiagnosticInfo, this.Locations[0]); return; } try { var declaredLocals = PooledHashSet <LocalSymbol> .GetInstance(); try { // Rewrite local declaration statement. body = (BoundStatement)LocalDeclarationRewriter.Rewrite( compilation, _container, declaredLocals, body, declaredLocalsArray, diagnostics.DiagnosticBag); // Verify local declaration names. foreach (var local in declaredLocals) { Debug.Assert(local.Locations.Length > 0); var name = local.Name; if (name.StartsWith("$", StringComparison.Ordinal)) { diagnostics.Add(ErrorCode.ERR_UnexpectedCharacter, local.Locations[0], name[0]); return; } } // Rewrite references to placeholder "locals". body = (BoundStatement)PlaceholderLocalRewriter.Rewrite(compilation, _container, declaredLocals, body, diagnostics.DiagnosticBag); if (diagnostics.HasAnyErrors()) { return; } } finally { declaredLocals.Free(); } var syntax = body.Syntax; var statementsBuilder = ArrayBuilder <BoundStatement> .GetInstance(); statementsBuilder.Add(body); // Insert an implicit return statement if necessary. if (body.Kind != BoundKind.ReturnStatement) { statementsBuilder.Add(new BoundReturnStatement(syntax, RefKind.None, expressionOpt: null, @checked: false)); } var localsSet = PooledHashSet <LocalSymbol> .GetInstance(); try { var localsBuilder = ArrayBuilder <LocalSymbol> .GetInstance(); foreach (var local in this.LocalsForBinding) { Debug.Assert(!localsSet.Contains(local)); localsBuilder.Add(local); localsSet.Add(local); } foreach (var local in this.Locals) { if (localsSet.Add(local)) { localsBuilder.Add(local); } } body = new BoundBlock(syntax, localsBuilder.ToImmutableAndFree(), statementsBuilder.ToImmutableAndFree()) { WasCompilerGenerated = true }; Debug.Assert(!diagnostics.HasAnyErrors()); Debug.Assert(!body.HasErrors); bool sawLambdas; bool sawLocalFunctions; bool sawAwaitInExceptionHandler; ImmutableArray <SourceSpan> dynamicAnalysisSpans = ImmutableArray <SourceSpan> .Empty; body = LocalRewriter.Rewrite( compilation: this.DeclaringCompilation, method: this, methodOrdinal: _methodOrdinal, containingType: _container, statement: body, compilationState: compilationState, previousSubmissionFields: null, allowOmissionOfConditionalCalls: false, instrumentForDynamicAnalysis: false, debugDocumentProvider: null, dynamicAnalysisSpans: ref dynamicAnalysisSpans, diagnostics: diagnostics, sawLambdas: out sawLambdas, sawLocalFunctions: out sawLocalFunctions, sawAwaitInExceptionHandler: out sawAwaitInExceptionHandler); Debug.Assert(!sawAwaitInExceptionHandler); Debug.Assert(dynamicAnalysisSpans.Length == 0); if (body.HasErrors) { return; } // Variables may have been captured by lambdas in the original method // or in the expression, and we need to preserve the existing values of // those variables in the expression. This requires rewriting the variables // in the expression based on the closure classes from both the original // method and the expression, and generating a preamble that copies // values into the expression closure classes. // // Consider the original method: // static void M() // { // int x, y, z; // ... // F(() => x + y); // } // and the expression in the EE: "F(() => x + z)". // // The expression is first rewritten using the closure class and local <1> // from the original method: F(() => <1>.x + z) // Then lambda rewriting introduces a new closure class that includes // the locals <1> and z, and a corresponding local <2>: F(() => <2>.<1>.x + <2>.z) // And a preamble is added to initialize the fields of <2>: // <2> = new <>c__DisplayClass0(); // <2>.<1> = <1>; // <2>.z = z; // Rewrite "this" and "base" references to parameter in this method. // Rewrite variables within body to reference existing display classes. body = (BoundStatement)CapturedVariableRewriter.Rewrite( this.GenerateThisReference, compilation.Conversions, _displayClassVariables, body, diagnostics.DiagnosticBag); if (body.HasErrors) { Debug.Assert(false, "Please add a test case capturing whatever caused this assert."); return; } if (diagnostics.HasAnyErrors()) { return; } if (sawLambdas || sawLocalFunctions) { var closureDebugInfoBuilder = ArrayBuilder <ClosureDebugInfo> .GetInstance(); var lambdaDebugInfoBuilder = ArrayBuilder <LambdaDebugInfo> .GetInstance(); body = ClosureConversion.Rewrite( loweredBody: body, thisType: this.SubstitutedSourceMethod.ContainingType, thisParameter: _thisParameter, method: this, methodOrdinal: _methodOrdinal, substitutedSourceMethod: this.SubstitutedSourceMethod.OriginalDefinition, closureDebugInfoBuilder: closureDebugInfoBuilder, lambdaDebugInfoBuilder: lambdaDebugInfoBuilder, slotAllocatorOpt: null, compilationState: compilationState, diagnostics: diagnostics, assignLocals: localsSet); // we don't need this information: closureDebugInfoBuilder.Free(); lambdaDebugInfoBuilder.Free(); } } finally { localsSet.Free(); } // Insert locals from the original method, // followed by any new locals. var block = (BoundBlock)body; var localBuilder = ArrayBuilder <LocalSymbol> .GetInstance(); foreach (var local in this.Locals) { Debug.Assert(!(local is EELocalSymbol) || (((EELocalSymbol)local).Ordinal == localBuilder.Count)); localBuilder.Add(local); } foreach (var local in block.Locals) { if (local is EELocalSymbol oldLocal) { Debug.Assert(localBuilder[oldLocal.Ordinal] == oldLocal); continue; } localBuilder.Add(local); } body = block.Update(localBuilder.ToImmutableAndFree(), block.LocalFunctions, block.Statements); TypeParameterChecker.Check(body, _allTypeParameters); compilationState.AddSynthesizedMethod(this, body); } catch (BoundTreeVisitor.CancelledByStackGuardException ex) { ex.AddAnError(diagnostics); } }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentMethod = this; try { LocalSymbol i = F.SynthesizedLocal(F.SpecialType(SpecialType.System_Int32)); LocalSymbol hashCode = F.SynthesizedLocal(F.SpecialType(SpecialType.System_UInt32)); LabelSymbol again = F.GenerateLabel("again"); LabelSymbol start = F.GenerateLabel("start"); ParameterSymbol text = this.Parameters[0]; // This method should be kept consistent with ComputeStringHash //uint hashCode = 0; //if (text != null) //{ // hashCode = unchecked((uint)2166136261); // int i = 0; // goto start; //again: // hashCode = (text[i] ^ hashCode) * 16777619; // i = i + 1; //start: // if (i < text.Length) // goto again; //} //return hashCode; var body = F.Block( ImmutableArray.Create <LocalSymbol>(hashCode, i), F.If( F.Binary(BinaryOperatorKind.ObjectNotEqual, F.SpecialType(SpecialType.System_Boolean), F.Parameter(text), F.Null(text.Type)), F.Block( F.Assignment(F.Local(hashCode), F.Literal((uint)2166136261)), F.Assignment(F.Local(i), F.Literal(0)), F.Goto(start), F.Label(again), F.Assignment( F.Local(hashCode), F.Binary(BinaryOperatorKind.Multiplication, hashCode.Type, F.Binary(BinaryOperatorKind.Xor, hashCode.Type, F.Convert(hashCode.Type, F.Call( F.Parameter(text), F.SpecialMethod(SpecialMember.System_String__Chars), F.Local(i)), ConversionKind.ImplicitNumeric), F.Local(hashCode)), F.Literal(16777619))), F.Assignment( F.Local(i), F.Binary(BinaryOperatorKind.Addition, i.Type, F.Local(i), F.Literal(1))), F.Label(start), F.If( F.Binary(BinaryOperatorKind.LessThan, F.SpecialType(SpecialType.System_Boolean), F.Local(i), F.Call(F.Parameter(text), F.SpecialMethod(SpecialMember.System_String__Length))), F.Goto(again)))), F.Return(F.Local(hashCode)) ); // NOTE: we created this block in its most-lowered form, so analysis is unnecessary F.CloseMethod(body); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); F.CloseMethod(F.ThrowNull()); } }
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> /// Note: this method captures diagnostics into the containing type (an injected attribute symbol) instead, /// as we don't yet know if the containing type will be emitted. /// </summary> internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { var containingType = (InjectedEmbeddedAttributeSymbol)ContainingType; GenerateMethodBodyCore(compilationState, containingType._diagnostics); }
internal override void GenerateMethodBody( TypeCompilationState compilationState, BindingDiagnosticBag diagnostics ) { // Method body: // // { // Object..ctor(); // this.backingField_1 = arg1; // ... // this.backingField_N = argN; // } SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory( compilationState, diagnostics ); int paramCount = this.ParameterCount; // List of statements BoundStatement[] statements = new BoundStatement[paramCount + 2]; int statementIndex = 0; // explicit base constructor call Debug.Assert( ContainingType.BaseTypeNoUseSiteDiagnostics.SpecialType == SpecialType.System_Object ); BoundExpression call = MethodCompiler.GenerateBaseParameterlessConstructorInitializer( this, diagnostics ); if (call == null) { // This may happen if Object..ctor is not found or is inaccessible return; } statements[statementIndex++] = F.ExpressionStatement(call); if (paramCount > 0) { AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType; Debug.Assert(anonymousType.Properties.Length == paramCount); // Assign fields for (int index = 0; index < this.ParameterCount; index++) { // Generate 'field' = 'parameter' statement statements[statementIndex++] = F.Assignment( F.Field(F.This(), anonymousType.Properties[index].BackingField), F.Parameter(_parameters[index]) ); } } // Final return statement statements[statementIndex++] = F.Return(); // Create a bound block F.CloseMethod(F.Block(statements)); }
internal override void GenerateMethodBody( TypeCompilationState compilationState, BindingDiagnosticBag diagnostics ) { CSharpSyntaxNode syntax = this.GetNonNullSyntaxNode(); SyntheticBoundNodeFactory factory = new SyntheticBoundNodeFactory( this, syntax, compilationState, diagnostics ); factory.CurrentFunction = this; ArrayBuilder <BoundStatement> body = ArrayBuilder <BoundStatement> .GetInstance(); // Initialize the payload root for each kind of dynamic analysis instrumentation. // A payload root is an array of arrays of per-method instrumentation payloads. // For each kind of instrumentation: // // payloadRoot = new T[MaximumMethodDefIndex + 1][]; // // where T is the type of the payload at each instrumentation point, and MaximumMethodDefIndex is the // index portion of the greatest method definition token in the compilation. This guarantees that any // method can use the index portion of its own method definition token as an index into the payload array. try { foreach ( KeyValuePair < int, InstrumentationPayloadRootField > payloadRoot in ContainingPrivateImplementationDetailsType.GetInstrumentationPayloadRoots() ) { int analysisKind = payloadRoot.Key; ArrayTypeSymbol payloadArrayType = (ArrayTypeSymbol)payloadRoot.Value.Type.GetInternalSymbol(); BoundStatement payloadInitialization = factory.Assignment( factory.InstrumentationPayloadRoot(analysisKind, payloadArrayType), factory.Array( payloadArrayType.ElementType, factory.Binary( BinaryOperatorKind.Addition, factory.SpecialType(SpecialType.System_Int32), factory.MaximumMethodDefIndex(), factory.Literal(1) ) ) ); body.Add(payloadInitialization); } // Initialize the module version ID (MVID) field. Dynamic instrumentation requires the MVID of the executing module, and this field makes that accessible. // MVID = new Guid(ModuleVersionIdString); body.Add( factory.Assignment( factory.ModuleVersionId(), factory.New( factory.WellKnownMethod(WellKnownMember.System_Guid__ctor), factory.ModuleVersionIdString() ) ) ); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember missing) { diagnostics.Add(missing.Diagnostic); } BoundStatement returnStatement = factory.Return(); body.Add(returnStatement); factory.CloseMethod(factory.Block(body.ToImmutableAndFree())); }
/// <remarks> /// This method should be kept consistent with <see cref="SynthesizedStringSwitchHashMethod.ComputeStringHash"/> /// </remarks> internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentFunction = this; try { ParameterSymbol text = this.Parameters[0]; NamedTypeSymbol spanChar = F.WellKnownType(_isReadOnlySpan ? WellKnownType.System_ReadOnlySpan_T : WellKnownType.System_Span_T) .Construct(F.SpecialType(SpecialType.System_Char)); LocalSymbol i = F.SynthesizedLocal(F.SpecialType(SpecialType.System_Int32)); LocalSymbol hashCode = F.SynthesizedLocal(F.SpecialType(SpecialType.System_UInt32)); LabelSymbol again = F.GenerateLabel("again"); LabelSymbol start = F.GenerateLabel("start"); // uint hashCode = unchecked((uint)2166136261); // int i = 0; // goto start; //again: // hashCode = (text[i] ^ hashCode) * 16777619; // i = i + 1; //start: // if (i < text.Length) // goto again; // return hashCode; var body = F.Block( ImmutableArray.Create <LocalSymbol>(hashCode, i), F.Assignment(F.Local(hashCode), F.Literal((uint)2166136261)), F.Assignment(F.Local(i), F.Literal(0)), F.Goto(start), F.Label(again), F.Assignment( F.Local(hashCode), F.Binary(BinaryOperatorKind.Multiplication, hashCode.Type, F.Binary(BinaryOperatorKind.Xor, hashCode.Type, F.Convert(hashCode.Type, F.Call( F.Parameter(text), F.WellKnownMethod(_isReadOnlySpan ? WellKnownMember.System_ReadOnlySpan_T__get_Item : WellKnownMember.System_Span_T__get_Item).AsMember(spanChar), F.Local(i)), Conversion.ImplicitNumeric), F.Local(hashCode)), F.Literal(16777619))), F.Assignment( F.Local(i), F.Binary(BinaryOperatorKind.Addition, i.Type, F.Local(i), F.Literal(1))), F.Label(start), F.If( F.Binary(BinaryOperatorKind.LessThan, F.SpecialType(SpecialType.System_Boolean), F.Local(i), F.Call( F.Parameter(text), F.WellKnownMethod(_isReadOnlySpan ? WellKnownMember.System_ReadOnlySpan_T__get_Length : WellKnownMember.System_Span_T__get_Length).AsMember(spanChar))), F.Goto(again)), F.Return(F.Local(hashCode)) ); // NOTE: we created this block in its most-lowered form, so analysis is unnecessary F.CloseMethod(body); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); F.CloseMethod(F.ThrowNull()); } }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentMethod = this; try { LocalSymbol i = F.SynthesizedLocal(F.SpecialType(SpecialType.System_Int32)); LocalSymbol hashCode = F.SynthesizedLocal(F.SpecialType(SpecialType.System_UInt32)); LabelSymbol again = F.GenerateLabel("again"); LabelSymbol start = F.GenerateLabel("start"); ParameterSymbol text = this.Parameters[0]; // This method should be kept consistent with ComputeStringHash //uint hashCode = 0; //if (text != null) //{ // hashCode = unchecked((uint)2166136261); // int i = 0; // goto start; //again: // hashCode = (text[i] ^ hashCode) * 16777619; // i = i + 1; //start: // if (i < text.Length) // goto again; //} //return hashCode; var body = F.Block( ImmutableArray.Create<LocalSymbol>(hashCode, i), F.If( F.Binary(BinaryOperatorKind.ObjectNotEqual, F.SpecialType(SpecialType.System_Boolean), F.Parameter(text), F.Null(text.Type)), F.Block( F.Assignment(F.Local(hashCode), F.Literal((uint)2166136261)), F.Assignment(F.Local(i), F.Literal(0)), F.Goto(start), F.Label(again), F.Assignment( F.Local(hashCode), F.Binary(BinaryOperatorKind.Multiplication, hashCode.Type, F.Binary(BinaryOperatorKind.Xor, hashCode.Type, F.Convert(hashCode.Type, F.Call( F.Parameter(text), F.SpecialMethod(SpecialMember.System_String__Chars), F.Local(i)), ConversionKind.ImplicitNumeric), F.Local(hashCode)), F.Literal(16777619))), F.Assignment( F.Local(i), F.Binary(BinaryOperatorKind.Addition, i.Type, F.Local(i), F.Literal(1))), F.Label(start), F.If( F.Binary(BinaryOperatorKind.LessThan, F.SpecialType(SpecialType.System_Boolean), F.Local(i), F.Call(F.Parameter(text), F.SpecialMethod(SpecialMember.System_String__Length))), F.Goto(again)))), F.Return(F.Local(hashCode)) ); // NOTE: we created this block in its most-lowered form, so analysis is unnecessary F.CloseMethod(body); } 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, 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. bool isRecordStruct = ContainingType.IsRecordStruct; if (isRecordStruct) { // We'll produce: // bool Equals(T other) => // field1 == other.field1 && ... && fieldN == other.fieldN; // or simply true if no fields. retExpr = 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 || !_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) => // (object)other == this || (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); } else if (retExpr is null) { retExpr = F.Literal(true); } fields.Free(); if (!isRecordStruct) { retExpr = F.LogicalOr(F.ObjectEqual(F.This(), other), retExpr); } 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 ) { 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 ) ); }
/// <summary> /// Given a SynthesizedExplicitImplementationMethod (effectively a tuple (interface method, implementing method, implementing type)), /// construct a BoundBlock body. Consider the tuple (Interface.Foo, Base.Foo, Derived). The generated method will look like: /// /// R Interface.Foo<T1, T2, ...>(A1 a1, A2 a2, ...) /// { /// //don't return the output if the return type is void /// return this.Foo<T1, T2, ...>(a1, a2, ...); /// } /// </summary> internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentMethod = (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 concept = ImplementingMethod.ContainingType; var conceptLoc = concept.Locations.IsEmpty ? Location.None : concept.Locations[0]; // TODO: wrong location? Debug.Assert(concept.IsConcept, "Tried to synthesise default struct implementation on a non-concept interface"); var instance = ContainingType; var instanceLoc = instance.Locations.IsEmpty ? Location.None : instance.Locations[0]; // TODO: wrong location? Debug.Assert(instance.IsInstance, "Tried to synthesise default struct implementation for a non-instance"); SyntheticBoundNodeFactory F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); F.CurrentMethod = OriginalDefinition; try { // Now try to find the default struct using the instance's scope... var binder = new BinderFactory(compilationState.Compilation, instance.GetNonNullSyntaxNode().SyntaxTree).GetBinder(instance.GetNonNullSyntaxNode()); var ignore = new HashSet <DiagnosticInfo>(); var defs = concept.GetDefaultStruct(binder, false, ref ignore); if (defs == null) { diagnostics.Add(ErrorCode.ERR_ConceptMethodNotImplementedAndNoDefault, instanceLoc, instance.Name, concept.Name, ImplementingMethod.ToDisplayString()); F.CloseMethod(F.ThrowNull()); return; } // Suppose the target concept is Foo<A, B>. // Then, the default must take type parameters <A, B, FooAB>, // where FooAB : Foo<A, B>. Thus, the arity is one higher than // the concept. if (defs.Arity != concept.Arity + 1) { // Don't use the default struct's location: it is an // implementation detail and may not actually exist. diagnostics.Add(ErrorCode.ERR_DefaultStructBadArity, conceptLoc, concept.Name, defs.Arity, concept.Arity + 1); F.CloseMethod(F.ThrowNull()); return; } // Due to above, arity must be at least 1. var witnessPar = defs.TypeParameters[defs.Arity - 1]; if (!witnessPar.IsConceptWitness) { diagnostics.Add(ErrorCode.ERR_DefaultStructNoWitnessParam, conceptLoc, concept.Name); F.CloseMethod(F.ThrowNull()); return; } var newTypeArguments = GenerateDefaultTypeArguments(); Debug.Assert(newTypeArguments.Length == concept.TypeArguments.Length + 1, "Conversion from concept type parameters to default struct lost or gained some entries."); // Now make the receiver for the call. As usual, it's a default(). var recvType = new ConstructedNamedTypeSymbol(defs, newTypeArguments); var receiver = F.Default(recvType); var arguments = GenerateInnerCallArguments(F); Debug.Assert(arguments.Length == ImplementingMethod.Parameters.Length, "Conversion from parameters to arguments lost or gained some entries."); var call = F.MakeInvocationExpression(BinderFlags.None, F.Syntax, receiver, ImplementingMethod.Name, arguments, diagnostics, ImplementingMethod.TypeArguments); if (call.HasErrors) { F.CloseMethod(F.ThrowNull()); return; } // If whichever call we end up making returns void, then we // can't just return its result; instead, we have to do the // call on its own _then_ return. BoundBlock block; if (call.Type.SpecialType == SpecialType.System_Void) { block = F.Block(F.ExpressionStatement(call), F.Return()); } else { block = F.Block(F.Return(call)); } F.CloseMethod(block); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); F.CloseMethod(F.ThrowNull()); } }
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.Array(manager.System_Object, arguments)); } else { // this is an empty anonymous type, just return "{ }" retExpression = F.Literal("{ }"); } F.CloseMethod(F.Block(F.Return(retExpression))); }
/// <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.CurrentMethod = (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()); } }
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)); }
/// <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.CurrentMethod = 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); } }