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()); } }
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 }); } }