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));
            }
Beispiel #10
0
        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;
        }
Beispiel #11
0
        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);
 }
Beispiel #16
0
        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);
        }
Beispiel #17
0
 /// <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());
            }
Beispiel #23
0
        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());
            }
Beispiel #24
0
        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());
            }
        }
Beispiel #25
0
        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));
            }
Beispiel #30
0
        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 abstract override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag 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, 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&lt;T1, T2, ...&gt;(A1 a1, A2 a2, ...)
        /// {
        ///     //don't return the output if the return type is void
        ///     return this.Foo&lt;T1, T2, ...&gt;(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);
                }
            }