internal SpillFieldAllocator(SyntheticBoundNodeFactory F, TypeCompilationState CompilationState) { allocatedFields = new KeyedStack<TypeSymbol, FieldSymbol>(); realizedSpills = new Dictionary<BoundSpillTemp, FieldSymbol>(); this.F = F; this.CompilationState = CompilationState; }
internal SynthesizedLambdaMethod(NamedTypeSymbol containingType, MethodSymbol topLevelMethod, BoundLambda node, bool isStatic, TypeCompilationState compilationState) : base(containingType, node.Symbol, null, node.SyntaxTree.GetReference(node.Body.Syntax), node.Syntax.GetLocation(), GeneratedNames.MakeLambdaMethodName(topLevelMethod.Name, compilationState.GenerateTempNumber()), (containingType is LambdaFrame ? DeclarationModifiers.Internal : DeclarationModifiers.Private) | (isStatic ? DeclarationModifiers.Static : 0) | (node.Symbol.IsAsync ? DeclarationModifiers.Async : 0)) { TypeMap typeMap; ImmutableArray<TypeParameterSymbol> typeParameters; LambdaFrame lambdaFrame; if (!topLevelMethod.IsGenericMethod) { typeMap = TypeMap.Empty; typeParameters = ImmutableArray<TypeParameterSymbol>.Empty; } else if ((object)(lambdaFrame = this.ContainingType as LambdaFrame) != null) { typeMap = lambdaFrame.TypeMap; typeParameters = ImmutableArray<TypeParameterSymbol>.Empty; } else { typeMap = TypeMap.Empty.WithAlphaRename(topLevelMethod, this, out typeParameters); } AssignTypeMapAndTypeParameters(typeMap, typeParameters); }
protected StateMachineRewriter( BoundStatement body, MethodSymbol method, SynthesizedContainer stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) { Debug.Assert(body != null); Debug.Assert(method != null); Debug.Assert(stateMachineType != null); Debug.Assert(compilationState != null); Debug.Assert(diagnostics != null); this.body = body; this.method = method; this.stateMachineType = stateMachineType; this.slotAllocatorOpt = slotAllocatorOpt; this.synthesizedLocalOrdinals = new SynthesizedLocalOrdinalsDispenser(); this.diagnostics = diagnostics; this.F = new SyntheticBoundNodeFactory(method, body.Syntax, compilationState, diagnostics); Debug.Assert(F.CurrentType == method.ContainingType); Debug.Assert(F.Syntax == body.Syntax); }
/// <summary> /// Rewrite an iterator method into a state machine class. /// </summary> /// <param name="body">The original body of the method</param> /// <param name="method">The method's identity</param> /// <param name="compilationState">The collection of generated methods that result from this transformation and which must be emitted</param> /// <param name="diagnostics">Diagnostic bag for diagnostics.</param> /// <param name="generateDebugInfo"></param> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo) { TypeSymbol elementType = method.IteratorElementType; if ((object)elementType == null) { return body; } // Figure out what kind of iterator we are generating. bool isEnumerable; switch (method.ReturnType.OriginalDefinition.SpecialType) { case SpecialType.System_Collections_IEnumerable: case SpecialType.System_Collections_Generic_IEnumerable_T: isEnumerable = true; break; case SpecialType.System_Collections_IEnumerator: case SpecialType.System_Collections_Generic_IEnumerator_T: isEnumerable = false; break; default: throw ExceptionUtilities.UnexpectedValue(method.ReturnType.OriginalDefinition.SpecialType); } var iteratorClass = new IteratorStateMachine(method, isEnumerable, elementType, compilationState); return new IteratorRewriter(body, method, isEnumerable, iteratorClass, compilationState, diagnostics, generateDebugInfo).Rewrite(); }
internal static BoundBlock Rewrite(SourceMethodSymbol sourceMethodSymbol, MethodContractSyntax contract, BoundBlock body, TypeCompilationState compilationState, DiagnosticBag diagsForCurrentMethod) { var binder = compilationState.Compilation.GetBinderFactory(sourceMethodSymbol.SyntaxTree) .GetBinder(body.Syntax); SyntheticBoundNodeFactory factory = new SyntheticBoundNodeFactory(sourceMethodSymbol, sourceMethodSymbol.SyntaxNode, compilationState, diagsForCurrentMethod); var contractType = compilationState.Compilation.GetTypeByReflectionType(typeof(System.Diagnostics.Contracts.Contract), diagsForCurrentMethod); var contractStatements = ArrayBuilder<BoundStatement>.GetInstance(contract.Requires.Count); foreach (var requires in contract.Requires) { var condition = binder.BindExpression(requires.Condition, diagsForCurrentMethod); var methodCall = factory.StaticCall(contractType, "Requires", condition); var statement = factory.ExpressionStatement(methodCall); contractStatements.Add(statement); } foreach (var requires in contract.Ensures) { var condition = binder.BindExpression(requires.Condition, diagsForCurrentMethod); var methodCall = factory.StaticCall(contractType, "Ensures", condition); var statement = factory.ExpressionStatement(methodCall); contractStatements.Add(statement); } return body.Update(body.Locals, body.Statements.InsertRange(0, contractStatements.ToImmutableAndFree())); }
/// <summary> /// Rewrite an async method into a state machine type. /// </summary> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, int methodOrdinal, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics, out AsyncStateMachine stateMachineType) { if (!method.IsAsync) { stateMachineType = null; return body; } // The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class. var typeKind = compilationState.Compilation.Options.EnableEditAndContinue ? TypeKind.Class : TypeKind.Struct; var bodyWithAwaitLifted = AwaitExpressionSpiller.Rewrite(body, method, compilationState, diagnostics); stateMachineType = new AsyncStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, typeKind); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType); var rewriter = new AsyncRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics); if (!rewriter.VerifyPresenceOfRequiredAPIs()) { return body; } return rewriter.Rewrite(); }
/// <summary> /// Rewrite an async method into a state machine class. /// </summary> /// <param name="body">The original body of the method</param> /// <param name="method">The method's identity</param> /// <param name="compilationState">The collection of generated methods that result from this transformation and which must be emitted</param> /// <param name="diagnostics">Diagnostic bag for diagnostics.</param> /// <param name="generateDebugInfo"></param> /// <param name="stateMachineType"></param> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo, out AsyncStateMachine stateMachineType) { if (!method.IsAsync) { stateMachineType = null; return body; } // The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class. var typeKind = compilationState.Compilation.Options.EnableEditAndContinue ? TypeKind.Class : TypeKind.Struct; var bodyWithAwaitLifted = AwaitLiftingRewriter.Rewrite(body, method, compilationState, diagnostics); stateMachineType = new AsyncStateMachine(method, typeKind); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType); var rewriter = new AsyncRewriter(bodyWithAwaitLifted, method, stateMachineType, compilationState, diagnostics, generateDebugInfo); if (!rewriter.constructedSuccessfully) { return body; } return rewriter.Rewrite(); }
public AsyncStruct(MethodSymbol method, TypeCompilationState compilationState) : base(method, GeneratedNames.MakeIteratorOrAsyncDisplayClassName(method.Name, compilationState.GenerateTempNumber()), TypeKind.Struct) { this.interfaces = ReadOnlyArray<NamedTypeSymbol>.CreateFrom( compilationState.EmitModule.Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IAsyncStateMachine)); this.constructor = new SynthesizedInstanceConstructor(this); }
private ExpressionLambdaRewriter(TypeCompilationState compilationState, CSharpSyntaxNode node, DiagnosticBag diagnostics) { Bound = new SyntheticBoundNodeFactory((NamedTypeSymbol)null, node, compilationState, diagnostics); Int32Type = Bound.SpecialType(SpecialType.System_Int32); ObjectType = Bound.SpecialType(SpecialType.System_Object); NullableType = Bound.SpecialType(SpecialType.System_Nullable_T); IEnumerableType = Bound.SpecialType(SpecialType.System_Collections_Generic_IEnumerable_T); }
public AsyncStateMachine(VariableSlotAllocator variableAllocatorOpt, TypeCompilationState compilationState, MethodSymbol asyncMethod, int asyncMethodOrdinal, TypeKind typeKind) : base(variableAllocatorOpt, compilationState, asyncMethod, asyncMethodOrdinal) { // TODO: report use-site errors on these types _typeKind = typeKind; _interfaces = ImmutableArray.Create(asyncMethod.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IAsyncStateMachine)); _constructor = new AsyncConstructor(this); }
private IteratorRewriter( BoundStatement body, MethodSymbol method, bool isEnumerable, IteratorStateMachine iteratorClass, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, iteratorClass, compilationState, diagnostics) { // the element type may contain method type parameters, which are now alpha-renamed into type parameters of the generated class this.elementType = iteratorClass.ElementType; this.isEnumerable = isEnumerable; }
private AsyncRewriter( BoundStatement body, MethodSymbol method, int methodOrdinal, AsyncStateMachine stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) { _constructedSuccessfully = AsyncMethodBuilderMemberCollection.TryCreate(F, method, this.stateMachineType.TypeMap, out _asyncMethodBuilderMemberCollection); _methodOrdinal = methodOrdinal; _ignoreAccessibility = compilationState.ModuleBuilderOpt.IgnoreAccessibility; }
private IteratorRewriter( BoundStatement body, MethodSymbol method, bool isEnumerable, IteratorStateMachine stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) { // the element type may contain method type parameters, which are now alpha-renamed into type parameters of the generated class _elementType = stateMachineType.ElementType; _isEnumerable = isEnumerable; }
protected StateMachineRewriter( BoundStatement body, MethodSymbol method, SynthesizedContainer stateMachineClass, TypeCompilationState compilationState, DiagnosticBag diagnostics) { this.body = body; this.method = method; this.stateMachineClass = stateMachineClass; this.compilationState = compilationState; this.diagnostics = diagnostics; this.F = new SyntheticBoundNodeFactory(method, body.Syntax, compilationState, diagnostics); Debug.Assert(F.CurrentClass == method.ContainingType); Debug.Assert(F.Syntax == body.Syntax); }
private AsyncRewriter( BoundStatement body, MethodSymbol method, AsyncStateMachine stateMachineClass, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, stateMachineClass, compilationState, diagnostics) { try { constructedSuccessfully = AsyncMethodBuilderMemberCollection.TryCreate(F, method, this.stateMachineClass.TypeMap, out this.asyncMethodBuilderMemberCollection); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); constructedSuccessfully = false; } }
public IteratorClass(MethodSymbol method, bool isEnumerable, TypeSymbol elementType, TypeCompilationState compilationState) : base(method, GeneratedNames.MakeIteratorOrAsyncDisplayClassName(method.Name, compilationState.GenerateTempNumber()), TypeKind.Class) { this.ElementType = TypeMap.SubstituteType(elementType); var interfaces = ArrayBuilder<NamedTypeSymbol>.GetInstance(); if (isEnumerable) { interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T).Construct(ElementType)); interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_Collections_IEnumerable)); } interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerator_T).Construct(ElementType)); interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_IDisposable)); interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_Collections_IEnumerator)); this.interfaces = interfaces.ToImmutableAndFree(); this.constructor = new IteratorConstructor(this); }
/// <summary> /// Rewrite an iterator method into a state machine class. /// </summary> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, int methodOrdinal, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics, out IteratorStateMachine stateMachineType) { TypeSymbol elementType = method.IteratorElementType; if ((object)elementType == null) { stateMachineType = null; return body; } // Figure out what kind of iterator we are generating. bool isEnumerable; switch (method.ReturnType.OriginalDefinition.SpecialType) { case SpecialType.System_Collections_IEnumerable: case SpecialType.System_Collections_Generic_IEnumerable_T: isEnumerable = true; break; case SpecialType.System_Collections_IEnumerator: case SpecialType.System_Collections_Generic_IEnumerator_T: isEnumerable = false; break; default: throw ExceptionUtilities.UnexpectedValue(method.ReturnType.OriginalDefinition.SpecialType); } stateMachineType = new IteratorStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, isEnumerable, elementType); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType); var rewriter = new IteratorRewriter(body, method, isEnumerable, stateMachineType, slotAllocatorOpt, compilationState, diagnostics); if (!rewriter.VerifyPresenceOfRequiredAPIs()) { return body; } return rewriter.Rewrite(); }
public IteratorStateMachine(VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, MethodSymbol iteratorMethod, int iteratorMethodOrdinal, bool isEnumerable, TypeSymbol elementType) : base(slotAllocatorOpt, compilationState, iteratorMethod, iteratorMethodOrdinal) { this.ElementType = TypeMap.SubstituteType(elementType); var interfaces = ArrayBuilder<NamedTypeSymbol>.GetInstance(); if (isEnumerable) { interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T).Construct(ElementType)); interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_Collections_IEnumerable)); } interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerator_T).Construct(ElementType)); interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_IDisposable)); interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_Collections_IEnumerator)); _interfaces = interfaces.ToImmutableAndFree(); _constructor = new IteratorConstructor(this); }
/// <summary> /// Rewrite an async method into a state machine class. /// </summary> /// <param name="body">The original body of the method</param> /// <param name="method">The method's identity</param> /// <param name="compilationState">The collection of generated methods that result from this transformation and which must be emitted</param> /// <param name="diagnostics">Diagnostic bag for diagnostics.</param> /// <param name="generateDebugInfo"></param> internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo) { if (!method.IsAsync) { return body; } var bodyWithAwaitLifted = AwaitLiftingRewriter.Rewrite(body, method, compilationState, diagnostics); var rewriter = new AsyncRewriter2(bodyWithAwaitLifted, method, ((SourceMethodSymbol)method).AsyncStateMachineType, compilationState, diagnostics, generateDebugInfo); if (!rewriter.constructedSuccessfully) { return body; } var bodyReplacement = rewriter.Rewrite(); return bodyReplacement; }
private AsyncRewriter( BoundStatement body, MethodSymbol method, int methodOrdinal, AsyncStateMachine stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) { try { _constructedSuccessfully = AsyncMethodBuilderMemberCollection.TryCreate(F, method, this.stateMachineType.TypeMap, out _asyncMethodBuilderMemberCollection); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); _constructedSuccessfully = false; } _methodOrdinal = methodOrdinal; _ignoreAccessibility = compilationState.ModuleBuilderOpt.IgnoreAccessibility; }
// NOTE: can return null if the method has no body. internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo, out ConsList<Imports> debugImports) { debugImports = null; BoundStatement constructorInitializer = null; BoundBlock body; var compilation = method.DeclaringCompilation; var sourceMethod = method as SourceMethodSymbol; if ((object)sourceMethod != null) { if (sourceMethod.IsExtern) { if (sourceMethod.BlockSyntax == null) { // Generate warnings only if we are not generating ERR_ExternHasBody error GenerateExternalMethodWarnings(sourceMethod, diagnostics); } return null; } else if (sourceMethod.IsParameterlessValueTypeConstructor(requireSynthesized: true)) { // No body for default struct constructor. return null; } var blockSyntax = sourceMethod.BlockSyntax; if (blockSyntax != null) { var factory = compilation.GetBinderFactory(sourceMethod.SyntaxTree); var inMethodBinder = factory.GetBinder(blockSyntax); var binder = new ExecutableCodeBinder(blockSyntax, sourceMethod, inMethodBinder); body = binder.BindBlock(blockSyntax, diagnostics); if (generateDebugInfo) { debugImports = binder.ImportsList; } if (inMethodBinder.IsDirectlyInIterator) { foreach (var parameter in method.Parameters) { if (parameter.RefKind != RefKind.None) { diagnostics.Add(ErrorCode.ERR_BadIteratorArgType, parameter.Locations[0]); } else if (parameter.Type.IsUnsafe()) { diagnostics.Add(ErrorCode.ERR_UnsafeIteratorArgType, parameter.Locations[0]); } } if (sourceMethod.IsUnsafe && compilation.Options.AllowUnsafe) // Don't cascade { diagnostics.Add(ErrorCode.ERR_IllegalInnerUnsafe, sourceMethod.Locations[0]); } if (sourceMethod.IsVararg) { // error CS1636: __arglist is not allowed in the parameter list of iterators diagnostics.Add(ErrorCode.ERR_VarargsIterator, sourceMethod.Locations[0]); } } } else // for [if (blockSyntax != null)] { var property = sourceMethod.AssociatedSymbol as SourcePropertySymbol; if ((object)property != null && property.IsAutoProperty) { return MethodBodySynthesizer.ConstructAutoPropertyAccessorBody(sourceMethod); } if (sourceMethod.IsPrimaryCtor) { body = null; } else { return null; } } } else { // synthesized methods should return their bound bodies body = null; } // delegates have constructors but not constructor initializers if (method.MethodKind == MethodKind.Constructor && !method.ContainingType.IsDelegateType()) { var initializerInvocation = BindConstructorInitializer(method, diagnostics, compilation); if (initializerInvocation != null) { constructorInitializer = new BoundExpressionStatement(initializerInvocation.Syntax, initializerInvocation) { WasCompilerGenerated = true }; Debug.Assert(initializerInvocation.HasAnyErrors || constructorInitializer.IsConstructorInitializer(), "Please keep this bound node in sync with BoundNodeExtensions.IsConstructorInitializer."); } } var statements = ArrayBuilder<BoundStatement>.GetInstance(); if (constructorInitializer != null) { statements.Add(constructorInitializer); } if ((object)sourceMethod != null && sourceMethod.IsPrimaryCtor && (object)((SourceMemberContainerTypeSymbol)sourceMethod.ContainingType).PrimaryCtor == (object)sourceMethod) { Debug.Assert(method.MethodKind == MethodKind.Constructor && !method.ContainingType.IsDelegateType()); Debug.Assert(body == null); if (sourceMethod.ParameterCount > 0) { var factory = new SyntheticBoundNodeFactory(sourceMethod, sourceMethod.SyntaxNode, compilationState, diagnostics); factory.CurrentMethod = sourceMethod; foreach (var parameter in sourceMethod.Parameters) { FieldSymbol field = parameter.PrimaryConstructorParameterBackingField; if ((object)field != null) { statements.Add(factory.Assignment(factory.Field(factory.This(), field), factory.Parameter(parameter))); } } } } if (body != null) { statements.Add(body); } CSharpSyntaxNode syntax = body != null ? body.Syntax : method.GetNonNullSyntaxNode(); BoundBlock block; if (statements.Count == 1 && statements[0].Kind == ((body == null) ? BoundKind.Block : body.Kind)) { // most common case - we just have a single block for the body. block = (BoundBlock)statements[0]; statements.Free(); } else { block = new BoundBlock(syntax, default(ImmutableArray<LocalSymbol>), statements.ToImmutableAndFree()) { WasCompilerGenerated = true }; } return method.MethodKind == MethodKind.Destructor ? MethodBodySynthesizer.ConstructDestructorBody(syntax, method, block) : block; }
internal static BoundStatement Rewrite(BoundStatement body, MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics) { return(new AwaitLiftingRewriter(method, body.Syntax, compilationState, diagnostics).Rewrite(body)); }
/// <summary> /// Create a bound node factory. Note that the use of the factory to get special or well-known members /// that do not exist will result in an exception of type <see cref="MissingPredefinedMember"/> being thrown. /// </summary> /// <param name="topLevelMethod">The top-level method that will contain the code</param> /// <param name="node">The syntax node to which generated code should be attributed</param> /// <param name="compilationState">The state of compilation of the enclosing type</param> /// <param name="diagnostics">A bag where any diagnostics should be output</param> public SyntheticBoundNodeFactory(MethodSymbol topLevelMethod, CSharpSyntaxNode node, TypeCompilationState compilationState, DiagnosticBag diagnostics) : this(topLevelMethod, topLevelMethod.ContainingType, node, compilationState, diagnostics) { }
internal static BoundStatement LowerStatement( bool generateDebugInfo, MethodSymbol method, BoundStatement body, SynthesizedSubmissionFields previousSubmissionFields, TypeCompilationState compilationState, DiagnosticBag diagnostics) { if (body.HasErrors) { return body; } bool sawLambdas; bool sawDynamicOperations; bool sawAwaitInExceptionHandler; var loweredBody = LocalRewriter.Rewrite( method.DeclaringCompilation, generateDebugInfo, method, method.ContainingType, body, compilationState, diagnostics, previousSubmissionFields, out sawLambdas, out sawDynamicOperations, out sawAwaitInExceptionHandler); if (sawDynamicOperations && compilationState.ModuleBuilder.IsENCDelta) { // Dynamic operations are not supported in ENC. var location = method.Locations[0]; diagnostics.Add(new CSDiagnosticInfo(ErrorCode.ERR_EnCNoDynamicOperation), location); } if (loweredBody.HasErrors) { return loweredBody; } if (sawAwaitInExceptionHandler) { // If we have awaits in handlers, we need to // replace handlers with synthetic ones which can be consumed by async rewriter. // The reason why this rewrite happens before the lambda rewrite // is that we may need access to exception locals and it would be fairly hard to do // if these locals are captured into closures (possibly nested ones). Debug.Assert(method.IteratorElementType == null); loweredBody = AsyncHandlerRewriter.Rewrite( generateDebugInfo, method, method.ContainingType, loweredBody, compilationState, diagnostics); } if (loweredBody.HasErrors) { return loweredBody; } BoundStatement bodyWithoutLambdas = loweredBody; if (sawLambdas) { LambdaRewriter.Analysis lambdaAnalysis = LambdaRewriter.Analysis.Analyze(loweredBody, method, out sawLambdas); if (sawLambdas) { bodyWithoutLambdas = LambdaRewriter.Rewrite(loweredBody, method.ContainingType, method.ThisParameter, method, compilationState, diagnostics, lambdaAnalysis, generateDebugInfo); } } if (bodyWithoutLambdas.HasErrors) { return bodyWithoutLambdas; } BoundStatement bodyWithoutIterators = IteratorRewriter.Rewrite(bodyWithoutLambdas, method, compilationState, diagnostics, generateDebugInfo); if (bodyWithoutIterators.HasErrors) { return bodyWithoutIterators; } BoundStatement bodyWithoutAsync = AsyncRewriter2.Rewrite(bodyWithoutIterators, method, compilationState, diagnostics, generateDebugInfo); return bodyWithoutAsync; }
internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, int methodOrdinal, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics, out IteratorStateMachine stateMachineType ) { TypeWithAnnotations elementType = method.IteratorElementTypeWithAnnotations; if (elementType.IsDefault || method.IsAsync) { stateMachineType = null; return(body); } // Figure out what kind of iterator we are generating. bool isEnumerable; switch (method.ReturnType.OriginalDefinition.SpecialType) { case SpecialType.System_Collections_IEnumerable: case SpecialType.System_Collections_Generic_IEnumerable_T: isEnumerable = true; break; case SpecialType.System_Collections_IEnumerator: case SpecialType.System_Collections_Generic_IEnumerator_T: isEnumerable = false; break; default: throw ExceptionUtilities.UnexpectedValue( method.ReturnType.OriginalDefinition.SpecialType ); } stateMachineType = new IteratorStateMachine( slotAllocatorOpt, compilationState, method, methodOrdinal, isEnumerable, elementType ); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType( method, stateMachineType ); var rewriter = new IteratorRewriter( body, method, isEnumerable, stateMachineType, slotAllocatorOpt, compilationState, diagnostics ); if (!rewriter.VerifyPresenceOfRequiredAPIs()) { return(body); } return(rewriter.Rewrite()); }
internal static BoundStatement LowerStatement( bool generateDebugInfo, NamedTypeSymbol thisType, ParameterSymbol thisParameter, MethodSymbol method, BoundStatement body, SynthesizedSubmissionFields previousSubmissionFields, TypeCompilationState compilationState, DiagnosticBag diagnostics) { if (body.HasErrors) { return(body); } bool sawLambdas; bool sawDynamicOperations; bool sawAwaitInExceptionHandler; var loweredBody = LocalRewriter.Rewrite( generateDebugInfo, method, method.ContainingType, body, compilationState, diagnostics, previousSubmissionFields, out sawLambdas, out sawDynamicOperations, out sawAwaitInExceptionHandler); if (sawDynamicOperations && compilationState.ModuleBuilder.IsENCDelta) { // Dynamic operations are not supported in ENC. var location = method.Locations[0]; diagnostics.Add(new CSDiagnosticInfo(ErrorCode.ERR_EnCNoDynamicOperation), location); } if (loweredBody.HasErrors) { return(loweredBody); } if (sawAwaitInExceptionHandler) { // If we have awaits in handlers, we need to // replace handlers with synthetic ones which can be consumed by async rewriter. // The reason why this rewrite happens before the lambda rewrite // is that we may need access to exception locals and it would be fairly hard to do // if these locals are captured into closures (possibly nested ones). Debug.Assert(method.IteratorElementType == null); loweredBody = AsyncHandlerRewriter.Rewrite( generateDebugInfo, method, method.ContainingType, loweredBody, compilationState, diagnostics); } if (loweredBody.HasErrors) { return(loweredBody); } BoundStatement bodyWithoutLambdas = loweredBody; if (sawLambdas) { LambdaRewriter.Analysis lambdaAnalysis = LambdaRewriter.Analysis.Analyze(loweredBody, method, out sawLambdas); if (sawLambdas) { bodyWithoutLambdas = LambdaRewriter.Rewrite(loweredBody, thisType, thisParameter, method, compilationState, diagnostics, lambdaAnalysis, generateDebugInfo); } } if (bodyWithoutLambdas.HasErrors) { return(bodyWithoutLambdas); } BoundStatement bodyWithoutIterators = IteratorRewriter.Rewrite(bodyWithoutLambdas, method, compilationState, diagnostics, generateDebugInfo); if (bodyWithoutIterators.HasErrors) { return(bodyWithoutIterators); } BoundStatement bodyWithoutAsync = AsyncRewriter2.Rewrite(bodyWithoutIterators, method, compilationState, diagnostics, generateDebugInfo); return(bodyWithoutAsync); }
internal static BoundStatement Rewrite( BoundStatement bodyWithAwaitLifted, MethodSymbol method, int methodOrdinal, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics, out AsyncStateMachine stateMachineType ) { if (!method.IsAsync) { stateMachineType = null; return(bodyWithAwaitLifted); } CSharpCompilation compilation = method.DeclaringCompilation; bool isAsyncEnumerableOrEnumerator = method.IsAsyncReturningIAsyncEnumerable(compilation) || method.IsAsyncReturningIAsyncEnumerator(compilation); if (isAsyncEnumerableOrEnumerator && !method.IsIterator) { bool containsAwait = AwaitDetector.ContainsAwait(bodyWithAwaitLifted); diagnostics.Add( containsAwait ? ErrorCode.ERR_PossibleAsyncIteratorWithoutYield : ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait, method.Locations[0], method.ReturnTypeWithAnnotations ); stateMachineType = null; return(bodyWithAwaitLifted); } // The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class. // For async-iterators, we also need to generate a class. var typeKind = (compilationState.Compilation.Options.EnableEditAndContinue || method.IsIterator) ? TypeKind.Class : TypeKind.Struct; stateMachineType = new AsyncStateMachine( slotAllocatorOpt, compilationState, method, methodOrdinal, typeKind ); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType( method, stateMachineType ); AsyncRewriter rewriter = isAsyncEnumerableOrEnumerator ? new AsyncIteratorRewriter( bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics ) : new AsyncRewriter( bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics ); if (!rewriter.VerifyPresenceOfRequiredAPIs()) { return(bodyWithAwaitLifted); } try { return(rewriter.Rewrite()); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); return(new BoundBadStatement( bodyWithAwaitLifted.Syntax, ImmutableArray.Create <BoundNode>(bodyWithAwaitLifted), hasErrors: true )); } }
internal LambdaFrame(MethodSymbol topLevelMethod, TypeCompilationState compilationState) : base(topLevelMethod, GeneratedNames.MakeAnonymousDisplayClassName(compilationState.GenerateTempNumber()), TypeKind.Class) { this.constructor = new SynthesizedInstanceConstructor(this); }
public StateMachineTypeSymbol(VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, MethodSymbol kickoffMethod, int kickoffMethodOrdinal) : base(MakeName(slotAllocatorOpt, compilationState, kickoffMethod, kickoffMethodOrdinal), kickoffMethod) { Debug.Assert(kickoffMethod != null); this.KickoffMethod = kickoffMethod; }
private static string MakeName(VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, MethodSymbol kickoffMethod, int kickoffMethodOrdinal) { return(slotAllocatorOpt?.PreviousStateMachineTypeName ?? GeneratedNames.MakeStateMachineTypeName(kickoffMethod.Name, kickoffMethodOrdinal, compilationState.ModuleBuilderOpt.CurrentGenerationOrdinal)); }
public static BoundBlock Rewrite( MethodSymbol method, BoundBlock block, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics, bool hasTrailingExpression, bool originalBodyNested) { #if DEBUG // We should only see a trailingExpression if we're in a Script initializer. Debug.Assert(!hasTrailingExpression || method.IsScriptInitializer); var initialDiagnosticCount = diagnostics.ToReadOnly().Diagnostics.Length; #endif var compilation = method.DeclaringCompilation; if (method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(compilation)) { ImmutableArray <FieldSymbol> implicitlyInitializedFields = default; bool needsImplicitReturn = true; // we don't analyze synthesized void methods. if ((method.IsImplicitlyDeclared && !method.IsScriptInitializer) || Analyze(compilation, method, block, diagnostics.DiagnosticBag, out needsImplicitReturn, out implicitlyInitializedFields)) { if (!implicitlyInitializedFields.IsDefault) { Debug.Assert(!implicitlyInitializedFields.IsEmpty); block = PrependImplicitInitializations(block, method, implicitlyInitializedFields, compilationState, diagnostics); } if (needsImplicitReturn) { block = AppendImplicitReturn(block, method, originalBodyNested); } } } else if (Analyze(compilation, method, block, diagnostics.DiagnosticBag, out var needsImplicitReturn, out var unusedImplicitlyInitializedFields)) { Debug.Assert(unusedImplicitlyInitializedFields.IsDefault); Debug.Assert(needsImplicitReturn); // If the method is a lambda expression being converted to a non-void delegate type // and the end point is reachable then suppress the error here; a special error // will be reported by the lambda binder. Debug.Assert(method.MethodKind != MethodKind.AnonymousFunction); // Add implicit "return default(T)" if this is a submission that does not have a trailing expression. var submissionResultType = (method as SynthesizedInteractiveInitializerMethod)?.ResultType; if (!hasTrailingExpression && ((object)submissionResultType != null)) { Debug.Assert(!submissionResultType.IsVoidType()); var trailingExpression = new BoundDefaultExpression(method.GetNonNullSyntaxNode(), submissionResultType); var newStatements = block.Statements.Add(new BoundReturnStatement(trailingExpression.Syntax, RefKind.None, trailingExpression, @checked: false)); block = new BoundBlock(block.Syntax, ImmutableArray <LocalSymbol> .Empty, newStatements) { WasCompilerGenerated = true }; #if DEBUG // It should not be necessary to repeat analysis after adding this node, because adding a trailing // return in cases where one was missing should never produce different Diagnostics. IEnumerable <Diagnostic> getErrorsOnly(IEnumerable <Diagnostic> diags) => diags.Where(d => d.Severity == DiagnosticSeverity.Error); var flowAnalysisDiagnostics = DiagnosticBag.GetInstance(); Debug.Assert(!Analyze(compilation, method, block, flowAnalysisDiagnostics, needsImplicitReturn: out _, out unusedImplicitlyInitializedFields)); Debug.Assert(unusedImplicitlyInitializedFields.IsDefault); // Ignore warnings since flow analysis reports nullability mismatches. Debug.Assert(getErrorsOnly(flowAnalysisDiagnostics.ToReadOnly()).SequenceEqual(getErrorsOnly(diagnostics.ToReadOnly().Diagnostics.Skip(initialDiagnosticCount)))); flowAnalysisDiagnostics.Free(); #endif } // If there's more than one location, then the method is partial and we // have already reported a non-void partial method error. else if (method.Locations.Length == 1) { diagnostics.Add(ErrorCode.ERR_ReturnExpected, method.Locations[0], method); } } return(block); }
private static BoundBlock PrependImplicitInitializations(BoundBlock body, MethodSymbol method, ImmutableArray <FieldSymbol> implicitlyInitializedFields, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { Debug.Assert(method.MethodKind == MethodKind.Constructor); Debug.Assert(method.ContainingType.IsStructType()); var syntax = body.Syntax; var F = new SyntheticBoundNodeFactory(method, syntax, compilationState, diagnostics); var builder = ArrayBuilder <BoundStatement> .GetInstance(implicitlyInitializedFields.Length + 1); foreach (var field in implicitlyInitializedFields) { builder.Add(new BoundExpressionStatement( syntax, F.AssignmentExpression( F.Field(F.This(), field), F.Default(field.Type)))); } builder.Add(body); return(BoundBlock.SynthesizedNoLocals(syntax, builder.ToImmutableAndFree())); }
private static BoundBlock PrependImplicitInitializations(BoundBlock body, MethodSymbol method, ImmutableArray <FieldSymbol> implicitlyInitializedFields, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { Debug.Assert(method.MethodKind == MethodKind.Constructor); Debug.Assert(method.ContainingType.IsStructType()); var F = new SyntheticBoundNodeFactory(method, body.Syntax, compilationState, diagnostics); var builder = ArrayBuilder <BoundStatement> .GetInstance(implicitlyInitializedFields.Length); foreach (var field in implicitlyInitializedFields) { builder.Add( F.ExpressionStatement( F.AssignmentExpression( F.Field(F.This(), field), F.Default(field.Type)))); } var initializations = F.HiddenSequencePoint(F.Block(builder.ToImmutableAndFree())); return(body.Update(body.Locals, body.LocalFunctions, body.Statements.Insert(index: 0, initializations))); }
internal static MethodBody GenerateMethodBody(TypeCompilationState compilationState, MethodSymbol method, BoundStatement block, DiagnosticBag diagnostics, bool optimize, DebugDocumentProvider debugDocumentProvider, ImmutableArray <NamespaceScope> namespaceScopes) { // Note: don't call diagnostics.HasAnyErrors() in release; could be expensive if compilation has many warnings. Debug.Assert(!diagnostics.HasAnyErrors(), "Running code generator when errors exist might be dangerous; code generator not well hardened"); bool emitSequencePoints = !namespaceScopes.IsDefault && !method.IsAsync; var module = compilationState.ModuleBuilder; var compilation = module.Compilation; var localSlotManager = module.CreateLocalSlotManager(method); ILBuilder builder = new ILBuilder(module, localSlotManager, optimize); DiagnosticBag diagnosticsForThisMethod = DiagnosticBag.GetInstance(); try { AsyncMethodBodyDebugInfo asyncDebugInfo = null; if ((object)method.AsyncKickoffMethod == null) // is this the MoveNext of an async method? { CodeGen.CodeGenerator.Run( method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints); } else { int asyncCatchHandlerOffset; ImmutableArray <int> asyncYieldPoints; ImmutableArray <int> asyncResumePoints; CodeGen.CodeGenerator.Run( method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints, out asyncCatchHandlerOffset, out asyncYieldPoints, out asyncResumePoints); asyncDebugInfo = new AsyncMethodBodyDebugInfo(method.AsyncKickoffMethod, asyncCatchHandlerOffset, asyncYieldPoints, asyncResumePoints); } var localVariables = builder.LocalSlotManager.LocalsInOrder(); if (localVariables.Length > 0xFFFE) { diagnosticsForThisMethod.Add(ErrorCode.ERR_TooManyLocals, method.Locations.First()); } if (diagnosticsForThisMethod.HasAnyErrors()) { // we are done here. Since there were errors we should not emit anything. return(null); } // We will only save the IL builders when running tests. if (module.SaveTestData) { module.SetMethodTestData(method, builder.GetSnapshot()); } // Only compiler-generated MoveNext methods have iterator scopes. See if this is one. bool hasIteratorScopes = method.Locations.IsEmpty && method.Name == "MoveNext" && (method.ExplicitInterfaceImplementations.Contains(compilation.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext) as MethodSymbol) || method.ExplicitInterfaceImplementations.Contains(compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_MoveNext) as MethodSymbol)); var iteratorScopes = hasIteratorScopes ? builder.GetIteratorScopes() : ImmutableArray <LocalScope> .Empty; var iteratorOrAsyncImplementation = compilationState.GetIteratorOrAsyncImplementationClass(method); return(new MethodBody( builder.RealizedIL, builder.MaxStack, method, localVariables, builder.RealizedSequencePoints, debugDocumentProvider, builder.RealizedExceptionHandlers, builder.GetAllScopes(), Microsoft.Cci.CustomDebugInfoKind.CSharpStyle, builder.HasDynamicLocal, namespaceScopes, (object)iteratorOrAsyncImplementation == null ? null : iteratorOrAsyncImplementation.MetadataName, iteratorScopes, asyncMethodDebugInfo: asyncDebugInfo )); } finally { // Basic blocks contain poolable builders for IL and sequence points. Free those back // to their pools. builder.FreeBasicBlocks(); // Remember diagnostics. diagnostics.AddRange(diagnosticsForThisMethod); diagnosticsForThisMethod.Free(); } }
// NOTE: can return null if the method has no body. internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics) { ConsList <Imports> unused; return(BindMethodBody(method, compilationState, diagnostics, false, out unused)); }
public AwaitLoweringRewriterPass2(SyntheticBoundNodeFactory F, TypeCompilationState CompilationState) { this.F = F; this.spillFieldAllocator = new SpillFieldAllocator(F, CompilationState); }
internal static BoundStatement Rewrite(BoundStatement body, MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics) { var tempSubstitution = PooledDictionary <LocalSymbol, LocalSymbol> .GetInstance(); var spiller = new SpillSequenceSpiller(method, body.Syntax, compilationState, tempSubstitution, diagnostics); BoundNode result = spiller.Visit(body); result = LocalSubstituter.Rewrite(tempSubstitution, result); tempSubstitution.Free(); return((BoundStatement)result); }
// NOTE: can return null if the method has no body. internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo, out ConsList <Imports> debugImports) { debugImports = null; BoundStatement constructorInitializer = null; BoundBlock body; var compilation = method.DeclaringCompilation; var sourceMethod = method as SourceMethodSymbol; if ((object)sourceMethod != null) { if (sourceMethod.IsExtern) { if (sourceMethod.BlockSyntax == null) { // Generate warnings only if we are not generating ERR_ExternHasBody error GenerateExternalMethodWarnings(sourceMethod, diagnostics); } return(null); } else if (sourceMethod.IsParameterlessValueTypeConstructor(requireSynthesized: true)) { // No body for default struct constructor. return(null); } var blockSyntax = sourceMethod.BlockSyntax; if (blockSyntax != null) { var factory = compilation.GetBinderFactory(sourceMethod.SyntaxTree); var inMethodBinder = factory.GetBinder(blockSyntax); var binder = new ExecutableCodeBinder(blockSyntax, sourceMethod, inMethodBinder); body = binder.BindBlock(blockSyntax, diagnostics); if (generateDebugInfo) { debugImports = binder.ImportsList; } if (inMethodBinder.IsDirectlyInIterator) { foreach (var parameter in method.Parameters) { if (parameter.RefKind != RefKind.None) { diagnostics.Add(ErrorCode.ERR_BadIteratorArgType, parameter.Locations[0]); } else if (parameter.Type.IsUnsafe()) { diagnostics.Add(ErrorCode.ERR_UnsafeIteratorArgType, parameter.Locations[0]); } } if (sourceMethod.IsUnsafe && compilation.Options.AllowUnsafe) // Don't cascade { diagnostics.Add(ErrorCode.ERR_IllegalInnerUnsafe, sourceMethod.Locations[0]); } if (sourceMethod.IsVararg) { // error CS1636: __arglist is not allowed in the parameter list of iterators diagnostics.Add(ErrorCode.ERR_VarargsIterator, sourceMethod.Locations[0]); } } } else // for [if (blockSyntax != null)] { var property = sourceMethod.AssociatedSymbol as SourcePropertySymbol; if ((object)property != null && property.IsAutoProperty) { return(MethodBodySynthesizer.ConstructAutoPropertyAccessorBody(sourceMethod)); } if (sourceMethod.IsPrimaryCtor) { body = null; } else { return(null); } } } else { // synthesized methods should return their bound bodies body = null; } // delegates have constructors but not constructor initializers if (method.MethodKind == MethodKind.Constructor && !method.ContainingType.IsDelegateType()) { var initializerInvocation = BindConstructorInitializer(method, diagnostics, compilation); if (initializerInvocation != null) { constructorInitializer = new BoundExpressionStatement(initializerInvocation.Syntax, initializerInvocation) { WasCompilerGenerated = true }; Debug.Assert(initializerInvocation.HasAnyErrors || constructorInitializer.IsConstructorInitializer(), "Please keep this bound node in sync with BoundNodeExtensions.IsConstructorInitializer."); } } var statements = ArrayBuilder <BoundStatement> .GetInstance(); if (constructorInitializer != null) { statements.Add(constructorInitializer); } if ((object)sourceMethod != null && sourceMethod.IsPrimaryCtor && (object)((SourceMemberContainerTypeSymbol)sourceMethod.ContainingType).PrimaryCtor == (object)sourceMethod) { Debug.Assert(method.MethodKind == MethodKind.Constructor && !method.ContainingType.IsDelegateType()); Debug.Assert(body == null); if (sourceMethod.ParameterCount > 0) { var factory = new SyntheticBoundNodeFactory(sourceMethod, sourceMethod.SyntaxNode, compilationState, diagnostics); factory.CurrentMethod = sourceMethod; foreach (var parameter in sourceMethod.Parameters) { FieldSymbol field = parameter.PrimaryConstructorParameterBackingField; if ((object)field != null) { statements.Add(factory.Assignment(factory.Field(factory.This(), field), factory.Parameter(parameter))); } } } } if (body != null) { statements.Add(body); } CSharpSyntaxNode syntax = body != null ? body.Syntax : method.GetNonNullSyntaxNode(); BoundBlock block; if (statements.Count == 1 && statements[0].Kind == ((body == null) ? BoundKind.Block : body.Kind)) { // most common case - we just have a single block for the body. block = (BoundBlock)statements[0]; statements.Free(); } else { block = new BoundBlock(syntax, default(ImmutableArray <LocalSymbol>), statements.ToImmutableAndFree()) { WasCompilerGenerated = true }; } return(method.MethodKind == MethodKind.Destructor ? MethodBodySynthesizer.ConstructDestructorBody(syntax, method, block) : block); }
private SpillSequenceSpiller(MethodSymbol method, SyntaxNode syntaxNode, TypeCompilationState compilationState, PooledDictionary <LocalSymbol, LocalSymbol> tempSubstitution, DiagnosticBag diagnostics) { _F = new SyntheticBoundNodeFactory(method, syntaxNode, compilationState, diagnostics); _F.CurrentFunction = method; _tempSubstitution = tempSubstitution; }
/// <param name="topLevelMethodOpt">The top-level method that will contain the code</param> /// <param name="currentClassOpt">The enclosing class</param> /// <param name="node">The syntax node to which generated code should be attributed</param> /// <param name="compilationState">The state of compilation of the enclosing type</param> /// <param name="diagnostics">A bag where any diagnostics should be output</param> public SyntheticBoundNodeFactory(MethodSymbol topLevelMethodOpt, NamedTypeSymbol currentClassOpt, CSharpSyntaxNode node, TypeCompilationState compilationState, DiagnosticBag diagnostics) { Debug.Assert(node != null); Debug.Assert(compilationState != null); Debug.Assert(diagnostics != null); this.CompilationState = compilationState; this.TopLevelMethod = topLevelMethodOpt; this.CurrentClass = currentClassOpt; this.Syntax = node; this.Diagnostics = diagnostics; }
public IteratorStateMachine(MethodSymbol iteratorMethod, bool isEnumerable, TypeSymbol elementType, TypeCompilationState compilationState) : base(GeneratedNames.MakeIteratorOrAsyncDisplayClassName(iteratorMethod.Name, compilationState.GenerateTempNumber()), iteratorMethod) { this.iteratorMethod = iteratorMethod; this.ElementType = TypeMap.SubstituteType(elementType); var interfaces = ArrayBuilder <NamedTypeSymbol> .GetInstance(); if (isEnumerable) { interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T).Construct(ElementType)); interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_Collections_IEnumerable)); } interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerator_T).Construct(ElementType)); interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_IDisposable)); interfaces.Add(ContainingAssembly.GetSpecialType(SpecialType.System_Collections_IEnumerator)); this.interfaces = interfaces.ToImmutableAndFree(); this.constructor = new IteratorConstructor(this); }
/// <summary> /// Lower a block of code by performing local rewritings. /// </summary> public static BoundStatement Rewrite( CSharpCompilation compilation, MethodSymbol method, int methodOrdinal, NamedTypeSymbol containingType, BoundStatement statement, TypeCompilationState compilationState, SynthesizedSubmissionFields previousSubmissionFields, bool allowOmissionOfConditionalCalls, bool instrumentForDynamicAnalysis, ref ImmutableArray <SourceSpan> dynamicAnalysisSpans, DebugDocumentProvider debugDocumentProvider, DiagnosticBag diagnostics, out bool sawLambdas, out bool sawLocalFunctions, out bool sawAwaitInExceptionHandler) { Debug.Assert(statement != null); Debug.Assert(compilationState != null); try { var factory = new SyntheticBoundNodeFactory(method, statement.Syntax, compilationState, diagnostics); DynamicAnalysisInjector dynamicInstrumenter = instrumentForDynamicAnalysis ? DynamicAnalysisInjector.TryCreate(method, statement, factory, diagnostics, debugDocumentProvider, Instrumenter.NoOp) : null; // We don’t want IL to differ based upon whether we write the PDB to a file/stream or not. // Presence of sequence points in the tree affects final IL, therefore, we always generate them. var localRewriter = new LocalRewriter(compilation, method, methodOrdinal, statement, containingType, factory, previousSubmissionFields, allowOmissionOfConditionalCalls, diagnostics, dynamicInstrumenter != null ? new DebugInfoInjector(dynamicInstrumenter) : DebugInfoInjector.Singleton); statement.CheckLocalsDefined(); var loweredStatement = (BoundStatement)localRewriter.Visit(statement); loweredStatement.CheckLocalsDefined(); sawLambdas = localRewriter._sawLambdas; sawLocalFunctions = localRewriter._sawLocalFunctions; sawAwaitInExceptionHandler = localRewriter._sawAwaitInExceptionHandler; if (localRewriter._needsSpilling && !loweredStatement.HasErrors) { // Move spill sequences to a top-level statement. This handles "lifting" await and the switch expression. var spilledStatement = SpillSequenceSpiller.Rewrite(loweredStatement, method, compilationState, diagnostics); spilledStatement.CheckLocalsDefined(); loweredStatement = spilledStatement; } if (dynamicInstrumenter != null) { dynamicAnalysisSpans = dynamicInstrumenter.DynamicAnalysisSpans; } #if DEBUG LocalRewritingValidator.Validate(loweredStatement); #endif return(loweredStatement); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); sawLambdas = sawLocalFunctions = sawAwaitInExceptionHandler = false; return(new BoundBadStatement(statement.Syntax, ImmutableArray.Create <BoundNode>(statement), hasErrors: true)); } }
internal static MethodBody GenerateMethodBody(TypeCompilationState compilationState, MethodSymbol method, BoundStatement block, DiagnosticBag diagnostics, bool optimize, DebugDocumentProvider debugDocumentProvider, ImmutableArray<NamespaceScope> namespaceScopes) { // Note: don't call diagnostics.HasAnyErrors() in release; could be expensive if compilation has many warnings. Debug.Assert(!diagnostics.HasAnyErrors(), "Running code generator when errors exist might be dangerous; code generator not well hardened"); bool emitSequencePoints = !namespaceScopes.IsDefault && !method.IsAsync; var module = compilationState.ModuleBuilder; var compilation = module.Compilation; var localSlotManager = module.CreateLocalSlotManager(method); ILBuilder builder = new ILBuilder(module, localSlotManager, optimize); DiagnosticBag diagnosticsForThisMethod = DiagnosticBag.GetInstance(); try { AsyncMethodBodyDebugInfo asyncDebugInfo = null; if ((object)method.AsyncKickoffMethod == null) // is this the MoveNext of an async method? { CodeGen.CodeGenerator.Run( method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints); } else { int asyncCatchHandlerOffset; ImmutableArray<int> asyncYieldPoints; ImmutableArray<int> asyncResumePoints; CodeGen.CodeGenerator.Run( method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints, out asyncCatchHandlerOffset, out asyncYieldPoints, out asyncResumePoints); asyncDebugInfo = new AsyncMethodBodyDebugInfo(method.AsyncKickoffMethod, asyncCatchHandlerOffset, asyncYieldPoints, asyncResumePoints); } var localVariables = builder.LocalSlotManager.LocalsInOrder(); if (localVariables.Length > 0xFFFE) { diagnosticsForThisMethod.Add(ErrorCode.ERR_TooManyLocals, method.Locations.First()); } if (diagnosticsForThisMethod.HasAnyErrors()) { // we are done here. Since there were errors we should not emit anything. return null; } // We will only save the IL builders when running tests. if (module.SaveTestData) { module.SetMethodTestData(method, builder.GetSnapshot()); } // Only compiler-generated MoveNext methods have iterator scopes. See if this is one. bool hasIteratorScopes = method.Locations.IsEmpty && method.Name == "MoveNext" && (method.ExplicitInterfaceImplementations.Contains(compilation.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext) as MethodSymbol) || method.ExplicitInterfaceImplementations.Contains(compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_MoveNext) as MethodSymbol)); var iteratorScopes = hasIteratorScopes ? builder.GetIteratorScopes() : ImmutableArray<LocalScope>.Empty; var iteratorOrAsyncImplementation = compilationState.GetIteratorOrAsyncImplementationClass(method); return new MethodBody( builder.RealizedIL, builder.MaxStack, method, localVariables, builder.RealizedSequencePoints, debugDocumentProvider, builder.RealizedExceptionHandlers, builder.GetAllScopes(), Microsoft.Cci.CustomDebugInfoKind.CSharpStyle, builder.HasDynamicLocal, namespaceScopes, (object)iteratorOrAsyncImplementation == null ? null : iteratorOrAsyncImplementation.MetadataName, iteratorScopes, asyncMethodDebugInfo: asyncDebugInfo ); } finally { // Basic blocks contain poolable builders for IL and sequence points. Free those back // to their pools. builder.FreeBasicBlocks(); // Remember diagnostics. diagnostics.AddRange(diagnosticsForThisMethod); diagnosticsForThisMethod.Free(); } }
public AwaitLiftingRewriter(MethodSymbol method, CSharpSyntaxNode syntaxNode, TypeCompilationState compilationState, DiagnosticBag diagnostics) { this.F = new SyntheticBoundNodeFactory(method, syntaxNode, compilationState, diagnostics); }
// NOTE: can return null if the method has no body. internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics) { ConsList<Imports> unused; return BindMethodBody(method, compilationState, diagnostics, false, out unused); }
private ExpressionLambdaRewriter(TypeCompilationState compilationState, TypeMap typeMap, CSharpSyntaxNode node, DiagnosticBag diagnostics) { _bound = new SyntheticBoundNodeFactory(null, compilationState.Type, node, compilationState, diagnostics); _ignoreAccessibility = compilationState.ModuleBuilderOpt.IgnoreAccessibility; _int32Type = _bound.SpecialType(SpecialType.System_Int32); _objectType = _bound.SpecialType(SpecialType.System_Object); _nullableType = _bound.SpecialType(SpecialType.System_Nullable_T); _IEnumerableType = _bound.SpecialType(SpecialType.System_Collections_Generic_IEnumerable_T); _typeMap = typeMap; }
internal static MethodSymbol DefineScriptEntryPoint(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuilt, TypeSymbol returnType, bool hasDeclarationErrors, DiagnosticBag diagnostics) { var scriptEntryPoint = new SynthesizedEntryPointSymbol(compilation.ScriptClass, returnType, diagnostics); if (moduleBeingBuilt != null && !hasDeclarationErrors && !diagnostics.HasAnyErrors()) { var compilationState = new TypeCompilationState(compilation.ScriptClass, moduleBeingBuilt); var body = scriptEntryPoint.CreateBody(); var emittedBody = GenerateMethodBody( compilationState, scriptEntryPoint, body, diagnostics, compilation.Options.Optimize, debugDocumentProvider: null, namespaceScopes: default(ImmutableArray<NamespaceScope>)); moduleBeingBuilt.SetMethodBody(scriptEntryPoint, emittedBody); moduleBeingBuilt.AddCompilerGeneratedDefinition(compilation.ScriptClass, scriptEntryPoint); } return scriptEntryPoint; }
internal SynthesizedClosureMethod( NamedTypeSymbol containingType, ImmutableArray <SynthesizedClosureEnvironment> structEnvironments, ClosureKind closureKind, MethodSymbol topLevelMethod, DebugId topLevelMethodId, MethodSymbol originalMethod, SyntaxReference blockSyntax, DebugId lambdaId, TypeCompilationState compilationState) : base(containingType, originalMethod, blockSyntax, originalMethod.DeclaringSyntaxReferences[0].GetLocation(), originalMethod is LocalFunctionSymbol ? MakeName(topLevelMethod.Name, originalMethod.Name, topLevelMethodId, closureKind, lambdaId) : MakeName(topLevelMethod.Name, topLevelMethodId, closureKind, lambdaId), MakeDeclarationModifiers(closureKind, originalMethod)) { Debug.Assert(containingType.DeclaringCompilation is not null); TopLevelMethod = topLevelMethod; ClosureKind = closureKind; LambdaId = lambdaId; TypeMap typeMap; ImmutableArray <TypeParameterSymbol> typeParameters; var lambdaFrame = ContainingType as SynthesizedClosureEnvironment; switch (closureKind) { case ClosureKind.Singleton: // all type parameters on method (except the top level method's) case ClosureKind.General: // only lambda's type parameters on method (rest on class) RoslynDebug.Assert(!(lambdaFrame is null)); typeMap = lambdaFrame.TypeMap.WithConcatAlphaRename( originalMethod, this, out typeParameters, out _, lambdaFrame.OriginalContainingMethodOpt); break; case ClosureKind.ThisOnly: // all type parameters on method case ClosureKind.Static: RoslynDebug.Assert(lambdaFrame is null); typeMap = TypeMap.Empty.WithConcatAlphaRename( originalMethod, this, out typeParameters, out _, stopAt: null); break; default: throw ExceptionUtilities.UnexpectedValue(closureKind); } if (!structEnvironments.IsDefaultOrEmpty && typeParameters.Length != 0) { var constructedStructClosures = ArrayBuilder <NamedTypeSymbol> .GetInstance(); foreach (var env in structEnvironments) { NamedTypeSymbol constructed; if (env.Arity == 0) { constructed = env; } else { var originals = env.ConstructedFromTypeParameters; var newArgs = typeMap.SubstituteTypeParameters(originals); constructed = env.Construct(newArgs); } constructedStructClosures.Add(constructed); } _structEnvironments = constructedStructClosures.ToImmutableAndFree(); } else { _structEnvironments = ImmutableArray <NamedTypeSymbol> .CastUp(structEnvironments); } AssignTypeMapAndTypeParameters(typeMap, typeParameters); EnsureAttributesExist(compilationState); // static local functions should be emitted as static. Debug.Assert(!(originalMethod is LocalFunctionSymbol) || !originalMethod.IsStatic || IsStatic); }
private AwaitExpressionSpiller(MethodSymbol method, SyntaxNode syntaxNode, TypeCompilationState compilationState, PooledDictionary <LocalSymbol, LocalSymbol> tempSubstitution, DiagnosticBag diagnostics) { _F = new SyntheticBoundNodeFactory(method, syntaxNode, compilationState, diagnostics); _tempSubstitution = tempSubstitution; }
internal static BoundStatement Rewrite(BoundStatement body, MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics) { return new AwaitLiftingRewriter(method, body.Syntax, compilationState, diagnostics).Rewrite(body); }
internal static BoundStatement Rewrite(BoundStatement body, MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics) { var tempSubstitution = PooledDictionary <LocalSymbol, LocalSymbol> .GetInstance(); var spiller = new AwaitExpressionSpiller(method, body.Syntax, compilationState, tempSubstitution, diagnostics); var result = (BoundStatement)spiller.Visit(body); tempSubstitution.Free(); return(result); }
internal static BoundNode RewriteLambda(BoundLambda node, TypeCompilationState compilationState, TypeMap typeMap, DiagnosticBag diagnostics) { try { var r = new ExpressionLambdaRewriter(compilationState, typeMap, node.Syntax, diagnostics); var result = r.VisitLambdaInternal(node); if (node.Type != result.Type) { diagnostics.Add(ErrorCode.ERR_MissingPredefinedMember, node.Syntax.Location, r.ExpressionType, "Lambda"); } return result; } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); return node; } }
internal SynthesizedLambdaMethod(NamedTypeSymbol containingType, MethodSymbol topLevelMethod, BoundLambda node, bool isStatic, TypeCompilationState compilationState) : base(containingType, node.Symbol, null, node.SyntaxTree.GetReference(node.Body.Syntax), node.Syntax.GetLocation(), GeneratedNames.MakeLambdaMethodName(topLevelMethod.Name, compilationState.GenerateTempNumber()), (containingType is LambdaFrame ? DeclarationModifiers.Internal : DeclarationModifiers.Private) | (isStatic ? DeclarationModifiers.Static : 0) | (node.Symbol.IsAsync ? DeclarationModifiers.Async : 0)) { TypeMap typeMap; ImmutableArray <TypeParameterSymbol> typeParameters; LambdaFrame lambdaFrame; if (!topLevelMethod.IsGenericMethod) { typeMap = TypeMap.Empty; typeParameters = ImmutableArray <TypeParameterSymbol> .Empty; } else if ((object)(lambdaFrame = this.ContainingType as LambdaFrame) != null) { typeMap = lambdaFrame.TypeMap; typeParameters = ImmutableArray <TypeParameterSymbol> .Empty; } else { typeMap = TypeMap.Empty.WithAlphaRename(topLevelMethod, this, out typeParameters); } AssignTypeMapAndTypeParameters(typeMap, typeParameters); }
internal LambdaFrameLocalSymbol(MethodSymbol containingMethod, TypeSymbol type, TypeCompilationState compilationState) : base(containingMethod, type, GeneratedNames.MakeLambdaDisplayClassLocalName(compilationState.GenerateTempNumber()), declarationKind: LocalDeclarationKind.CompilerGeneratedLambdaDisplayClassLocal) { }
internal LambdaFrame(MethodSymbol topLevelMethod, TypeCompilationState compilationState) : base(GeneratedNames.MakeLambdaDisplayClassName(compilationState.GenerateTempNumber()), topLevelMethod) { this.topLevelMethod = topLevelMethod; this.constructor = new LambdaFrameConstructor(this); }