protected override BoundExpression BindRangeVariable(SimpleNameSyntax node, RangeVariableSymbol qv, DiagnosticBag diagnostics)
            {
                Debug.Assert(!qv.IsTransparent);

                BoundExpression translation;
                ImmutableArray<string> path;
                if (_rangeVariableMap.TryGetValue(qv, out path))
                {
                    if (path.IsEmpty)
                    {
                        // the range variable maps directly to a use of the parameter of that name
                        var value = base.parameterMap[qv.Name];
                        Debug.Assert(value.Count == 1);
                        translation = new BoundParameter(node, value.Single()) { WasCompilerGenerated = true };
                    }
                    else
                    {
                        // if the query variable map for this variable is non empty, we always start with the current
                        // lambda's first parameter, which is a transparent identifier.
                        Debug.Assert(base.lambdaSymbol.Parameters[0].Name.StartsWith(transparentIdentifierPrefix));
                        translation = new BoundParameter(node, base.lambdaSymbol.Parameters[0]) { WasCompilerGenerated = true };
                        for (int i = path.Length - 1; i >= 0; i--)
                        {
                            var nextField = path[i];
                            translation = SelectField(node, translation, nextField, diagnostics);
                            translation.WasCompilerGenerated = true;
                        }
                    }

                    return new BoundRangeVariable(node, qv, translation, translation.Type);
                }

                return base.BindRangeVariable(node, qv, diagnostics);
            }
 protected override void VisitLvalueParameter(BoundParameter node)
 {
     TryHoistTopLevelParameter(node);
     base.VisitLvalueParameter(node);
 }
 public override BoundNode VisitParameter(BoundParameter node)
 {
     Capture(node.ParameterSymbol, node.Syntax);
     return base.VisitParameter(node);
 }
 public override BoundNode VisitParameter(BoundParameter node)
 {
     TryHoistTopLevelParameter(node);
     return base.VisitParameter(node);
 }
        internal static BoundTypeOrInstanceInitializers Rewrite(ImmutableArray<BoundInitializer> boundInitializers, MethodSymbol constructor)
        {
            Debug.Assert(!boundInitializers.IsDefault);

            var boundStatements = ArrayBuilder<BoundStatement>.GetInstance(boundInitializers.Length);

            for (int i = 0; i < boundInitializers.Length; i++)
            {
                var init = boundInitializers[i];

                switch (init.Kind)
                {
                    case BoundKind.FieldInitializer:
                        boundStatements.Add(RewriteFieldInitializer((BoundFieldInitializer)init));
                        break;

                    case BoundKind.InitializationScope:
                        var scope = (BoundInitializationScope)init;
                        var fieldInitializers = ArrayBuilder<BoundStatement>.GetInstance(scope.Initializers.Length);

                        foreach (BoundFieldInitializer fieldInitializer in scope.Initializers)
                        {
                            fieldInitializers.Add(RewriteFieldInitializer(fieldInitializer));
                        }

                        boundStatements.Add(new BoundBlock(scope.Syntax, scope.Locals, fieldInitializers.ToImmutableAndFree()) { WasCompilerGenerated = true });
                        break;

                    case BoundKind.GlobalStatementInitializer:
                        var stmtInit = (BoundGlobalStatementInitializer)init;

                        // the value of the last expression statement (if any) is stored to a ref parameter of the submission constructor:
                        if (constructor.IsSubmissionConstructor && i == boundInitializers.Length - 1 && stmtInit.Statement.Kind == BoundKind.ExpressionStatement)
                        {
                            var syntax = stmtInit.Syntax;
                            var submissionResultVariable = new BoundParameter(syntax, constructor.Parameters[1]);
                            var expr = ((BoundExpressionStatement)stmtInit.Statement).Expression;

                            // The expression is converted to the submission result type when the initializer is bound, 
                            // so we just need to assign it to the out parameter:
                            if ((object)expr.Type != null && expr.Type.SpecialType != SpecialType.System_Void)
                            {
                                boundStatements.Add(
                                    new BoundExpressionStatement(syntax,
                                        new BoundAssignmentOperator(syntax,
                                            submissionResultVariable,
                                            expr,
                                            expr.Type
                                        )
                                    ));

                                break;
                            }
                        }

                        boundStatements.Add(stmtInit.Statement);
                        break;

                    default:
                        throw ExceptionUtilities.UnexpectedValue(init.Kind);
                }
            }

            Debug.Assert(boundStatements.Count == boundInitializers.Length);

            CSharpSyntaxNode listSyntax;

            SourceMethodSymbol sourceConstructor = constructor as SourceMethodSymbol;
            if ((object)sourceConstructor != null)
            {
                listSyntax = sourceConstructor.SyntaxNode;
            }
            else
            {
                listSyntax = constructor.GetNonNullSyntaxNode();
            }

            return new BoundTypeOrInstanceInitializers(listSyntax, boundStatements.ToImmutableAndFree());
        }
        /// <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 WinRT field-like event.
        /// 
        /// Add:
        ///   return EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddEventHandler(value);
        /// 
        /// Remove:
        ///   EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveEventHandler(value);
        /// </summary>
        internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode;

            MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;
            Debug.Assert((object)accessor != null);

            FieldSymbol field = eventSymbol.AssociatedField;
            Debug.Assert((object)field != null);

            NamedTypeSymbol fieldType = (NamedTypeSymbol)field.Type;
            Debug.Assert(fieldType.Name == "EventRegistrationTokenTable");

            MethodSymbol getOrCreateMethod = (MethodSymbol)Binder.GetWellKnownTypeMember(
                compilation,
                WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__GetOrCreateEventRegistrationTokenTable,
                diagnostics,
                syntax: syntax);

            if ((object)getOrCreateMethod == null)
            {
                Debug.Assert(diagnostics.HasAnyErrors());
                return null;
            }

            getOrCreateMethod = getOrCreateMethod.AsMember(fieldType);

            WellKnownMember processHandlerMember = isAddMethod
                ? WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__AddEventHandler
                : WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__RemoveEventHandler;

            MethodSymbol processHandlerMethod = (MethodSymbol)Binder.GetWellKnownTypeMember(
                compilation,
                processHandlerMember,
                diagnostics,
                syntax: syntax);

            if ((object)processHandlerMethod == null)
            {
                Debug.Assert(diagnostics.HasAnyErrors());
                return null;
            }

            processHandlerMethod = processHandlerMethod.AsMember(fieldType);

            // _tokenTable
            BoundFieldAccess fieldAccess = new BoundFieldAccess(
                syntax,
                field.IsStatic ? null : new BoundThisReference(syntax, accessor.ThisParameter.Type),
                field,
                constantValueOpt: null)
            { WasCompilerGenerated = true };

            // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable)
            BoundCall getOrCreateCall = BoundCall.Synthesized(
                syntax,
                receiverOpt: null,
                method: getOrCreateMethod,
                arguments: fieldAccess);

            // value
            BoundParameter parameterAccess = new BoundParameter(
                syntax,
                accessor.Parameters.Single());

            // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value) // or RemoveHandler
            BoundCall processHandlerCall = BoundCall.Synthesized(
                syntax,
                receiverOpt: getOrCreateCall,
                method: processHandlerMethod,
                arguments: parameterAccess);

            if (isAddMethod)
            {
                // {
                //     return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value);
                // }   
                BoundStatement returnStatement = BoundReturnStatement.Synthesized(syntax, processHandlerCall);
                return BoundBlock.SynthesizedNoLocals(syntax, returnStatement);
            }
            else
            {
                // {
                //     EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveHandler(value);
                //     return;
                // }  
                BoundStatement callStatement = new BoundExpressionStatement(syntax, processHandlerCall);
                BoundStatement returnStatement = new BoundReturnStatement(syntax, expressionOpt: null);
                return BoundBlock.SynthesizedNoLocals(syntax, callStatement, returnStatement);
            }
        }
        /// <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 });
            }
        }
 public override BoundNode VisitParameter(BoundParameter node)
 {
     AddIfCaptured(node.ParameterSymbol);
     return(base.VisitParameter(node));
 }
 public override BoundNode VisitParameter(BoundParameter node)
 {
     ReferenceVariable(node.Syntax, node.ParameterSymbol);
     return(base.VisitParameter(node));
 }
Beispiel #11
0
        internal static BoundStatementList Rewrite(ImmutableArray<BoundInitializer> boundInitializers, MethodSymbol constructor)
        {
            Debug.Assert(!boundInitializers.IsDefault);

            var boundStatements = new BoundStatement[boundInitializers.Length];
            for (int i = 0; i < boundStatements.Length; i++)
            {
                var init = boundInitializers[i];
                var syntax = init.Syntax;
                switch (init.Kind)
                {
                    case BoundKind.FieldInitializer:
                        var fieldInit = (BoundFieldInitializer)init;

                        var boundReceiver = fieldInit.Field.IsStatic ? null :
                            new BoundThisReference(syntax, fieldInit.Field.ContainingType);

                        // Mark this as CompilerGenerated so that the local rewriter doesn't add a sequence point.
                        boundStatements[i] =
                            new BoundExpressionStatement(syntax,
                                new BoundAssignmentOperator(syntax,
                                    new BoundFieldAccess(syntax,
                                        boundReceiver,
                                        fieldInit.Field,
                                        constantValueOpt: null),
                                    fieldInit.InitialValue,
                                    fieldInit.Field.Type)
                        { WasCompilerGenerated = true })
                        { WasCompilerGenerated = true };

                        Debug.Assert(syntax is ExpressionSyntax); // Should be the initial value.
                        Debug.Assert(syntax.Parent.Kind == SyntaxKind.EqualsValueClause);
                        Debug.Assert(syntax.Parent.Parent.Kind == SyntaxKind.VariableDeclarator);
                        Debug.Assert(syntax.Parent.Parent.Parent.Kind == SyntaxKind.VariableDeclaration);

                        var declaratorSyntax = (VariableDeclaratorSyntax)syntax.Parent.Parent;
                        boundStatements[i] = LocalRewriter.AddSequencePoint(declaratorSyntax, boundStatements[i]);
                        break;

                    case BoundKind.GlobalStatementInitializer:
                        var stmtInit = (BoundGlobalStatementInitializer)init;

                        // the value of the last expression statement (if any) is stored to a ref parameter of the submission constructor:
                        if (constructor.IsSubmissionConstructor && i == boundStatements.Length - 1 && stmtInit.Statement.Kind == BoundKind.ExpressionStatement)
                        {
                            var submissionResultVariable = new BoundParameter(syntax, constructor.Parameters[1]);
                            var expr = ((BoundExpressionStatement)stmtInit.Statement).Expression;

                            // The expression is converted to the submission result type when the initializer is bound, 
                            // so we just need to assign it to the out parameter:
                            if ((object)expr.Type != null && expr.Type.SpecialType != SpecialType.System_Void)
                            {
                                boundStatements[i] =
                                    new BoundExpressionStatement(syntax,
                                        new BoundAssignmentOperator(syntax,
                                            submissionResultVariable,
                                            expr,
                                            expr.Type
                                        )
                                    );

                                break;
                            }
                        }

                        boundStatements[i] = stmtInit.Statement;
                        break;

                    default:
                        throw ExceptionUtilities.UnexpectedValue(init.Kind);
                }
            }

            CSharpSyntaxNode listSyntax;

            SourceMethodSymbol sourceConstructor = constructor as SourceMethodSymbol;
            if ((object)sourceConstructor != null)
            {
                listSyntax = sourceConstructor.SyntaxNode;
            }
            else
            {
                listSyntax = constructor.GetNonNullSyntaxNode();
            }

            return new BoundStatementList(listSyntax, boundStatements.AsImmutableOrNull());
        }
Beispiel #12
0
        private void ReduceLet(LetClauseSyntax let, QueryTranslationState state, DiagnosticBag diagnostics)
        {
            // A query expression with a let clause
            //     from x in e
            //     let y = f
            //     ...
            // is translated into
            //     from * in ( e ) . Select ( x => new { x , y = f } )
            //     ...
            var x = state.rangeVariable;

            // We use a slightly different translation strategy.  We produce
            //     from * in ( e ) . Select ( x => new Pair<X,Y>(x, f) )
            // Where X is the type of x, and Y is the type of the expression f.
            // Subsequently, x (or members of x, if it is a transparent identifier)
            // are accessed as TRID.Item1 (or members of that), and y is accessed
            // as TRID.Item2, where TRID is the compiler-generated identifier used
            // to represent the transparent identifier in the result.
            LambdaBodyFactory bodyFactory = (LambdaSymbol lambdaSymbol, ref Binder lambdaBodyBinder, DiagnosticBag d) =>
            {
                var xExpression = new BoundParameter(let, lambdaSymbol.Parameters[0]) { WasCompilerGenerated = true };

                var yExpression = lambdaBodyBinder.BindValue(let.Expression, d, BindValueKind.RValue);
                SourceLocation errorLocation = new SourceLocation(let.SyntaxTree, new TextSpan(let.Identifier.SpanStart, let.Expression.Span.End - let.Identifier.SpanStart));
                if (!yExpression.HasAnyErrors && !yExpression.HasExpressionType())
                {
                    MessageID id = MessageID.IDS_NULL;
                    if (yExpression.Kind == BoundKind.UnboundLambda)
                    {
                        id = ((UnboundLambda)yExpression).MessageID;
                    }
                    else if (yExpression.Kind == BoundKind.MethodGroup)
                    {
                        id = MessageID.IDS_MethodGroup;
                    }
                    else
                    {
                        Debug.Assert(yExpression.IsLiteralNull(), "How did we successfully bind an expression without a type?");
                    }

                    Error(d, ErrorCode.ERR_QueryRangeVariableAssignedBadValue, errorLocation, id.Localize());
                    yExpression = new BoundBadExpression(yExpression.Syntax, LookupResultKind.Empty, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<BoundNode>(yExpression), CreateErrorType());
                }
                else if (!yExpression.HasAnyErrors && yExpression.Type.SpecialType == SpecialType.System_Void)
                {
                    Error(d, ErrorCode.ERR_QueryRangeVariableAssignedBadValue, errorLocation, yExpression.Type);
                    yExpression = new BoundBadExpression(yExpression.Syntax, LookupResultKind.Empty, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<BoundNode>(yExpression), yExpression.Type);
                }

                var construction = MakePair(let, x.Name, xExpression, let.Identifier.ValueText, yExpression, state, d);
                return lambdaBodyBinder.CreateBlockFromExpression(let, lambdaBodyBinder.Locals, null, construction, d);
            };

            var lambda = MakeQueryUnboundLambda(state.RangeVariableMap(), ImmutableArray.Create(x), let.Expression, bodyFactory);
            state.rangeVariable = state.TransparentRangeVariable(this);
            state.AddTransparentIdentifier(x.Name);
            var y = state.AddRangeVariable(this, let.Identifier, diagnostics);
            state.allRangeVariables[y].Add(let.Identifier.ValueText);
            var invocation = MakeQueryInvocation(let, state.fromExpression, "Select", lambda, diagnostics);
            state.fromExpression = MakeQueryClause(let, invocation, y, invocation);
        }
 public override BoundNode VisitParameter(BoundParameter node)
 {
     Capture(node.ParameterSymbol, node.Syntax);
     return(base.VisitParameter(node));
 }
 public override BoundNode VisitParameter(BoundParameter node)
 {
     TryHoistTopLevelParameter(node);
     return(base.VisitParameter(node));
 }
Beispiel #15
0
        private UnboundLambda MakePairLambda(CSharpSyntaxNode node, QueryTranslationState state, RangeVariableSymbol x1, RangeVariableSymbol x2)
        {
            Debug.Assert(LambdaUtilities.IsQueryPairLambda(node));

            LambdaBodyFactory bodyFactory = (LambdaSymbol lambdaSymbol, Binder lambdaBodyBinder, DiagnosticBag d) =>
            {
                var x1Expression = new BoundParameter(node, lambdaSymbol.Parameters[0]) { WasCompilerGenerated = true };
                var x2Expression = new BoundParameter(node, lambdaSymbol.Parameters[1]) { WasCompilerGenerated = true };
                var construction = MakePair(node, x1.Name, x1Expression, x2.Name, x2Expression, state, d);
                return lambdaBodyBinder.CreateBlockFromExpression(node, ImmutableArray<LocalSymbol>.Empty, RefKind.None, construction, null, d);
            };

            var result = MakeQueryUnboundLambda(state.RangeVariableMap(), ImmutableArray.Create(x1, x2), node, bodyFactory);
            state.rangeVariable = state.TransparentRangeVariable(this);
            state.AddTransparentIdentifier(x1.Name);
            var x2m = state.allRangeVariables[x2];
            x2m[x2m.Count - 1] = x2.Name;
            return result;
        }
Beispiel #16
0
        private void ReduceLet(LetClauseSyntax let, QueryTranslationState state, DiagnosticBag diagnostics)
        {
            // A query expression with a let clause
            //     from x in e
            //     let y = f
            //     ...
            // is translated into
            //     from * in ( e ) . Select ( x => new { x , y = f } )
            //     ...
            var x = state.rangeVariable;

            // We use a slightly different translation strategy.  We produce
            //     from * in ( e ) . Select ( x => new Pair<X,Y>(x, f) )
            // Where X is the type of x, and Y is the type of the expression f.
            // Subsequently, x (or members of x, if it is a transparent identifier)
            // are accessed as TRID.Item1 (or members of that), and y is accessed
            // as TRID.Item2, where TRID is the compiler-generated identifier used
            // to represent the transparent identifier in the result.
            LambdaBodyFactory bodyFactory = (LambdaSymbol lambdaSymbol, Binder lambdaBodyBinder, DiagnosticBag d) =>
            {
                var xExpression = new BoundParameter(let, lambdaSymbol.Parameters[0]) { WasCompilerGenerated = true };

                lambdaBodyBinder = lambdaBodyBinder.GetBinder(let.Expression);
                Debug.Assert(lambdaBodyBinder != null);

                var yExpression = lambdaBodyBinder.BindValue(let.Expression, d, BindValueKind.RValue);
                SourceLocation errorLocation = new SourceLocation(let.SyntaxTree, new TextSpan(let.Identifier.SpanStart, let.Expression.Span.End - let.Identifier.SpanStart));
                if (!yExpression.HasAnyErrors && !yExpression.HasExpressionType())
                {
                    Error(d, ErrorCode.ERR_QueryRangeVariableAssignedBadValue, errorLocation, yExpression.Display);
                    yExpression = new BoundBadExpression(yExpression.Syntax, LookupResultKind.Empty, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<BoundNode>(yExpression), CreateErrorType());
                }
                else if (!yExpression.HasAnyErrors && yExpression.Type.SpecialType == SpecialType.System_Void)
                {
                    Error(d, ErrorCode.ERR_QueryRangeVariableAssignedBadValue, errorLocation, yExpression.Type);
                    yExpression = new BoundBadExpression(yExpression.Syntax, LookupResultKind.Empty, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<BoundNode>(yExpression), yExpression.Type);
                }

                var construction = MakePair(let, x.Name, xExpression, let.Identifier.ValueText, yExpression, state, d);

                // The bound block represents a closure scope for transparent identifiers captured in the let clause.
                // Such closures shall be associated with the lambda body expression.
                return lambdaBodyBinder.CreateBlockFromExpression(let.Expression, lambdaBodyBinder.GetDeclaredLocalsForScope(let.Expression), RefKind.None, construction, null, d);
            };

            var lambda = MakeQueryUnboundLambda(state.RangeVariableMap(), ImmutableArray.Create(x), let.Expression, bodyFactory);
            state.rangeVariable = state.TransparentRangeVariable(this);
            state.AddTransparentIdentifier(x.Name);
            var y = state.AddRangeVariable(this, let.Identifier, diagnostics);
            state.allRangeVariables[y].Add(let.Identifier.ValueText);
            var invocation = MakeQueryInvocation(let, state.fromExpression, "Select", lambda, diagnostics);
            state.fromExpression = MakeQueryClause(let, invocation, y, invocation);
        }
Beispiel #17
0
        internal static BoundTypeOrInstanceInitializers Rewrite(ImmutableArray <BoundInitializer> boundInitializers, MethodSymbol constructor)
        {
            Debug.Assert(!boundInitializers.IsDefault);

            var boundStatements = ArrayBuilder <BoundStatement> .GetInstance(boundInitializers.Length);

            for (int i = 0; i < boundInitializers.Length; i++)
            {
                var init = boundInitializers[i];

                switch (init.Kind)
                {
                case BoundKind.FieldInitializer:
                    boundStatements.Add(RewriteFieldInitializer((BoundFieldInitializer)init));
                    break;

                case BoundKind.GlobalStatementInitializer:
                    var stmtInit = (BoundGlobalStatementInitializer)init;

                    // the value of the last expression statement (if any) is stored to a ref parameter of the submission constructor:
                    if (constructor.IsSubmissionConstructor && i == boundInitializers.Length - 1 && stmtInit.Statement.Kind == BoundKind.ExpressionStatement)
                    {
                        var syntax = stmtInit.Syntax;
                        var submissionResultVariable = new BoundParameter(syntax, constructor.Parameters[1]);
                        var expr = ((BoundExpressionStatement)stmtInit.Statement).Expression;

                        // The expression is converted to the submission result type when the initializer is bound,
                        // so we just need to assign it to the out parameter:
                        if ((object)expr.Type != null && expr.Type.SpecialType != SpecialType.System_Void)
                        {
                            boundStatements.Add(
                                new BoundExpressionStatement(syntax,
                                                             new BoundAssignmentOperator(syntax,
                                                                                         submissionResultVariable,
                                                                                         expr,
                                                                                         expr.Type
                                                                                         )
                                                             ));

                            break;
                        }
                    }

                    boundStatements.Add(stmtInit.Statement);
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(init.Kind);
                }
            }

            Debug.Assert(boundStatements.Count == boundInitializers.Length);

            CSharpSyntaxNode listSyntax;

            SourceMethodSymbol sourceConstructor = constructor as SourceMethodSymbol;

            if ((object)sourceConstructor != null)
            {
                listSyntax = sourceConstructor.SyntaxNode;
            }
            else
            {
                listSyntax = constructor.GetNonNullSyntaxNode();
            }

            return(new BoundTypeOrInstanceInitializers(listSyntax, boundStatements.ToImmutableAndFree()));
        }
        /// <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,
            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
                });
            }
        }
Beispiel #19
0
        private void ReduceLet(LetClauseSyntax let, QueryTranslationState state, DiagnosticBag diagnostics)
        {
            // A query expression with a let clause
            //     from x in e
            //     let y = f
            //     ...
            // is translated into
            //     from * in ( e ) . Select ( x => new { x , y = f } )
            //     ...
            var x = state.rangeVariable;

            // We use a slightly different translation strategy.  We produce
            //     from * in ( e ) . Select ( x => new Pair<X,Y>(x, f) )
            // Where X is the type of x, and Y is the type of the expression f.
            // Subsequently, x (or members of x, if it is a transparent identifier)
            // are accessed as TRID.Item1 (or members of that), and y is accessed
            // as TRID.Item2, where TRID is the compiler-generated identifier used
            // to represent the transparent identifier in the result.
            LambdaBodyFactory bodyFactory = (LambdaSymbol lambdaSymbol, ref Binder lambdaBodyBinder, DiagnosticBag d) =>
            {
                var xExpression = new BoundParameter(let, lambdaSymbol.Parameters[0])
                {
                    WasCompilerGenerated = true
                };

                var            yExpression   = lambdaBodyBinder.BindValue(let.Expression, d, BindValueKind.RValue);
                SourceLocation errorLocation = new SourceLocation(let.SyntaxTree, new TextSpan(let.Identifier.SpanStart, let.Expression.Span.End - let.Identifier.SpanStart));
                if (!yExpression.HasAnyErrors && !yExpression.HasExpressionType())
                {
                    MessageID id = MessageID.IDS_NULL;
                    if (yExpression.Kind == BoundKind.UnboundLambda)
                    {
                        id = ((UnboundLambda)yExpression).MessageID;
                    }
                    else if (yExpression.Kind == BoundKind.MethodGroup)
                    {
                        id = MessageID.IDS_MethodGroup;
                    }
                    else
                    {
                        Debug.Assert(yExpression.IsLiteralNull(), "How did we successfully bind an expression without a type?");
                    }

                    Error(d, ErrorCode.ERR_QueryRangeVariableAssignedBadValue, errorLocation, id.Localize());
                    yExpression = new BoundBadExpression(yExpression.Syntax, LookupResultKind.Empty, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundNode>(yExpression), CreateErrorType());
                }
                else if (!yExpression.HasAnyErrors && yExpression.Type.SpecialType == SpecialType.System_Void)
                {
                    Error(d, ErrorCode.ERR_QueryRangeVariableAssignedBadValue, errorLocation, yExpression.Type);
                    yExpression = new BoundBadExpression(yExpression.Syntax, LookupResultKind.Empty, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundNode>(yExpression), yExpression.Type);
                }

                var construction = MakePair(let, x.Name, xExpression, let.Identifier.ValueText, yExpression, state, d);
                return(lambdaBodyBinder.CreateBlockFromExpression(let, lambdaBodyBinder.Locals, null, construction, d));
            };

            var lambda = MakeQueryUnboundLambda(state.RangeVariableMap(), ImmutableArray.Create(x), let.Expression, bodyFactory);

            state.rangeVariable = state.TransparentRangeVariable(this);
            state.AddTransparentIdentifier(x.Name);
            var y = state.AddRangeVariable(this, let.Identifier, diagnostics);

            state.allRangeVariables[y].Add(let.Identifier.ValueText);
            var invocation = MakeQueryInvocation(let, state.fromExpression, "Select", lambda, diagnostics);

            state.fromExpression = MakeQueryClause(let, invocation, y, invocation);
        }
        /// <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 };

        }
Beispiel #21
0
 private BoundExpression VisitParameter(BoundParameter node)
 {
     return(_parameterMap[node.ParameterSymbol]);
 }
 public override BoundNode VisitParameter(BoundParameter node)
 {
     ReferenceVariable(node.Syntax, node.ParameterSymbol);
     return base.VisitParameter(node);
 }
 public override BoundNode VisitParameter(BoundParameter node)
 {
     CheckReferenceToVariable(node, node.ParameterSymbol);
     return(base.VisitParameter(node));
 }
 protected override void VisitLvalueParameter(BoundParameter node)
 {
     TryHoistTopLevelParameter(node);
     base.VisitLvalueParameter(node);
 }
        /// <summary>
        /// Generate a thread-safe accessor for a WinRT field-like event.
        ///
        /// Add:
        ///   return EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddEventHandler(value);
        ///
        /// Remove:
        ///   EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveEventHandler(value);
        /// </summary>
        internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode;

            MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;

            Debug.Assert((object)accessor != null);

            FieldSymbol field = eventSymbol.AssociatedField;

            Debug.Assert((object)field != null);

            NamedTypeSymbol fieldType = (NamedTypeSymbol)field.Type;

            Debug.Assert(fieldType.Name == "EventRegistrationTokenTable");

            MethodSymbol getOrCreateMethod = (MethodSymbol)Binder.GetWellKnownTypeMember(
                compilation,
                WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__GetOrCreateEventRegistrationTokenTable,
                diagnostics,
                syntax: syntax);

            if ((object)getOrCreateMethod == null)
            {
                Debug.Assert(diagnostics.HasAnyErrors());
                return(null);
            }

            getOrCreateMethod = getOrCreateMethod.AsMember(fieldType);

            WellKnownMember processHandlerMember = isAddMethod
                ? WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__AddEventHandler
                : WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__RemoveEventHandler;

            MethodSymbol processHandlerMethod = (MethodSymbol)Binder.GetWellKnownTypeMember(
                compilation,
                processHandlerMember,
                diagnostics,
                syntax: syntax);

            if ((object)processHandlerMethod == null)
            {
                Debug.Assert(diagnostics.HasAnyErrors());
                return(null);
            }

            processHandlerMethod = processHandlerMethod.AsMember(fieldType);

            // _tokenTable
            BoundFieldAccess fieldAccess = new BoundFieldAccess(
                syntax,
                field.IsStatic ? null : new BoundThisReference(syntax, accessor.ThisParameter.Type),
                field,
                constantValueOpt: null)
            {
                WasCompilerGenerated = true
            };

            // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable)
            BoundCall getOrCreateCall = BoundCall.Synthesized(
                syntax,
                receiverOpt: null,
                method: getOrCreateMethod,
                arg0: fieldAccess);

            // value
            BoundParameter parameterAccess = new BoundParameter(
                syntax,
                accessor.Parameters[0]);

            // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value) // or RemoveHandler
            BoundCall processHandlerCall = BoundCall.Synthesized(
                syntax,
                receiverOpt: getOrCreateCall,
                method: processHandlerMethod,
                arg0: parameterAccess);

            if (isAddMethod)
            {
                // {
                //     return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value);
                // }
                BoundStatement returnStatement = BoundReturnStatement.Synthesized(syntax, processHandlerCall);
                return(BoundBlock.SynthesizedNoLocals(syntax, returnStatement));
            }
            else
            {
                // {
                //     EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveHandler(value);
                //     return;
                // }
                BoundStatement callStatement   = new BoundExpressionStatement(syntax, processHandlerCall);
                BoundStatement returnStatement = new BoundReturnStatement(syntax, expressionOpt: null);
                return(BoundBlock.SynthesizedNoLocals(syntax, callStatement, returnStatement));
            }
        }
 private void TryHoistTopLevelParameter(BoundParameter node)
 {
     if (node.ParameterSymbol.ContainingSymbol == topLevelMethod)
     {
         CaptureVariable(node.ParameterSymbol, node.Syntax);
     }
 }
        /// <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);
        ///
        /// Note, if System.Threading.Interlocked.CompareExchange&lt;T&gt; is not available,
        /// we emit the following code and mark the method Synchronized (unless it is a struct).
        ///
        /// _event = (DelegateType)Delegate.Combine(_event, value); //Remove for -=
        ///
        /// </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);

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

            BoundStatement @return = new BoundReturnStatement(syntax,
                                                              expressionOpt: null)
            {
                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(new BoundBlock(syntax,
                                      locals: ImmutableArray <LocalSymbol> .Empty,
                                      statements: ImmutableArray.Create <BoundStatement>(@return))
                {
                    WasCompilerGenerated = true
                });
            }

            Binder.ReportUseSiteDiagnostics(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)),
                                                                           kind: ConversionKind.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(new BoundBlock(syntax,
                                      locals: ImmutableArray <LocalSymbol> .Empty,
                                      statements: ImmutableArray.Create <BoundStatement>(
                                          eventUpdate,
                                          @return))
                {
                    WasCompilerGenerated = true
                });
            }

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

            Binder.ReportUseSiteDiagnostics(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, delegateType, SynthesizedLocalKind.LoweringTemp);
                boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType);
            }

            // 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)),
                                                                       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
            };

            return(new BoundBlock(syntax,
                                  locals: tmps.AsImmutable(),
                                  statements: ImmutableArray.Create <BoundStatement>(
                                      tmp0Init,
                                      loopStart,
                                      tmp1Update,
                                      tmp2Update,
                                      tmp0Update,
                                      loopEnd,
                                      @return))
            {
                WasCompilerGenerated = true
            });
        }
 private BoundExpression VisitParameter(BoundParameter node)
 {
     return _parameterMap[node.ParameterSymbol];
 }
Beispiel #29
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());
        }