public override BoundNode VisitHostObjectMemberReference(BoundHostObjectMemberReference node)
        {
            Debug.Assert(_previousSubmissionFields != null);
            Debug.Assert(!_factory.CurrentMethod.IsStatic);

            var syntax = node.Syntax;
            var hostObjectReference = _previousSubmissionFields.GetHostObjectField();
            var thisReference = new BoundThisReference(syntax, _factory.CurrentType);
            return new BoundFieldAccess(syntax, thisReference, hostObjectReference, constantValueOpt: null);
        }
        public override BoundNode VisitPreviousSubmissionReference(BoundPreviousSubmissionReference node)
        {
            var targetType = (ImplicitNamedTypeSymbol)node.Type;
            Debug.Assert(targetType.TypeKind == TypeKind.Submission);
            Debug.Assert(!_factory.CurrentMethod.IsStatic);

            Debug.Assert(_previousSubmissionFields != null);

            var syntax = node.Syntax;
            var targetScriptReference = _previousSubmissionFields.GetOrMakeField(targetType);
            var thisReference = new BoundThisReference(syntax, _factory.CurrentType);
            return new BoundFieldAccess(syntax, thisReference, targetScriptReference, ConstantValue.NotAvailable);
        }
        internal static ImmutableArray<BoundStatement> ConstructScriptConstructorBody(
            BoundStatement loweredBody,
            MethodSymbol constructor,
            SynthesizedSubmissionFields previousSubmissionFields,
            CSharpCompilation compilation)
        {
            // Script field initializers have to be emitted after the call to the base constructor because they can refer to "this" instance.
            //
            // Unlike regular field initializers, initializers of global script variables can access "this" instance. 
            // If the base class had a constructor that initializes its state a global variable would access partially initialized object. 
            // For this reason Script class must always derive directly from a class that has no state (System.Object).

            CSharpSyntaxNode syntax = loweredBody.Syntax;

            // base constructor call:
            Debug.Assert((object)constructor.ContainingType.BaseTypeNoUseSiteDiagnostics == null || constructor.ContainingType.BaseTypeNoUseSiteDiagnostics.SpecialType == SpecialType.System_Object);
            var objectType = constructor.ContainingAssembly.GetSpecialType(SpecialType.System_Object);

            BoundExpression receiver = new BoundThisReference(syntax, constructor.ContainingType) { WasCompilerGenerated = true };

            BoundStatement baseConstructorCall =
                new BoundExpressionStatement(syntax,
                    new BoundCall(syntax,
                        receiverOpt: receiver,
                        method: objectType.InstanceConstructors[0],
                        arguments: ImmutableArray<BoundExpression>.Empty,
                        argumentNamesOpt: ImmutableArray<string>.Empty,
                        argumentRefKindsOpt: ImmutableArray<RefKind>.Empty,
                        isDelegateCall: false,
                        expanded: false,
                        invokedAsExtensionMethod: false,
                        argsToParamsOpt: ImmutableArray<int>.Empty,
                        resultKind: LookupResultKind.Viable,
                        type: objectType)
                    { WasCompilerGenerated = true })
                { WasCompilerGenerated = true };

            var statements = ArrayBuilder<BoundStatement>.GetInstance();
            statements.Add(baseConstructorCall);

            if (constructor.IsSubmissionConstructor)
            {
                // submission initialization:
                MakeSubmissionInitialization(statements, syntax, constructor, previousSubmissionFields, compilation);
            }

            statements.Add(loweredBody);
            return statements.ToImmutableAndFree();
        }
 public override BoundNode VisitThisReference(BoundThisReference node)
 {
     Capture(_topLevelMethod.ThisParameter, node.Syntax);
     return base.VisitThisReference(node);
 }
        public override BoundNode VisitThisReference(BoundThisReference node)
        {
            var thisParameter = this.originalMethod.ThisParameter;
            CapturedSymbolReplacement proxy;
            if ((object)thisParameter == null || !proxies.TryGetValue(thisParameter, out proxy))
            {
                // This can occur in a delegate creation expression because the method group
                // in the argument can have a "this" receiver even when "this"
                // is not captured because a static method is selected.  But we do preserve
                // the method group and its receiver in the bound tree, so the "this"
                // receiver must be rewritten.

                //TODO: It seems we may capture more than needed here.

                // TODO: Why don't we drop "this" while lowering if method is static? 
                //       Actually, considering that method group expression does not evaluate to a particular value 
                //       why do we have it in the lowered tree at all?
                return node.Update(VisitType(node.Type));
            }
            else
            {
                Debug.Assert(proxy != null);
                return proxy.Replacement(F.Syntax, frameType => F.This());
            }
        }
Example #6
0
        internal static BoundCall GenerateObjectConstructorInitializer(MethodSymbol constructor, DiagnosticBag diagnostics)
        {
            NamedTypeSymbol objectType = constructor.ContainingType.BaseTypeNoUseSiteDiagnostics;
            Debug.Assert(objectType.SpecialType == SpecialType.System_Object);
            MethodSymbol objectConstructor = null;
            LookupResultKind resultKind = LookupResultKind.Viable;

            foreach (MethodSymbol objectCtor in objectType.InstanceConstructors)
            {
                if (objectCtor.ParameterCount == 0)
                {
                    objectConstructor = objectCtor;
                    break;
                }
            }

            // UNDONE: If this happens then something is deeply wrong. Should we give a better error?
            if ((object)objectConstructor == null)
            {
                diagnostics.Add(ErrorCode.ERR_BadCtorArgCount, constructor.Locations[0], objectType, /*desired param count*/ 0);
                return null;
            }

            // UNDONE: If this happens then something is deeply wrong. Should we give a better error?
            bool hasErrors = false;
            HashSet<DiagnosticInfo> useSiteDiagnostics = null;
            if (!AccessCheck.IsSymbolAccessible(objectConstructor, constructor.ContainingType, ref useSiteDiagnostics))
            {
                diagnostics.Add(ErrorCode.ERR_BadAccess, constructor.Locations[0], objectConstructor);
                resultKind = LookupResultKind.Inaccessible;
                hasErrors = true;
            }

            if (!useSiteDiagnostics.IsNullOrEmpty())
            {
                diagnostics.Add(constructor.Locations.IsEmpty ? NoLocation.Singleton : constructor.Locations[0], useSiteDiagnostics);
            }

            CSharpSyntaxNode syntax = constructor.GetNonNullSyntaxNode();

            BoundExpression receiver = new BoundThisReference(syntax, constructor.ContainingType) { WasCompilerGenerated = true };
            return new BoundCall(
                syntax: syntax,
                receiverOpt: receiver,
                method: objectConstructor,
                arguments: ImmutableArray<BoundExpression>.Empty,
                argumentNamesOpt: ImmutableArray<string>.Empty,
                argumentRefKindsOpt: ImmutableArray<RefKind>.Empty,
                isDelegateCall: false,
                expanded: false,
                invokedAsExtensionMethod: false,
                argsToParamsOpt: ImmutableArray<int>.Empty,
                resultKind: resultKind,
                type: objectType,
                hasErrors: hasErrors)
            { WasCompilerGenerated = true };
        }
            public override BoundNode VisitThisReference(BoundThisReference node)
            {
                var thisParam = _topLevelMethod.ThisParameter;
                if (thisParam != null)
                {
                    ReferenceVariable(node.Syntax, thisParam);
                }
                else
                {
                    // This can occur in a delegate creation expression because the method group
                    // in the argument can have a "this" receiver even when "this"
                    // is not captured because a static method is selected.  But we do preserve
                    // the method group and its receiver in the bound tree.
                    // No need to capture "this" in such case.

                    // TODO: Why don't we drop "this" while lowering if method is static? 
                    //       Actually, considering that method group expression does not evaluate to a particular value 
                    //       why do we have it in the lowered tree at all?
                }

                return base.VisitThisReference(node);
            }
        /// <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>
        /// Construct a body for an auto-property accessor (updating or returning the backing field).
        /// </summary>
        internal static BoundBlock ConstructAutoPropertyAccessorBody(SourceMethodSymbol accessor)
        {
            Debug.Assert(accessor.MethodKind == MethodKind.PropertyGet || accessor.MethodKind == MethodKind.PropertySet);

            var property = (SourcePropertySymbol)accessor.AssociatedSymbol;
            CSharpSyntaxNode syntax = property.CSharpSyntaxNode;
            BoundExpression thisReference = null;
            if (!accessor.IsStatic)
            {
                var thisSymbol = accessor.ThisParameter;
                thisReference = new BoundThisReference(syntax, thisSymbol.Type) { WasCompilerGenerated = true };
            }

            var field = property.BackingField;
            var fieldAccess = new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable) { WasCompilerGenerated = true };
            BoundStatement statement;

            if (accessor.MethodKind == MethodKind.PropertyGet)
            {
                statement = new BoundReturnStatement(syntax, fieldAccess) { WasCompilerGenerated = true };
            }
            else
            {
                Debug.Assert(accessor.MethodKind == MethodKind.PropertySet);
                var parameter = accessor.Parameters[0];
                statement = new BoundExpressionStatement(
                    syntax,
                    new BoundAssignmentOperator(
                        syntax,
                        fieldAccess,
                        new BoundParameter(syntax, parameter) { WasCompilerGenerated = true },
                        property.Type)
                { WasCompilerGenerated = true })
                { WasCompilerGenerated = true };
            }

            statement = new BoundSequencePoint(accessor.SyntaxNode, statement) { WasCompilerGenerated = true };

            return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray.Create<BoundStatement>(statement)) { WasCompilerGenerated = true };
        }
        /// <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 });
            }
        }