예제 #1
0
        private static void SetScriptInitializerReturnType(
            CSharpCompilation compilation,
            SynthesizedInteractiveInitializerMethod scriptInitializer,
            ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> fieldInitializers,
            DiagnosticBag diagnostics)
        {
            bool isAsync = scriptInitializer.IsSubmissionInitializer && fieldInitializers.Any(i => i.Any(ContainsAwaitsVisitor.ContainsAwait));
            var resultType = scriptInitializer.ResultType;
            TypeSymbol returnType;

            if ((object)resultType == null)
            {
                Debug.Assert(!isAsync);
                returnType = compilation.GetSpecialType(SpecialType.System_Void);
            }
            else if (!isAsync)
            {
                returnType = resultType;
            }
            else
            {
                var taskT = compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T);
                var useSiteDiagnostic = taskT.GetUseSiteDiagnostic();
                if (useSiteDiagnostic != null)
                {
                    diagnostics.Add(useSiteDiagnostic, NoLocation.Singleton);
                }
                returnType = taskT.Construct(resultType);
            }

            scriptInitializer.SetReturnType(isAsync, returnType);
        }
        public static void GetDelegateArguments(CSharpSyntaxNode syntax, AnalyzedArguments analyzedArguments, ImmutableArray<ParameterSymbol> delegateParameters, CSharpCompilation compilation)
        {
            foreach (var p in delegateParameters)
            {
                ParameterSymbol parameter = p;

                // In ExpressionBinder::BindGrpConversion, the native compiler substitutes object in place of dynamic.  This is
                // necessary because conversions from expressions of type dynamic always succeed, whereas conversions from the
                // type generally fail (modulo identity conversions).  This is not reflected in the C# 4 spec, but will be
                // incorporated going forward.  See DevDiv #742345 for additional details.
                // NOTE: Dev11 does a deep substitution (e.g. C<C<C<dynamic>>> -> C<C<C<object>>>), but that seems redundant.
                if (parameter.Type.IsDynamic())
                {
                    // If we don't have System.Object, then we'll get an error type, which will cause overload resolution to fail, 
                    // which will cause some error to be reported.  That's sufficient (i.e. no need to specifically report its absence here).
                    parameter = new SignatureOnlyParameterSymbol(
                        compilation.GetSpecialType(SpecialType.System_Object), parameter.CustomModifiers, parameter.IsParams, parameter.RefKind);
                }

                analyzedArguments.Arguments.Add(new BoundParameter(syntax, parameter) { WasCompilerGenerated = true });
                analyzedArguments.RefKinds.Add(parameter.RefKind);
            }
        }
예제 #3
0
        internal static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuilt, bool hasDeclarationErrors, DiagnosticBag diagnostics, CancellationToken cancellationToken)
        {
            CSharpCompilationOptions options = compilation.Options;
            if (!options.OutputKind.IsApplication())
            {
                Debug.Assert(compilation.GetEntryPointAndDiagnostics(cancellationToken) == null);
                return compilation.IsSubmission
                    ? DefineScriptEntryPoint(compilation, moduleBeingBuilt, compilation.GetSubmissionReturnType(), hasDeclarationErrors, diagnostics)
                    : null;
            }

            Debug.Assert(!compilation.IsSubmission);
            Debug.Assert(options.OutputKind.IsApplication());

            CSharpCompilation.EntryPoint entryPoint = compilation.GetEntryPointAndDiagnostics(cancellationToken);
            Debug.Assert(entryPoint != null);
            Debug.Assert(!entryPoint.Diagnostics.IsDefault);

            diagnostics.AddRange(entryPoint.Diagnostics);

            if ((object)compilation.ScriptClass != null)
            {
                Debug.Assert((object)entryPoint.MethodSymbol == null);
                return DefineScriptEntryPoint(compilation, moduleBeingBuilt, compilation.GetSpecialType(SpecialType.System_Void), hasDeclarationErrors, diagnostics);
            }

            Debug.Assert((object)entryPoint.MethodSymbol != null || entryPoint.Diagnostics.HasAnyErrors() || !compilation.Options.Errors.IsDefaultOrEmpty);
            return entryPoint.MethodSymbol;
        }
        /// <summary>
        /// Generates a submission initialization part of a Script type constructor that represents an interactive submission.
        /// </summary>
        /// <remarks>
        /// The constructor takes a parameter of type Roslyn.Scripting.Session - the session reference.
        /// It adds the object being constructed into the session by calling Microsoft.CSharp.RuntimeHelpers.SessionHelpers.SetSubmission,
        /// and retrieves strongly typed references on all previous submission script classes whose members are referenced by this submission.
        /// The references are stored to fields of the submission (<paramref name="synthesizedFields"/>).
        /// </remarks>
        private static ImmutableArray<BoundStatement> MakeSubmissionInitialization(CSharpSyntaxNode syntax, MethodSymbol submissionConstructor, SynthesizedSubmissionFields synthesizedFields, CSharpCompilation compilation)
        {
            Debug.Assert(submissionConstructor.ParameterCount == 2);

            BoundStatement[] result = new BoundStatement[1 + synthesizedFields.Count];

            var sessionReference = new BoundParameter(syntax, submissionConstructor.Parameters[0]) { WasCompilerGenerated = true };
            var submissionGetter = (MethodSymbol)compilation.GetWellKnownTypeMember(
                WellKnownMember.Microsoft_CSharp_RuntimeHelpers_SessionHelpers__GetSubmission
            );
            var submissionAdder = (MethodSymbol)compilation.GetWellKnownTypeMember(
                WellKnownMember.Microsoft_CSharp_RuntimeHelpers_SessionHelpers__SetSubmission
            );

            // TODO: report missing adder/getter
            Debug.Assert((object)submissionAdder != null && (object)submissionGetter != null);

            var intType = compilation.GetSpecialType(SpecialType.System_Int32);
            var thisReference = new BoundThisReference(syntax, submissionConstructor.ContainingType) { WasCompilerGenerated = true };

            int i = 0;

            // hostObject = (THostObject)SessionHelpers.SetSubmission(<session>, <slot index>, this);
            var slotIndex = compilation.GetSubmissionSlotIndex();
            Debug.Assert(slotIndex >= 0);

            BoundExpression setSubmission = BoundCall.Synthesized(syntax,
                null,
                submissionAdder,
                sessionReference,
                new BoundLiteral(syntax, ConstantValue.Create(slotIndex), intType) { WasCompilerGenerated = true },
                thisReference
            );

            var hostObjectField = synthesizedFields.GetHostObjectField();
            if ((object)hostObjectField != null)
            {
                setSubmission = new BoundAssignmentOperator(syntax,
                    new BoundFieldAccess(syntax, thisReference, hostObjectField, ConstantValue.NotAvailable) { WasCompilerGenerated = true },
                    BoundConversion.Synthesized(syntax,
                        setSubmission,
                        Conversion.ExplicitReference,
                        false,
                        true,
                        ConstantValue.NotAvailable,
                        hostObjectField.Type
                    ),
                    hostObjectField.Type
                )
                { WasCompilerGenerated = true };
            }

            result[i++] = new BoundExpressionStatement(syntax, setSubmission) { WasCompilerGenerated = true };

            foreach (var field in synthesizedFields.FieldSymbols)
            {
                var targetScriptClass = (ImplicitNamedTypeSymbol)field.Type;
                var targetSubmissionId = targetScriptClass.DeclaringCompilation.GetSubmissionSlotIndex();
                Debug.Assert(targetSubmissionId >= 0);

                // this.<field> = (<FieldType>)SessionHelpers.GetSubmission(<session>, <i>);
                result[i++] =
                    new BoundExpressionStatement(syntax,
                        new BoundAssignmentOperator(syntax,
                            new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable) { WasCompilerGenerated = true },
                            BoundConversion.Synthesized(syntax,
                                BoundCall.Synthesized(syntax,
                                    null,
                                    submissionGetter,
                                    sessionReference,
                                    new BoundLiteral(syntax, ConstantValue.Create(targetSubmissionId), intType) { WasCompilerGenerated = true }),
                                Conversion.ExplicitReference,
                                false,
                                true,
                                ConstantValue.NotAvailable,
                                targetScriptClass
                            ),
                            targetScriptClass
                        )
                { WasCompilerGenerated = true })
                { WasCompilerGenerated = true };
            }

            Debug.Assert(i == result.Length);

            return result.AsImmutableOrNull();
        }
        /// <summary>
        /// Generate a thread-safe accessor for a regular field-like event.
        /// 
        /// DelegateType tmp0 = _event; //backing field
        /// DelegateType tmp1;
        /// DelegateType tmp2;
        /// do {
        ///     tmp1 = tmp0;
        ///     tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -=
        ///     tmp0 = Interlocked.CompareExchange&lt;DelegateType&gt;(ref _event, tmp2, tmp1);
        /// } while ((object)tmp0 != (object)tmp1);
        /// </summary>
        internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode;

            TypeSymbol delegateType = eventSymbol.Type;
            MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;
            ParameterSymbol thisParameter = accessor.ThisParameter;

            TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean);
            MethodSymbol updateMethod = (MethodSymbol)compilation.GetSpecialTypeMember(isAddMethod ? SpecialMember.System_Delegate__Combine : SpecialMember.System_Delegate__Remove);
            MethodSymbol compareExchangeMethod = GetConstructedCompareExchangeMethod(delegateType, compilation, accessor.Locations[0], diagnostics);

            if ((object)compareExchangeMethod == null)
            {
                return new BoundBlock(syntax,
                    locals: ImmutableArray<LocalSymbol>.Empty,
                    statements: ImmutableArray.Create<BoundStatement>(
                        new BoundReturnStatement(syntax,
                            expressionOpt: null)
                { WasCompilerGenerated = true }))
                { WasCompilerGenerated = true };
            }

            GeneratedLabelSymbol loopLabel = new GeneratedLabelSymbol("loop");

            const int numTemps = 3;

            LocalSymbol[] tmps = new LocalSymbol[numTemps];
            BoundLocal[] boundTmps = new BoundLocal[numTemps];

            for (int i = 0; i < numTemps; i++)
            {
                tmps[i] = new SynthesizedLocal(accessor, delegateType, SynthesizedLocalKind.LoweringTemp);
                boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType);
            }

            BoundThisReference fieldReceiver = eventSymbol.IsStatic ?
                null :
                new BoundThisReference(syntax, thisParameter.Type) { WasCompilerGenerated = true };

            BoundFieldAccess boundBackingField = new BoundFieldAccess(syntax,
                receiver: fieldReceiver,
                fieldSymbol: eventSymbol.AssociatedField,
                constantValueOpt: null)
            { WasCompilerGenerated = true };

            BoundParameter boundParameter = new BoundParameter(syntax,
                parameterSymbol: accessor.Parameters[0])
            { WasCompilerGenerated = true };

            // tmp0 = _event;
            BoundStatement tmp0Init = new BoundExpressionStatement(syntax,
                expression: new BoundAssignmentOperator(syntax,
                    left: boundTmps[0],
                    right: boundBackingField,
                    type: delegateType)
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true };

            // LOOP:
            BoundStatement loopStart = new BoundLabelStatement(syntax,
                label: loopLabel)
            { WasCompilerGenerated = true };

            // tmp1 = tmp0;
            BoundStatement tmp1Update = new BoundExpressionStatement(syntax,
                expression: new BoundAssignmentOperator(syntax,
                    left: boundTmps[1],
                    right: boundTmps[0],
                    type: delegateType)
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true };

            // (DelegateType)Delegate.Combine(tmp1, value)
            BoundExpression delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax,
                operand: BoundCall.Synthesized(syntax,
                    receiverOpt: null,
                    method: updateMethod,
                    arguments: ImmutableArray.Create<BoundExpression>(boundTmps[1], boundParameter)),
                kind: ConversionKind.ExplicitReference,
                type: delegateType);

            // tmp2 = (DelegateType)Delegate.Combine(tmp1, value);
            BoundStatement tmp2Update = new BoundExpressionStatement(syntax,
                expression: new BoundAssignmentOperator(syntax,
                    left: boundTmps[2],
                    right: delegateUpdate,
                    type: delegateType)
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true };

            // Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1)
            BoundExpression compareExchange = BoundCall.Synthesized(syntax,
                receiverOpt: null,
                method: compareExchangeMethod,
                arguments: ImmutableArray.Create<BoundExpression>(boundBackingField, boundTmps[2], boundTmps[1]));

            // tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1);
            BoundStatement tmp0Update = new BoundExpressionStatement(syntax,
                expression: new BoundAssignmentOperator(syntax,
                    left: boundTmps[0],
                    right: compareExchange,
                    type: delegateType)
            { WasCompilerGenerated = true })
            { WasCompilerGenerated = true };

            // tmp0 == tmp1 // i.e. exit when they are equal, jump to start otherwise
            BoundExpression loopExitCondition = new BoundBinaryOperator(syntax,
                operatorKind: BinaryOperatorKind.ObjectEqual,
                left: boundTmps[0],
                right: boundTmps[1],
                constantValueOpt: null,
                methodOpt: null,
                resultKind: LookupResultKind.Viable,
                type: boolType)
            { WasCompilerGenerated = true };
            
            // branchfalse (tmp0 == tmp1) LOOP
            BoundStatement loopEnd = new BoundConditionalGoto(syntax,
                condition: loopExitCondition,
                jumpIfTrue: false,
                label: loopLabel)
            { WasCompilerGenerated = true };

            BoundStatement @return = new BoundReturnStatement(syntax,
                expressionOpt: null)
            { WasCompilerGenerated = true };

            return new BoundBlock(syntax,
                locals: tmps.AsImmutable(),
                statements: ImmutableArray.Create<BoundStatement>(
                    tmp0Init,
                    loopStart,
                    tmp1Update,
                    tmp2Update,
                    tmp0Update,
                    loopEnd,
                    @return))
            { WasCompilerGenerated = true };

        }
예제 #6
0
        /// <summary>
        /// Generates a submission initialization part of a Script type constructor that represents an interactive submission.
        /// </summary>
        /// <remarks>
        /// The constructor takes a parameter of type Microsoft.CodeAnalysis.Scripting.Session - the session reference.
        /// It adds the object being constructed into the session by calling Microsoft.CSharp.RuntimeHelpers.SessionHelpers.SetSubmission,
        /// and retrieves strongly typed references on all previous submission script classes whose members are referenced by this submission.
        /// The references are stored to fields of the submission (<paramref name="synthesizedFields"/>).
        /// </remarks>
        private static void MakeSubmissionInitialization(
            ArrayBuilder<BoundStatement> statements,
            CSharpSyntaxNode syntax,
            MethodSymbol submissionConstructor,
            SynthesizedSubmissionFields synthesizedFields,
            CSharpCompilation compilation)
        {
            Debug.Assert(submissionConstructor.ParameterCount == 1);

            var submissionArrayReference = new BoundParameter(syntax, submissionConstructor.Parameters[0]) { WasCompilerGenerated = true };

            var intType = compilation.GetSpecialType(SpecialType.System_Int32);
            var objectType = compilation.GetSpecialType(SpecialType.System_Object);
            var thisReference = new BoundThisReference(syntax, submissionConstructor.ContainingType) { WasCompilerGenerated = true };

            var slotIndex = compilation.GetSubmissionSlotIndex();
            Debug.Assert(slotIndex >= 0);

            // <submission_array>[<slot_index] = this;
            statements.Add(new BoundExpressionStatement(syntax,
                new BoundAssignmentOperator(syntax,
                    new BoundArrayAccess(syntax,
                        submissionArrayReference,
                        ImmutableArray.Create<BoundExpression>(new BoundLiteral(syntax, ConstantValue.Create(slotIndex), intType) { WasCompilerGenerated = true }),
                        objectType)
                    { WasCompilerGenerated = true },
                    thisReference,
                    RefKind.None,
                    thisReference.Type)
                { WasCompilerGenerated = true })
            { WasCompilerGenerated = true });

            var hostObjectField = synthesizedFields.GetHostObjectField();
            if ((object)hostObjectField != null)
            {
                // <host_object> = (<host_object_type>)<submission_array>[0]
                statements.Add(
                    new BoundExpressionStatement(syntax,
                        new BoundAssignmentOperator(syntax,
                            new BoundFieldAccess(syntax, thisReference, hostObjectField, ConstantValue.NotAvailable) { WasCompilerGenerated = true },
                            BoundConversion.Synthesized(syntax,
                                new BoundArrayAccess(syntax,
                                    submissionArrayReference,
                                    ImmutableArray.Create<BoundExpression>(new BoundLiteral(syntax, ConstantValue.Create(0), intType) { WasCompilerGenerated = true }),
                                    objectType),
                                Conversion.ExplicitReference,
                                false,
                                true,
                                ConstantValue.NotAvailable,
                                hostObjectField.Type
                            ),
                            hostObjectField.Type)
                        { WasCompilerGenerated = true })
                    { WasCompilerGenerated = true });
            }

            foreach (var field in synthesizedFields.FieldSymbols)
            {
                var targetScriptType = (ImplicitNamedTypeSymbol)field.Type;
                var targetSubmissionIndex = targetScriptType.DeclaringCompilation.GetSubmissionSlotIndex();
                Debug.Assert(targetSubmissionIndex >= 0);

                // this.<field> = (<target_script_type>)<submission_array>[<target_submission_index>];
                statements.Add(
                    new BoundExpressionStatement(syntax,
                        new BoundAssignmentOperator(syntax,
                            new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable) { WasCompilerGenerated = true },
                            BoundConversion.Synthesized(syntax,
                                new BoundArrayAccess(syntax,
                                    submissionArrayReference,
                                    ImmutableArray.Create<BoundExpression>(new BoundLiteral(syntax, ConstantValue.Create(targetSubmissionIndex), intType) { WasCompilerGenerated = true }),
                                    objectType)
                                { WasCompilerGenerated = true },
                                Conversion.ExplicitReference,
                                false,
                                true,
                                ConstantValue.NotAvailable,
                                targetScriptType
                            ),
                            targetScriptType
                        )
                        { WasCompilerGenerated = true })
                    { WasCompilerGenerated = true });
            }
        }
예제 #7
0
        internal readonly TypeSymbol IteratorElementType; // only for async-iterators

        public AsyncStateMachine(VariableSlotAllocator variableAllocatorOpt, TypeCompilationState compilationState, MethodSymbol asyncMethod, int asyncMethodOrdinal, TypeKind typeKind)
            : base(variableAllocatorOpt, compilationState, asyncMethod, asyncMethodOrdinal)
        {
            _typeKind = typeKind;
            CSharpCompilation compilation = asyncMethod.DeclaringCompilation;
            var interfaces = ArrayBuilder <NamedTypeSymbol> .GetInstance();

            bool isIterator = asyncMethod.IsIterator;

            if (isIterator)
            {
                var elementType = TypeMap.SubstituteType(asyncMethod.IteratorElementType).TypeSymbol;
                this.IteratorElementType = elementType;

                bool isEnumerable = asyncMethod.IsIAsyncEnumerableReturningAsync(compilation);
                if (isEnumerable)
                {
                    // IAsyncEnumerable<TResult>
                    interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T).Construct(elementType));
                }

                // IAsyncEnumerator<TResult>
                interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerator_T).Construct(elementType));

                // IValueTaskSource<bool>
                interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Sources_IValueTaskSource_T).Construct(compilation.GetSpecialType(SpecialType.System_Boolean)));

                // IValueTaskSource
                interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Sources_IValueTaskSource));

                // IAsyncDisposable
                interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable));
            }

            interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IAsyncStateMachine));
            _interfaces = interfaces.ToImmutableAndFree();

            _constructor = isIterator ? (MethodSymbol) new IteratorConstructor(this) : new AsyncConstructor(this);
        }
예제 #8
0
        internal UnaryOperatorSignature GetSignature(UnaryOperatorKind kind)
        {
            TypeSymbol opType = null;

            if (kind.IsLifted())
            {
                var nullable = _compilation.GetSpecialType(SpecialType.System_Nullable_T);

                switch (kind.OperandTypes())
                {
                case UnaryOperatorKind.SByte: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_SByte)); break;

                case UnaryOperatorKind.Byte: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Byte)); break;

                case UnaryOperatorKind.Short: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Int16)); break;

                case UnaryOperatorKind.UShort: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_UInt16)); break;

                case UnaryOperatorKind.Int: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Int32)); break;

                case UnaryOperatorKind.UInt: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_UInt32)); break;

                case UnaryOperatorKind.Long: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Int64)); break;

                case UnaryOperatorKind.ULong: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_UInt64)); break;

                case UnaryOperatorKind.Char: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Char)); break;

                case UnaryOperatorKind.Float: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Single)); break;

                case UnaryOperatorKind.Double: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Double)); break;

                case UnaryOperatorKind.Decimal: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Decimal)); break;

                case UnaryOperatorKind.Bool: opType = nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Boolean)); break;
                }
            }
            else
            {
                switch (kind.OperandTypes())
                {
                case UnaryOperatorKind.SByte: opType = _compilation.GetSpecialType(SpecialType.System_SByte); break;

                case UnaryOperatorKind.Byte: opType = _compilation.GetSpecialType(SpecialType.System_Byte); break;

                case UnaryOperatorKind.Short: opType = _compilation.GetSpecialType(SpecialType.System_Int16); break;

                case UnaryOperatorKind.UShort: opType = _compilation.GetSpecialType(SpecialType.System_UInt16); break;

                case UnaryOperatorKind.Int: opType = _compilation.GetSpecialType(SpecialType.System_Int32); break;

                case UnaryOperatorKind.UInt: opType = _compilation.GetSpecialType(SpecialType.System_UInt32); break;

                case UnaryOperatorKind.Long: opType = _compilation.GetSpecialType(SpecialType.System_Int64); break;

                case UnaryOperatorKind.ULong: opType = _compilation.GetSpecialType(SpecialType.System_UInt64); break;

                case UnaryOperatorKind.Char: opType = _compilation.GetSpecialType(SpecialType.System_Char); break;

                case UnaryOperatorKind.Float: opType = _compilation.GetSpecialType(SpecialType.System_Single); break;

                case UnaryOperatorKind.Double: opType = _compilation.GetSpecialType(SpecialType.System_Double); break;

                case UnaryOperatorKind.Decimal: opType = _compilation.GetSpecialType(SpecialType.System_Decimal); break;

                case UnaryOperatorKind.Bool: opType = _compilation.GetSpecialType(SpecialType.System_Boolean); break;
                }
            }
            Debug.Assert((object)opType != null);
            return(new UnaryOperatorSignature(kind, opType, opType));
        }
예제 #9
0
        private static void MakeSubmissionInitialization(
            ArrayBuilder <BoundStatement> statements,
            SyntaxNode syntax,
            MethodSymbol submissionConstructor,
            SynthesizedSubmissionFields synthesizedFields,
            CSharpCompilation compilation)
        {
            Debug.Assert(submissionConstructor.ParameterCount == 1);

            var submissionArrayReference = new BoundParameter(syntax, submissionConstructor.Parameters[0])
            {
                WasCompilerGenerated = true
            };

            var intType       = compilation.GetSpecialType(SpecialType.System_Int32);
            var objectType    = compilation.GetSpecialType(SpecialType.System_Object);
            var thisReference = new BoundThisReference(syntax, submissionConstructor.ContainingType)
            {
                WasCompilerGenerated = true
            };

            var slotIndex = compilation.GetSubmissionSlotIndex();

            Debug.Assert(slotIndex >= 0);

            // <submission_array>[<slot_index] = this;
            statements.Add(new BoundExpressionStatement(syntax,
                                                        new BoundAssignmentOperator(syntax,
                                                                                    new BoundArrayAccess(syntax,
                                                                                                         submissionArrayReference,
                                                                                                         ImmutableArray.Create <BoundExpression>(new BoundLiteral(syntax, ConstantValue.Create(slotIndex), intType)
            {
                WasCompilerGenerated = true
            }),
                                                                                                         objectType)
            {
                WasCompilerGenerated = true
            },
                                                                                    thisReference,
                                                                                    false,
                                                                                    thisReference.Type)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            });

            var hostObjectField = synthesizedFields.GetHostObjectField();

            if ((object)hostObjectField != null)
            {
                // <host_object> = (<host_object_type>)<submission_array>[0]
                statements.Add(
                    new BoundExpressionStatement(syntax,
                                                 new BoundAssignmentOperator(syntax,
                                                                             new BoundFieldAccess(syntax, thisReference, hostObjectField, ConstantValue.NotAvailable)
                {
                    WasCompilerGenerated = true
                },
                                                                             BoundConversion.Synthesized(syntax,
                                                                                                         new BoundArrayAccess(syntax,
                                                                                                                              submissionArrayReference,
                                                                                                                              ImmutableArray.Create <BoundExpression>(new BoundLiteral(syntax, ConstantValue.Create(0), intType)
                {
                    WasCompilerGenerated = true
                }),
                                                                                                                              objectType),
                                                                                                         Conversion.ExplicitReference,
                                                                                                         false,
                                                                                                         explicitCastInCode: true,
                                                                                                         conversionGroupOpt: null,
                                                                                                         ConstantValue.NotAvailable,
                                                                                                         hostObjectField.Type
                                                                                                         ),
                                                                             hostObjectField.Type)
                {
                    WasCompilerGenerated = true
                })
                {
                    WasCompilerGenerated = true
                });
            }

            foreach (var field in synthesizedFields.FieldSymbols)
            {
                var targetScriptType      = (ImplicitNamedTypeSymbol)field.Type;
                var targetSubmissionIndex = targetScriptType.DeclaringCompilation.GetSubmissionSlotIndex();
                Debug.Assert(targetSubmissionIndex >= 0);

                // this.<field> = (<target_script_type>)<submission_array>[<target_submission_index>];
                statements.Add(
                    new BoundExpressionStatement(syntax,
                                                 new BoundAssignmentOperator(syntax,
                                                                             new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable)
                {
                    WasCompilerGenerated = true
                },
                                                                             BoundConversion.Synthesized(syntax,
                                                                                                         new BoundArrayAccess(syntax,
                                                                                                                              submissionArrayReference,
                                                                                                                              ImmutableArray.Create <BoundExpression>(new BoundLiteral(syntax, ConstantValue.Create(targetSubmissionIndex), intType)
                {
                    WasCompilerGenerated = true
                }),
                                                                                                                              objectType)
                {
                    WasCompilerGenerated = true
                },
                                                                                                         Conversion.ExplicitReference,
                                                                                                         false,
                                                                                                         explicitCastInCode: true,
                                                                                                         conversionGroupOpt: null,
                                                                                                         ConstantValue.NotAvailable,
                                                                                                         targetScriptType
                                                                                                         ),
                                                                             targetScriptType
                                                                             )
                {
                    WasCompilerGenerated = true
                })
                {
                    WasCompilerGenerated = true
                });
            }
        }
예제 #10
0
        internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, BindingDiagnosticBag diagnostics)
        {
            CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode;

            TypeSymbol      delegateType  = eventSymbol.Type;
            MethodSymbol    accessor      = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;
            ParameterSymbol thisParameter = accessor.ThisParameter;

            TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean);

            SpecialMember updateMethodId = isAddMethod ? SpecialMember.System_Delegate__Combine : SpecialMember.System_Delegate__Remove;
            MethodSymbol  updateMethod   = (MethodSymbol)compilation.GetSpecialTypeMember(updateMethodId);

            BoundStatement @return = new BoundReturnStatement(syntax,
                                                              refKind: RefKind.None,
                                                              expressionOpt: null,
                                                              @checked: false)
            {
                WasCompilerGenerated = true
            };

            if (updateMethod == null)
            {
                MemberDescriptor memberDescriptor = SpecialMembers.GetDescriptor(updateMethodId);
                diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(ErrorCode.ERR_MissingPredefinedMember,
                                                                      memberDescriptor.DeclaringTypeMetadataName,
                                                                      memberDescriptor.Name),
                                                 syntax.Location));

                return(BoundBlock.SynthesizedNoLocals(syntax, @return));
            }

            Binder.ReportUseSite(updateMethod, diagnostics, syntax);

            BoundThisReference fieldReceiver = eventSymbol.IsStatic ?
                                               null :
                                               new BoundThisReference(syntax, thisParameter.Type)
            {
                WasCompilerGenerated = true
            };

            BoundFieldAccess boundBackingField = new BoundFieldAccess(syntax,
                                                                      receiver: fieldReceiver,
                                                                      fieldSymbol: eventSymbol.AssociatedField,
                                                                      constantValueOpt: null)
            {
                WasCompilerGenerated = true
            };

            BoundParameter boundParameter = new BoundParameter(syntax,
                                                               parameterSymbol: accessor.Parameters[0])
            {
                WasCompilerGenerated = true
            };

            BoundExpression delegateUpdate;

            MethodSymbol compareExchangeMethod = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T);

            if ((object)compareExchangeMethod == null)
            {
                // (DelegateType)Delegate.Combine(_event, value)
                delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax,
                                                                           operand: BoundCall.Synthesized(syntax,
                                                                                                          receiverOpt: null,
                                                                                                          method: updateMethod,
                                                                                                          arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundParameter)),
                                                                           conversion: Conversion.ExplicitReference,
                                                                           type: delegateType);

                // _event = (DelegateType)Delegate.Combine(_event, value);
                BoundStatement eventUpdate = new BoundExpressionStatement(syntax,
                                                                          expression: new BoundAssignmentOperator(syntax,
                                                                                                                  left: boundBackingField,
                                                                                                                  right: delegateUpdate,
                                                                                                                  type: delegateType)
                {
                    WasCompilerGenerated = true
                })
                {
                    WasCompilerGenerated = true
                };

                return(BoundBlock.SynthesizedNoLocals(syntax,
                                                      statements: ImmutableArray.Create <BoundStatement>(
                                                          eventUpdate,
                                                          @return)));
            }

            compareExchangeMethod = compareExchangeMethod.Construct(ImmutableArray.Create <TypeSymbol>(delegateType));

            Binder.ReportUseSite(compareExchangeMethod, diagnostics, syntax);

            GeneratedLabelSymbol loopLabel = new GeneratedLabelSymbol("loop");

            const int numTemps = 3;

            LocalSymbol[] tmps      = new LocalSymbol[numTemps];
            BoundLocal[]  boundTmps = new BoundLocal[numTemps];

            for (int i = 0; i < numTemps; i++)
            {
                tmps[i]      = new SynthesizedLocal(accessor, TypeWithAnnotations.Create(delegateType), SynthesizedLocalKind.LoweringTemp);
                boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType)
                {
                    WasCompilerGenerated = true
                };
            }

            // tmp0 = _event;
            BoundStatement tmp0Init = new BoundExpressionStatement(syntax,
                                                                   expression: new BoundAssignmentOperator(syntax,
                                                                                                           left: boundTmps[0],
                                                                                                           right: boundBackingField,
                                                                                                           type: delegateType)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            };

            // LOOP:
            BoundStatement loopStart = new BoundLabelStatement(syntax,
                                                               label: loopLabel)
            {
                WasCompilerGenerated = true
            };

            // tmp1 = tmp0;
            BoundStatement tmp1Update = new BoundExpressionStatement(syntax,
                                                                     expression: new BoundAssignmentOperator(syntax,
                                                                                                             left: boundTmps[1],
                                                                                                             right: boundTmps[0],
                                                                                                             type: delegateType)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            };

            // (DelegateType)Delegate.Combine(tmp1, value)
            delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax,
                                                                       operand: BoundCall.Synthesized(syntax,
                                                                                                      receiverOpt: null,
                                                                                                      method: updateMethod,
                                                                                                      arguments: ImmutableArray.Create <BoundExpression>(boundTmps[1], boundParameter)),
                                                                       conversion: Conversion.ExplicitReference,
                                                                       type: delegateType);

            // tmp2 = (DelegateType)Delegate.Combine(tmp1, value);
            BoundStatement tmp2Update = new BoundExpressionStatement(syntax,
                                                                     expression: new BoundAssignmentOperator(syntax,
                                                                                                             left: boundTmps[2],
                                                                                                             right: delegateUpdate,
                                                                                                             type: delegateType)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            };

            // Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1)
            BoundExpression compareExchange = BoundCall.Synthesized(syntax,
                                                                    receiverOpt: null,
                                                                    method: compareExchangeMethod,
                                                                    arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundTmps[2], boundTmps[1]));

            // tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1);
            BoundStatement tmp0Update = new BoundExpressionStatement(syntax,
                                                                     expression: new BoundAssignmentOperator(syntax,
                                                                                                             left: boundTmps[0],
                                                                                                             right: compareExchange,
                                                                                                             type: delegateType)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            };

            // tmp0 == tmp1 // i.e. exit when they are equal, jump to start otherwise
            BoundExpression loopExitCondition = new BoundBinaryOperator(syntax,
                                                                        operatorKind: BinaryOperatorKind.ObjectEqual,
                                                                        left: boundTmps[0],
                                                                        right: boundTmps[1],
                                                                        constantValueOpt: null,
                                                                        methodOpt: null,
                                                                        constrainedToTypeOpt: null,
                                                                        resultKind: LookupResultKind.Viable,
                                                                        type: boolType)
            {
                WasCompilerGenerated = true
            };

            // branchfalse (tmp0 == tmp1) LOOP
            BoundStatement loopEnd = new BoundConditionalGoto(syntax,
                                                              condition: loopExitCondition,
                                                              jumpIfTrue: false,
                                                              label: loopLabel)
            {
                WasCompilerGenerated = true
            };

            return(new BoundBlock(syntax,
                                  locals: tmps.AsImmutable(),
                                  statements: ImmutableArray.Create <BoundStatement>(
                                      tmp0Init,
                                      loopStart,
                                      tmp1Update,
                                      tmp2Update,
                                      tmp0Update,
                                      loopEnd,
                                      @return))
            {
                WasCompilerGenerated = true
            });
        }
예제 #11
0
        internal UnaryOperatorSignature GetSignature(UnaryOperatorKind kind)
        {
            TypeSymbol opType;

            switch (kind.OperandTypes())
            {
            case UnaryOperatorKind.SByte: opType = _compilation.GetSpecialType(SpecialType.System_SByte); break;

            case UnaryOperatorKind.Byte: opType = _compilation.GetSpecialType(SpecialType.System_Byte); break;

            case UnaryOperatorKind.Short: opType = _compilation.GetSpecialType(SpecialType.System_Int16); break;

            case UnaryOperatorKind.UShort: opType = _compilation.GetSpecialType(SpecialType.System_UInt16); break;

            case UnaryOperatorKind.Int: opType = _compilation.GetSpecialType(SpecialType.System_Int32); break;

            case UnaryOperatorKind.UInt: opType = _compilation.GetSpecialType(SpecialType.System_UInt32); break;

            case UnaryOperatorKind.Long: opType = _compilation.GetSpecialType(SpecialType.System_Int64); break;

            case UnaryOperatorKind.ULong: opType = _compilation.GetSpecialType(SpecialType.System_UInt64); break;

            case UnaryOperatorKind.Char: opType = _compilation.GetSpecialType(SpecialType.System_Char); break;

            case UnaryOperatorKind.Float: opType = _compilation.GetSpecialType(SpecialType.System_Single); break;

            case UnaryOperatorKind.Double: opType = _compilation.GetSpecialType(SpecialType.System_Double); break;

            case UnaryOperatorKind.Decimal: opType = _compilation.GetSpecialType(SpecialType.System_Decimal); break;

            case UnaryOperatorKind.Bool: opType = _compilation.GetSpecialType(SpecialType.System_Boolean); break;

            default: throw ExceptionUtilities.UnexpectedValue(kind.OperandTypes());
            }

            if (kind.IsLifted())
            {
                opType = _compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(opType);
            }

            return(new UnaryOperatorSignature(kind, opType, opType));
        }
예제 #12
0
 internal DisposeCheckerPass(CSharpCompilation compilation, MethodSymbol method, BoundNode node)
     : base(compilation, method, node, trackExceptions: true)
 {
     this.IDisposableType = compilation.GetSpecialType(SpecialType.System_IDisposable);
 }
예제 #13
0
        /// <summary>
        /// Generates a submission initialization part of a Script type constructor that represents an interactive submission.
        /// </summary>
        /// <remarks>
        /// The constructor takes a parameter of type Roslyn.Scripting.Session - the session reference.
        /// It adds the object being constructed into the session by calling Microsoft.CSharp.RuntimeHelpers.SessionHelpers.SetSubmission,
        /// and retrieves strongly typed references on all previous submission script classes whose members are referenced by this submission.
        /// The references are stored to fields of the submission (<paramref name="synthesizedFields"/>).
        /// </remarks>
        private static ImmutableArray <BoundStatement> MakeSubmissionInitialization(CSharpSyntaxNode syntax, MethodSymbol submissionConstructor, SynthesizedSubmissionFields synthesizedFields, CSharpCompilation compilation)
        {
            Debug.Assert(submissionConstructor.ParameterCount == 2);

            BoundStatement[] result = new BoundStatement[1 + synthesizedFields.Count];

            var sessionReference = new BoundParameter(syntax, submissionConstructor.Parameters[0])
            {
                WasCompilerGenerated = true
            };
            var submissionGetter = (MethodSymbol)compilation.GetWellKnownTypeMember(
                WellKnownMember.Microsoft_CSharp_RuntimeHelpers_SessionHelpers__GetSubmission
                );
            var submissionAdder = (MethodSymbol)compilation.GetWellKnownTypeMember(
                WellKnownMember.Microsoft_CSharp_RuntimeHelpers_SessionHelpers__SetSubmission
                );

            // TODO: report missing adder/getter
            Debug.Assert((object)submissionAdder != null && (object)submissionGetter != null);

            var intType       = compilation.GetSpecialType(SpecialType.System_Int32);
            var thisReference = new BoundThisReference(syntax, submissionConstructor.ContainingType)
            {
                WasCompilerGenerated = true
            };

            int i = 0;

            // hostObject = (THostObject)SessionHelpers.SetSubmission(<session>, <slot index>, this);
            var slotIndex = compilation.GetSubmissionSlotIndex();

            Debug.Assert(slotIndex >= 0);

            BoundExpression setSubmission = BoundCall.Synthesized(syntax,
                                                                  null,
                                                                  submissionAdder,
                                                                  sessionReference,
                                                                  new BoundLiteral(syntax, ConstantValue.Create(slotIndex), intType)
            {
                WasCompilerGenerated = true
            },
                                                                  thisReference
                                                                  );

            var hostObjectField = synthesizedFields.GetHostObjectField();

            if ((object)hostObjectField != null)
            {
                setSubmission = new BoundAssignmentOperator(syntax,
                                                            new BoundFieldAccess(syntax, thisReference, hostObjectField, ConstantValue.NotAvailable)
                {
                    WasCompilerGenerated = true
                },
                                                            BoundConversion.Synthesized(syntax,
                                                                                        setSubmission,
                                                                                        Conversion.ExplicitReference,
                                                                                        false,
                                                                                        true,
                                                                                        ConstantValue.NotAvailable,
                                                                                        hostObjectField.Type
                                                                                        ),
                                                            hostObjectField.Type
                                                            )
                {
                    WasCompilerGenerated = true
                };
            }

            result[i++] = new BoundExpressionStatement(syntax, setSubmission)
            {
                WasCompilerGenerated = true
            };

            foreach (var field in synthesizedFields.FieldSymbols)
            {
                var targetScriptClass  = (ImplicitNamedTypeSymbol)field.Type;
                var targetSubmissionId = targetScriptClass.DeclaringCompilation.GetSubmissionSlotIndex();
                Debug.Assert(targetSubmissionId >= 0);

                // this.<field> = (<FieldType>)SessionHelpers.GetSubmission(<session>, <i>);
                result[i++] =
                    new BoundExpressionStatement(syntax,
                                                 new BoundAssignmentOperator(syntax,
                                                                             new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable)
                {
                    WasCompilerGenerated = true
                },
                                                                             BoundConversion.Synthesized(syntax,
                                                                                                         BoundCall.Synthesized(syntax,
                                                                                                                               null,
                                                                                                                               submissionGetter,
                                                                                                                               sessionReference,
                                                                                                                               new BoundLiteral(syntax, ConstantValue.Create(targetSubmissionId), intType)
                {
                    WasCompilerGenerated = true
                }),
                                                                                                         Conversion.ExplicitReference,
                                                                                                         false,
                                                                                                         true,
                                                                                                         ConstantValue.NotAvailable,
                                                                                                         targetScriptClass
                                                                                                         ),
                                                                             targetScriptClass
                                                                             )
                {
                    WasCompilerGenerated = true
                })
                {
                    WasCompilerGenerated = true
                };
            }

            Debug.Assert(i == result.Length);

            return(result.AsImmutableOrNull());
        }
예제 #14
0
        /// <summary>
        /// Generate a thread-safe accessor for a regular field-like event.
        ///
        /// DelegateType tmp0 = _event; //backing field
        /// DelegateType tmp1;
        /// DelegateType tmp2;
        /// do {
        ///     tmp1 = tmp0;
        ///     tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -=
        ///     tmp0 = Interlocked.CompareExchange&lt;DelegateType&gt;(ref _event, tmp2, tmp1);
        /// } while ((object)tmp0 != (object)tmp1);
        /// </summary>
        internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode;

            TypeSymbol      delegateType  = eventSymbol.Type;
            MethodSymbol    accessor      = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;
            ParameterSymbol thisParameter = accessor.ThisParameter;

            TypeSymbol   boolType              = compilation.GetSpecialType(SpecialType.System_Boolean);
            MethodSymbol updateMethod          = (MethodSymbol)compilation.GetSpecialTypeMember(isAddMethod ? SpecialMember.System_Delegate__Combine : SpecialMember.System_Delegate__Remove);
            MethodSymbol compareExchangeMethod = GetConstructedCompareExchangeMethod(delegateType, compilation, accessor.Locations[0], diagnostics);

            if ((object)compareExchangeMethod == null)
            {
                return(new BoundBlock(syntax,
                                      localsOpt: default(ImmutableArray <LocalSymbol>),
                                      statements: ImmutableArray.Create <BoundStatement>(
                                          new BoundReturnStatement(syntax,
                                                                   expressionOpt: null)
                {
                    WasCompilerGenerated = true
                }))
                {
                    WasCompilerGenerated = true
                });
            }

            GeneratedLabelSymbol loopLabel = new GeneratedLabelSymbol("loop");

            const int numTemps = 3;

            LocalSymbol[] tmps      = new LocalSymbol[numTemps];
            BoundLocal[]  boundTmps = new BoundLocal[numTemps];

            for (int i = 0; i < numTemps; i++)
            {
                tmps[i]      = new SynthesizedLocal(accessor, delegateType);
                boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType);
            }

            BoundThisReference fieldReceiver = eventSymbol.IsStatic ?
                                               null :
                                               new BoundThisReference(syntax, thisParameter.Type)
            {
                WasCompilerGenerated = true
            };

            BoundFieldAccess boundBackingField = new BoundFieldAccess(syntax,
                                                                      receiver: fieldReceiver,
                                                                      fieldSymbol: eventSymbol.AssociatedField,
                                                                      constantValueOpt: null)
            {
                WasCompilerGenerated = true
            };

            BoundParameter boundParameter = new BoundParameter(syntax,
                                                               parameterSymbol: accessor.Parameters[0])
            {
                WasCompilerGenerated = true
            };

            // tmp0 = _event;
            BoundStatement tmp0Init = new BoundExpressionStatement(syntax,
                                                                   expression: new BoundAssignmentOperator(syntax,
                                                                                                           left: boundTmps[0],
                                                                                                           right: boundBackingField,
                                                                                                           type: delegateType)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            };

            // LOOP:
            BoundStatement loopStart = new BoundLabelStatement(syntax,
                                                               label: loopLabel)
            {
                WasCompilerGenerated = true
            };

            // tmp1 = tmp0;
            BoundStatement tmp1Update = new BoundExpressionStatement(syntax,
                                                                     expression: new BoundAssignmentOperator(syntax,
                                                                                                             left: boundTmps[1],
                                                                                                             right: boundTmps[0],
                                                                                                             type: delegateType)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            };

            // (DelegateType)Delegate.Combine(tmp1, value)
            BoundExpression delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax,
                                                                                       operand: BoundCall.Synthesized(syntax,
                                                                                                                      receiverOpt: null,
                                                                                                                      method: updateMethod,
                                                                                                                      arguments: ImmutableArray.Create <BoundExpression>(boundTmps[1], boundParameter)),
                                                                                       kind: ConversionKind.ExplicitReference,
                                                                                       type: delegateType);

            // tmp2 = (DelegateType)Delegate.Combine(tmp1, value);
            BoundStatement tmp2Update = new BoundExpressionStatement(syntax,
                                                                     expression: new BoundAssignmentOperator(syntax,
                                                                                                             left: boundTmps[2],
                                                                                                             right: delegateUpdate,
                                                                                                             type: delegateType)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            };

            // Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1)
            BoundExpression compareExchange = BoundCall.Synthesized(syntax,
                                                                    receiverOpt: null,
                                                                    method: compareExchangeMethod,
                                                                    arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundTmps[2], boundTmps[1]));

            // tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1);
            BoundStatement tmp0Update = new BoundExpressionStatement(syntax,
                                                                     expression: new BoundAssignmentOperator(syntax,
                                                                                                             left: boundTmps[0],
                                                                                                             right: compareExchange,
                                                                                                             type: delegateType)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = true
            };

            // tmp0 == tmp1 // i.e. exit when they are equal, jump to start otherwise
            BoundExpression loopExitCondition = new BoundBinaryOperator(syntax,
                                                                        operatorKind: BinaryOperatorKind.ObjectEqual,
                                                                        left: boundTmps[0],
                                                                        right: boundTmps[1],
                                                                        constantValueOpt: null,
                                                                        methodOpt: null,
                                                                        resultKind: LookupResultKind.Viable,
                                                                        type: boolType)
            {
                WasCompilerGenerated = true
            };

            // branchfalse (tmp0 == tmp1) LOOP
            BoundStatement loopEnd = new BoundConditionalGoto(syntax,
                                                              condition: loopExitCondition,
                                                              jumpIfTrue: false,
                                                              label: loopLabel)
            {
                WasCompilerGenerated = true
            };

            BoundStatement @return = new BoundReturnStatement(syntax,
                                                              expressionOpt: null)
            {
                WasCompilerGenerated = true
            };

            return(new BoundBlock(syntax,
                                  localsOpt: tmps.AsImmutableOrNull(),
                                  statements: ImmutableArray.Create <BoundStatement>(
                                      tmp0Init,
                                      loopStart,
                                      tmp1Update,
                                      tmp2Update,
                                      tmp0Update,
                                      loopEnd,
                                      @return))
            {
                WasCompilerGenerated = true
            });
        }