public override BoundNode VisitConditionalOperator(BoundConditionalOperator node) { BoundSpillSequenceBuilder conditionBuilder = null; var condition = VisitExpression(ref conditionBuilder, node.Condition); BoundSpillSequenceBuilder consequenceBuilder = null; var consequence = VisitExpression(ref consequenceBuilder, node.Consequence); BoundSpillSequenceBuilder alternativeBuilder = null; var alternative = VisitExpression(ref alternativeBuilder, node.Alternative); if (consequenceBuilder == null && alternativeBuilder == null) { return(UpdateExpression(conditionBuilder, node.Update(condition, consequence, alternative, node.ConstantValueOpt, node.Type))); } if (conditionBuilder == null) { conditionBuilder = new BoundSpillSequenceBuilder(); } if (consequenceBuilder == null) { consequenceBuilder = new BoundSpillSequenceBuilder(); } if (alternativeBuilder == null) { alternativeBuilder = new BoundSpillSequenceBuilder(); } if (node.Type.SpecialType == SpecialType.System_Void) { conditionBuilder.AddStatement( _F.If(condition, UpdateStatement(consequenceBuilder, _F.ExpressionStatement(consequence), substituteTemps: false), UpdateStatement(alternativeBuilder, _F.ExpressionStatement(alternative), substituteTemps: false))); return(conditionBuilder.Update(_F.Default(node.Type))); } else { Debug.Assert(_F.Syntax.IsKind(SyntaxKind.AwaitExpression)); var tmp = _F.SynthesizedLocal(node.Type, kind: SynthesizedLocalKind.AwaitSpill, syntax: _F.Syntax); conditionBuilder.AddLocal(tmp, _F.Diagnostics); conditionBuilder.AddStatement( _F.If(condition, UpdateStatement(consequenceBuilder, _F.Assignment(_F.Local(tmp), consequence), substituteTemps: false), UpdateStatement(alternativeBuilder, _F.Assignment(_F.Local(tmp), alternative), substituteTemps: false))); return(conditionBuilder.Update(_F.Local(tmp))); } }
public override BoundNode VisitConditionalOperator(BoundConditionalOperator node) { BoundSpillSequenceBuilder conditionBuilder = null; var condition = VisitExpression(ref conditionBuilder, node.Condition); BoundSpillSequenceBuilder consequenceBuilder = null; var consequence = VisitExpression(ref consequenceBuilder, node.Consequence); BoundSpillSequenceBuilder alternativeBuilder = null; var alternative = VisitExpression(ref alternativeBuilder, node.Alternative); if (consequenceBuilder == null && alternativeBuilder == null) { return(UpdateExpression(conditionBuilder, node.Update(node.IsRef, condition, consequence, alternative, node.ConstantValueOpt, node.Type))); } if (conditionBuilder == null) { conditionBuilder = new BoundSpillSequenceBuilder(); } if (consequenceBuilder == null) { consequenceBuilder = new BoundSpillSequenceBuilder(); } if (alternativeBuilder == null) { alternativeBuilder = new BoundSpillSequenceBuilder(); } if (node.Type.IsVoidType()) { conditionBuilder.AddStatement( _F.If(condition, UpdateStatement(consequenceBuilder, _F.ExpressionStatement(consequence)), UpdateStatement(alternativeBuilder, _F.ExpressionStatement(alternative)))); return(conditionBuilder.Update(_F.Default(node.Type))); } else { var tmp = _F.SynthesizedLocal(node.Type, kind: SynthesizedLocalKind.Spill, syntax: _F.Syntax); conditionBuilder.AddLocal(tmp); conditionBuilder.AddStatement( _F.If(condition, UpdateStatement(consequenceBuilder, _F.Assignment(_F.Local(tmp), consequence)), UpdateStatement(alternativeBuilder, _F.Assignment(_F.Local(tmp), alternative)))); return(conditionBuilder.Update(_F.Local(tmp))); } }
private BoundExpression VisitBinaryOperator(BinaryOperatorKind opKind, MethodSymbol methodOpt, TypeSymbol type, BoundExpression left, BoundExpression right) { bool isChecked, isLifted, requiresLifted; string opName = GetBinaryOperatorName(opKind, out isChecked, out isLifted, out requiresLifted); // Fix up the null value for a nullable comparison vs null if ((object)left.Type == null && left.IsLiteralNull()) { left = _bound.Default(right.Type); } if ((object)right.Type == null && right.IsLiteralNull()) { right = _bound.Default(left.Type); } // Enums are handled as per their promoted underlying type switch (opKind.OperandTypes()) { case BinaryOperatorKind.EnumAndUnderlying: case BinaryOperatorKind.UnderlyingAndEnum: case BinaryOperatorKind.Enum: { var enumOperand = (opKind.OperandTypes() == BinaryOperatorKind.UnderlyingAndEnum) ? right : left; var promotedType = PromotedType(enumOperand.Type.StrippedType().GetEnumUnderlyingType()); if (opKind.IsLifted()) { promotedType = _nullableType.Construct(promotedType); } var loweredLeft = VisitAndPromoteEnumOperand(left, promotedType, isChecked); var loweredRight = VisitAndPromoteEnumOperand(right, promotedType, isChecked); var result = MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight); return(Demote(result, type, isChecked)); } default: { var loweredLeft = Visit(left); var loweredRight = Visit(right); return(MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight)); } } }
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))); }
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 BoundExpression VisitBinaryOperator(BoundBinaryOperator node) { var opKind = node.OperatorKind; var op = opKind & BinaryOperatorKind.OpMask; var isChecked = (opKind & BinaryOperatorKind.Checked) != 0; var isLogical = (opKind & BinaryOperatorKind.Logical) != 0; var isLifted = (opKind & BinaryOperatorKind.Lifted) != 0; bool requiresLifted = false; string opname; switch (op) { case BinaryOperatorKind.Addition: opname = isChecked ? "AddChecked" : "Add"; break; case BinaryOperatorKind.Multiplication: opname = isChecked ? "MultiplyChecked" : "Multiply"; break; case BinaryOperatorKind.Subtraction: opname = isChecked ? "SubtractChecked" : "Subtract"; break; case BinaryOperatorKind.Division: opname = "Divide"; break; case BinaryOperatorKind.Remainder: opname = "Modulo"; break; case BinaryOperatorKind.And: opname = isLogical ? "AndAlso" : "And"; break; case BinaryOperatorKind.Xor: opname = "ExclusiveOr"; break; case BinaryOperatorKind.Or: opname = isLogical ? "OrElse" : "Or"; break; case BinaryOperatorKind.LeftShift: opname = "LeftShift"; break; case BinaryOperatorKind.RightShift: opname = "RightShift"; break; case BinaryOperatorKind.Equal: opname = "Equal"; requiresLifted = true; break; case BinaryOperatorKind.NotEqual: opname = "NotEqual"; requiresLifted = true; break; case BinaryOperatorKind.LessThan: opname = "LessThan"; requiresLifted = true; break; case BinaryOperatorKind.LessThanOrEqual: opname = "LessThanOrEqual"; requiresLifted = true; break; case BinaryOperatorKind.GreaterThan: opname = "GreaterThan"; requiresLifted = true; break; case BinaryOperatorKind.GreaterThanOrEqual: opname = "GreaterThanOrEqual"; requiresLifted = true; break; default: throw ExceptionUtilities.UnexpectedValue(op); } BoundExpression left = node.Left; BoundExpression right = node.Right; // Fix up the null value for a nullable comparison vs null if ((object)left.Type == null && left.IsLiteralNull()) { left = Bound.Default(right.Type); } if ((object)right.Type == null && right.IsLiteralNull()) { right = Bound.Default(left.Type); } var loweredLeft = Visit(left); var loweredRight = Visit(right); // Enums are handled as per their promoted underlying type switch (node.OperatorKind.OperandTypes()) { case BinaryOperatorKind.Enum: case BinaryOperatorKind.EnumAndUnderlying: case BinaryOperatorKind.UnderlyingAndEnum: { var enumOperand = (node.OperatorKind.OperandTypes() == BinaryOperatorKind.UnderlyingAndEnum) ? right : left; var promotedType = PromotedType(enumOperand.Type.StrippedType().GetEnumUnderlyingType()); if (isLifted) { promotedType = NullableType.Construct(promotedType); } loweredLeft = Convert(loweredLeft, left.Type, promotedType, isChecked, false); loweredRight = Convert(loweredRight, right.Type, promotedType, isChecked, false); var result = MakeBinary(node, isLifted, requiresLifted, opname, loweredLeft, loweredRight); return(Demote(result, node.Type, isChecked)); } default: return(MakeBinary(node, isLifted, requiresLifted, opname, loweredLeft, loweredRight)); } }
/// <summary> /// Generate the GetEnumerator() method for iterators and GetAsyncEnumerator() for async-iterators. /// </summary> protected SynthesizedImplementationMethod GenerateIteratorGetEnumerator(MethodSymbol getEnumeratorMethod, ref BoundExpression managedThreadId, int initialState) { // Produces: // {StateMachineType} result; // if (this.initialThreadId == {managedThreadId} && this.state == -2) // { // this.state = {initialState}; // extraReset // result = this; // } // else // { // result = new {StateMachineType}({initialState}); // } // // // Initialize each parameter fields // result.parameter = this.parameterProxy; // OR // if (token.Equals(default)) { result.parameter = this.parameterProxy; } else { result.parameter = token; } // for async-enumerable parameters marked with [EnumeratorCancellation] // The implementation doesn't depend on the method body of the iterator method. // Only on its parameters and staticness. var getEnumerator = OpenMethodImplementation( getEnumeratorMethod, hasMethodBodyDependency: false); var bodyBuilder = ArrayBuilder <BoundStatement> .GetInstance(); // {StateMachineType} result; var resultVariable = F.SynthesizedLocal(stateMachineType, null); // result = new {StateMachineType}({initialState}) BoundStatement makeIterator = F.Assignment(F.Local(resultVariable), F.New(stateMachineType.Constructor, F.Literal(initialState))); var thisInitialized = F.GenerateLabel("thisInitialized"); if ((object)initialThreadIdField != null) { managedThreadId = MakeCurrentThreadId(); var thenBuilder = ArrayBuilder <BoundStatement> .GetInstance(4); thenBuilder.Add( // this.state = {initialState}; F.Assignment(F.Field(F.This(), stateField), F.Literal(initialState))); thenBuilder.Add( // result = this; F.Assignment(F.Local(resultVariable), F.This())); var extraReset = GetExtraResetForIteratorGetEnumerator(); if (extraReset != null) { thenBuilder.Add(extraReset); } if (method.IsStatic || method.ThisParameter.Type.IsReferenceType) { // if this is a reference type, no need to copy it since it is not assignable thenBuilder.Add( // goto thisInitialized; F.Goto(thisInitialized)); } makeIterator = F.If( // if (this.state == -2 && this.initialThreadId == Thread.CurrentThread.ManagedThreadId) condition: F.LogicalAnd( F.IntEqual(F.Field(F.This(), stateField), F.Literal(StateMachineStates.FinishedStateMachine)), F.IntEqual(F.Field(F.This(), initialThreadIdField), managedThreadId)), thenClause: F.Block(thenBuilder.ToImmutableAndFree()), elseClauseOpt: makeIterator); } bodyBuilder.Add(makeIterator); // Initialize all the parameter copies var copySrc = initialParameters; var copyDest = nonReusableLocalProxies; if (!method.IsStatic) { // starting with "this" CapturedSymbolReplacement proxy; if (copyDest.TryGetValue(method.ThisParameter, out proxy)) { bodyBuilder.Add( F.Assignment( proxy.Replacement(F.Syntax, stateMachineType => F.Local(resultVariable)), copySrc[method.ThisParameter].Replacement(F.Syntax, stateMachineType => F.This()))); } } bodyBuilder.Add(F.Label(thisInitialized)); foreach (var parameter in method.Parameters) { CapturedSymbolReplacement proxy; if (copyDest.TryGetValue(parameter, out proxy)) { // result.parameter = this.parameterProxy; BoundExpression left = proxy.Replacement(F.Syntax, stateMachineType => F.Local(resultVariable)); BoundStatement copy = F.Assignment( left, copySrc[parameter].Replacement(F.Syntax, stateMachineType => F.This())); if (this.method.IsAsync) { ParameterSymbol tokenParameter = getEnumeratorMethod.Parameters[0]; if (hasEnumeratorCancellationAttribute(parameter)) { // For any async-enumerable parameter marked with [EnumeratorCancellation] attribute, conditionally copy GetAsyncEnumerator's cancellation token parameter instead // if (token.Equals(default)) // result.parameter = this.parameterProxy; // else // result.parameter = token; copy = F.If( // if (token.Equals(default)) F.Call(F.Parameter(tokenParameter), WellKnownMember.System_Threading_CancellationToken__Equals, F.Default(tokenParameter.Type)), // result.parameter = this.parameterProxy; copy, // result.parameter = token; F.Assignment(left, F.Parameter(tokenParameter))); } } bodyBuilder.Add(copy); } } bodyBuilder.Add(F.Return(F.Local(resultVariable))); F.CloseMethod(F.Block(ImmutableArray.Create(resultVariable), bodyBuilder.ToImmutableAndFree())); return(getEnumerator);