Esempio n. 1
0
        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)));
            }
        }
Esempio n. 2
0
        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));
            }
            }
        }
Esempio n. 4
0
        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)));
        }
Esempio n. 5
0
        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()));
        }
Esempio n. 6
0
        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));
            }
        }
Esempio n. 7
0
        /// <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);